    001/*
    002 * Copyright (c) 2009 The openGion Project.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *        http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    013 * either express or implied. See the License for the specific language
    014 * governing permissions and limitations under the License.
    015 */
    016package org.opengion.fukurou.taglet;            // 7.4.4.0 (2021/06/30) openGionV8事前準備(taglet2→taglet)
    017
    018import jdk.javadoc.doclet.DocletEnvironment      ;
    019// import jdk.javadoc.doclet.Doclet  ;
    020// import jdk.javadoc.doclet.Reporter ;
    021// import javax.lang.model.element.Element      ;
    022import javax.lang.model.element.Modifier ;
    023import javax.lang.model.element.TypeElement;
    024// import javax.lang.model.element.ElementKind  ;
    025import javax.lang.model.element.VariableElement;
    026// import javax.lang.model.SourceVersion ;
    027import javax.lang.model.util.ElementFilter ;
    028// import javax.lang.model.util.Elements ;
    029import javax.tools.Diagnostic.Kind ;
    030import com.sun.source.doctree.DocCommentTree  ;
    031import com.sun.source.util.DocTrees  ;
    032// import com.sun.source.doctree.DocTree  ;
    033
    034// import java.util.Locale ;
    035import java.util.Set;
    036import java.util.List;
    037import java.util.HashSet;
    038import java.util.Arrays;
    039import java.util.Map;
    040
    041// import java.io.IOException;
    042// import java.io.File;
    043// import java.io.PrintWriter;
    044
    045// import org.opengion.fukurou.util.FileUtil;
    046// import org.opengion.fukurou.util.StringUtil;
    047
    048/**
    049 * ｿｰｽｺﾒﾝﾄから､ﾊﾟﾗﾒｰﾀ情報を取り出す Doclet ｸﾗｽです｡
    050 * og.paramLevel ﾀｸﾞと og.cryptography ﾀｸﾞを切り出します｡
    051 * これらは､ｼｽﾃﾑﾊﾟﾗﾒｰﾀとしてGE12ﾃｰﾌﾞﾙに設定される値をｸﾗｽより抽出する
    052 * のに使用します｡
    053 *
    054 * @version  7.3
    055 * @author      Kazuhiko Hasegawa
    056 * @since        JDK11.0,
    057 */
    058public class DocTreeParam extends AbstractDocTree {
    059        private static final String OG_PARAM_LVL    = "og.paramLevel";
    060        private static final String OG_CRYPTOGRAPHY = "og.cryptography";
    061
    062        private static final int    CNST   = 1000;
    063
    064        private String systemId = "**" ;
    065        private String outfile;
    066
    067//      private DocTrees docUtil;
    068
    069        /**
    070         * ﾃﾞﾌｫﾙﾄｺﾝｽﾄﾗｸﾀｰ
    071         *
    072         * @og.rev 7.3.0.0 (2021/01/06) PMD refactoring. Each class should declare at least one constructor.
    073         */
    074        public DocTreeParam() { super(); }              // これも､自動的に呼ばれるが､空のﾒｿｯﾄﾞを作成すると警告されるので､明示的にしておきます｡
    075
    076        /**
    077         * Doclet のｴﾝﾄﾘﾎﾟｲﾝﾄﾒｿｯﾄﾞです(昔の startﾒｿｯﾄﾞ)｡
    078         *
    079         * @og.rev 7.3.0.0 (2021/01/06) 新しいJavaDoc対応
    080         *
    081         * @param docEnv ﾄﾞｯｸﾚｯﾄを1回呼び出す操作環境
    082         *
    083         * @return 正常実行時 true
    084         */
    085        @Override
    086        public boolean run( final DocletEnvironment docEnv ) {
    087                try( DocTreeWriter writer = new DocTreeWriter( outfile,ENCODE ) ) {
    088                        writer.printTag( "<?xml version=\"1.0\" encoding=\"", ENCODE , "\" ?>" );
    089                        writer.printTag( "<javadoc>" );
    090                        writer.printTag( " <systemId>" , systemId , "</systemId>" );
    091                        writeContents( docEnv,writer );
    092                        writer.printTag( "</javadoc>" );
    093                }
    094                catch( final Throwable th ) {
    095                        reporter.print(Kind.ERROR, th.getMessage());
    096                }
    097
    098                return true;
    099        }
    100
    101        /**
    102         * DocletEnvironmentよりｺﾝﾃﾝﾂを作成します｡
    103         *
    104         * @og.rev 7.3.0.0 (2021/01/06) 新しいJavaDoc対応
    105         * @og.rev 8.0.1.0 (2021/10/29) titleを改行か『｡』までの文字列を切り出す｡
    106         * @og.rev 8.0.2.1 (2021/12/10) ｺﾒﾝﾄ分割で『。』と半角の『｡』の両方対応しておく。
    107         *
    108         * @param docEnv        ﾄﾞｯｸﾚｯﾄの最上位
    109         * @param writer        DocTreeWriterｵﾌﾞｼﾞｪｸﾄ
    110         */
    111        private void writeContents( final DocletEnvironment docEnv, final DocTreeWriter writer ) {
    112                // get the DocTrees utility class to access document comments
    113//              docUtil = docEnv.getDocTrees();
    114                final DocTrees docUtil = docEnv.getDocTrees();
    115//              final Elements eleUtil  = docEnv.getElementUtils();
    116
    117                // ｸﾗｽ単位にﾙｰﾌﾟする｡
    118                for( final TypeElement typEle : ElementFilter.typesIn(docEnv.getIncludedElements())) {
    119                        int cnt = 0;
    120                        final String fullName = String.valueOf( typEle.getQualifiedName() ) ;
    121//                      final String fullName = String.valueOf(typEle);
    122//                      System.out.println(typEle.getKind() + ":" + fullName);
    123                        writer.setClassName( fullName );
    124
    125                        // ﾌｨｰﾙﾄﾞのみﾌｨﾙﾀﾘﾝｸﾞして取得する
    126                        for( final VariableElement varEle : ElementFilter.fieldsIn(typEle.getEnclosedElements())) {             // ﾌｨｰﾙﾄﾞだけに絞る
    127                                if( varEle.getModifiers().contains( Modifier.PUBLIC )) {                                                                                // public だけに絞る
    128                                        final DocCommentTree docTree = docUtil.getDocCommentTree(varEle);               // ﾄﾞｷｭﾒﾝﾃｰｼｮﾝ･ｺﾒﾝﾄが見つからない場合､null が返る｡
    129
    130                                        final String paramId                            = String.valueOf(varEle);
    131                                        final String seq                                        = String.valueOf(cnt*10 + CNST);
    132        //                              final List<? extends DocTree> title     = docTree == null ? EMPTY_LIST : docTree.getFirstSentence();
    133        //                              final List<? extends DocTree> cmnt      = docTree == null ? EMPTY_LIST : docTree.getFullBody();
    134                                        final String[] cmnts = getTitleCmnt( docTree );         // 8.0.1.0 (2021/10/29)
    135
    136                                        final String param = String.valueOf( varEle.getConstantValue() );
    137
    138                                        final Map<String,List<String>> blkTagMap = blockTagsMap(docTree);
    139                                        final String paramLvl = getBlockTag( OG_PARAM_LVL   , blkTagMap, "" ).split(":")[0];    // 取得した値を ':' で分割した最初の文字列｡
    140                                        final String fgcrypt  = getBlockTag( OG_CRYPTOGRAPHY, blkTagMap, "" ).split(":")[0];
    141
    142//                                      String paramLvl = "";
    143//                                      String fgcrypt  = "";
    144//                                      if( docTree != null ) {
    145//                                              for( final DocTree dt : docTree.getBlockTags() ) {
    146//                                                      final String tag = String.valueOf(dt);
    147//                                                      if( tag.contains( OG_PARAM_LVL ) ) {
    148//                                                              paramLvl = cut( tag,' ',':' );
    149//                                                      }
    150//                                                      else if( tag.contains( OG_CRYPTOGRAPHY ) ) {
    151//                                                              fgcrypt = cut( tag,' ',':' );
    152//                                                      }
    153//                                              }
    154//                                      }
    155
    156                                        writer.printTag( " <fieldDoc>" );
    157                                        writer.printTag( "   <paramId>"         ,paramId        ,"</paramId>"           );
    158                                        writer.printTag( "   <seq>"                     ,seq            ,"</seq>"                       );
    159                                        writer.printTag( "   <param>"           ,param          ,"</param>"                     );
    160//                                      writer.printTag( "   <title>"           ,title          ,"</title>"                     );
    161                                        writer.printTag( "   <title>"           ,cmnts[0]       ,"</title>"                     );      // 8.0.1.0 (2021/10/29)
    162//                                      writer.printTag( "   <contents>"        ,cmnt           ,"</contents>"          );
    163                                        writer.printTag( "   <contents>"        ,cmnts[1]       ,"</contents>"          );      // 8.0.1.0 (2021/10/29)
    164                                        writer.printTag( "   <paramLevel>"      ,paramLvl       ,"</paramLevel>"        );
    165                                        writer.printTag( "   <fgcrypt>"         ,fgcrypt        ,"</fgcrypt>"           );
    166                                        writer.printTag( " </fieldDoc>" );
    167
    168                                        cnt++;
    169                                }
    170                        }
    171                }
    172        }
    173
    174//      /**
    175//       * DocTreeﾘｽﾄから､最初の1文(改行か『｡』まで)と本文の文字列を切り出します｡
    176//       *
    177//       * title が､docTree.getFirstSentence(); でうまく取れていないようです｡
    178//       * docTree.getFullBody() で取ってきた最初の1文と､残りの本文を切り出します｡
    179//       *
    180//       * @og.rev 8.0.1.0 (2021/10/29) titleを改行か『｡』までの文字列を切り出す｡
    181//       * @og.rev 8.0.2.1 (2021/12/10) ｺﾒﾝﾄ分割で『。』と半角の『｡』の両方対応しておく。
    182//       * @og.rev 8.0.2.1 (2021/12/10) DocTreeParam → AbstractDocTree に移動
    183//       *
    184//       * @param docTree       DocCommentTreeｵﾌﾞｼﾞｪｸﾄ
    185//       * @return 最初の1文(改行か『｡』まで)と本文の文字列を分割した配列
    186//       */
    187//      private String[] getTitleCmnt( final DocCommentTree docTree ) {
    188//              final String[] rtns = { "","" };                // 初期値
    189//
    190//              if( docTree == null ) { return rtns; }
    191//              final List<? extends DocTree> doc = docTree.getFullBody();
    192//
    193//              if( doc.isEmpty() ) { return rtns; }
    194//
    195//              final String body = String.valueOf( doc.get(0) );
    196////            int st = body.indexOf( '｡' );
    197//              int st = Math.max( body.indexOf( '。' ) , body.indexOf( '｡' ) ); // 8.0.2.1 (2021/12/10)
    198//              if( st < 0 ) {
    199//                      st = body.indexOf( '\n' );
    200//              }
    201//
    202//              if( st >= 0 ) {
    203//                      rtns[0] = body.substring( 0,st ).trim();        // 一応､ｽﾍﾟｰｽは削除する｡
    204//                      rtns[1] = body.substring( st ).trim();          //
    205//              }
    206//              else {
    207//                      rtns[1] = body.trim();
    208//              }
    209//
    210//              return rtns ;
    211//      }
    212
    213        /**
    214         * ｻﾎﾟｰﾄされているすべてのｵﾌﾟｼｮﾝを返します｡
    215         *
    216         * @return ｻﾎﾟｰﾄされているすべてのｵﾌﾟｼｮﾝを含むｾｯﾄ､存在しない場合は空のｾｯﾄ
    217         */
    218        @Override
    219        public Set<? extends Option> getSupportedOptions() {
    220                final Option[] options = {
    221                        new AbstractOption( "-outfile", "-systemId" ) {
    222
    223                                /**
    224                                 * 必要に応じてｵﾌﾟｼｮﾝと引数を処理します｡
    225                                 *
    226                                 * @param  opt ｵﾌﾟｼｮﾝ名
    227                                 * @param  arguments 引数をｶﾌﾟｾﾙ化したﾘｽﾄ
    228                                 * @return 操作が成功した場合はtrue､そうでない場合はfalse
    229                                 */
    230                                @Override
    231                                public boolean process(final String opt, final List<String> arguments) {
    232                                        if( "-outfile".equalsIgnoreCase(opt) ) {
    233                                                outfile = arguments.get(0);
    234                                        }
    235                                        else if( "-systemId".equalsIgnoreCase(opt) ) {
    236                                                systemId = arguments.get(0);
    237                                        }
    238                                        return true;
    239                                }
    240                        }
    241                };
    242                return new HashSet<>(Arrays.asList(options));
    243        }
    244}