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  ;
032import 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         *
107         * @param docEnv        ドックレットの最上位
108         * @param writer        DocTreeWriterオブジェクト
109         */
110        private void writeContents( final DocletEnvironment docEnv, final DocTreeWriter writer ) {
111                // get the DocTrees utility class to access document comments
112//              docUtil = docEnv.getDocTrees();
113                final DocTrees docUtil = docEnv.getDocTrees();
114//              final Elements eleUtil  = docEnv.getElementUtils();
115
116                // クラス単位にループする。
117                for( final TypeElement typEle : ElementFilter.typesIn(docEnv.getIncludedElements())) {
118                        int cnt = 0;
119                        final String fullName = String.valueOf( typEle.getQualifiedName() ) ;
120//                      final String fullName = String.valueOf(typEle);
121//                      System.out.println(typEle.getKind() + ":" + fullName);
122                        writer.setClassName( fullName );
123
124                        // フィールドのみフィルタリングして取得する
125                        for( final VariableElement varEle : ElementFilter.fieldsIn(typEle.getEnclosedElements())) {             // フィールドだけに絞る
126                                if( varEle.getModifiers().contains( Modifier.PUBLIC )) {                                                                                // public だけに絞る
127                                        final DocCommentTree docTree = docUtil.getDocCommentTree(varEle);               // ドキュメンテーション・コメントが見つからない場合、null が返る。
128
129                                        final String paramId                            = String.valueOf(varEle);
130                                        final String seq                                        = String.valueOf(cnt*10 + CNST);
131        //                              final List<? extends DocTree> title     = docTree == null ? EMPTY_LIST : docTree.getFirstSentence();
132        //                              final List<? extends DocTree> cmnt      = docTree == null ? EMPTY_LIST : docTree.getFullBody();
133                                        final String[] cmnts = getTitleCmnt( docTree );         // 8.0.1.0 (2021/10/29)
134
135                                        final String param = String.valueOf( varEle.getConstantValue() );
136
137                                        final Map<String,List<String>> blkTagMap = blockTagsMap(docTree);
138                                        final String paramLvl = getBlockTag( OG_PARAM_LVL   , blkTagMap, "" ).split(":")[0];    // 取得した値を ':' で分割した最初の文字列。
139                                        final String fgcrypt  = getBlockTag( OG_CRYPTOGRAPHY, blkTagMap, "" ).split(":")[0];
140
141//                                      String paramLvl = "";
142//                                      String fgcrypt  = "";
143//                                      if( docTree != null ) {
144//                                              for( final DocTree dt : docTree.getBlockTags() ) {
145//                                                      final String tag = String.valueOf(dt);
146//                                                      if( tag.contains( OG_PARAM_LVL ) ) {
147//                                                              paramLvl = cut( tag,' ',':' );
148//                                                      }
149//                                                      else if( tag.contains( OG_CRYPTOGRAPHY ) ) {
150//                                                              fgcrypt = cut( tag,' ',':' );
151//                                                      }
152//                                              }
153//                                      }
154
155                                        writer.printTag( " <fieldDoc>" );
156                                        writer.printTag( "   <paramId>"         ,paramId        ,"</paramId>"           );
157                                        writer.printTag( "   <seq>"                     ,seq            ,"</seq>"                       );
158                                        writer.printTag( "   <param>"           ,param          ,"</param>"                     );
159//                                      writer.printTag( "   <title>"           ,title          ,"</title>"                     );
160                                        writer.printTag( "   <title>"           ,cmnts[0]       ,"</title>"                     );      // 8.0.1.0 (2021/10/29)
161//                                      writer.printTag( "   <contents>"        ,cmnt           ,"</contents>"          );
162                                        writer.printTag( "   <contents>"        ,cmnts[1]       ,"</contents>"          );      // 8.0.1.0 (2021/10/29)
163                                        writer.printTag( "   <paramLevel>"      ,paramLvl       ,"</paramLevel>"        );
164                                        writer.printTag( "   <fgcrypt>"         ,fgcrypt        ,"</fgcrypt>"           );
165                                        writer.printTag( " </fieldDoc>" );
166
167                                        cnt++;
168                                }
169                        }
170                }
171        }
172
173        /**
174         * DocTreeリストから、最初の1文(改行か『。』まで)と本文の文字列を切り出します。
175         *
176         * title が、docTree.getFirstSentence(); でうまく取れていないようです。
177         * docTree.getFullBody() で取ってきた最初の1文と、残りの本文を切り出します。
178         *
179         * @og.rev 8.0.1.0 (2021/10/29) titleを改行か『。』までの文字列を切り出す。
180         *
181         * @param docTree       DocCommentTreeオブジェクト
182         * @return 最初の1文(改行か『。』まで)と本文の文字列を分割した配列
183         */
184        private String[] getTitleCmnt( final DocCommentTree docTree ) {
185                final String[] rtns = { "","" };                // 初期値
186
187                if( docTree == null ) { return rtns; }
188                final List<? extends DocTree> doc = docTree.getFullBody();
189
190                if( doc.isEmpty() ) { return rtns; }
191
192                final String body = String.valueOf( doc.get(0) );
193                int st = body.indexOf( '。' );
194                if( st < 0 ) {
195                        st = body.indexOf( '\n' );
196                }
197
198                if( st >= 0 ) {
199                        rtns[0] = body.substring( 0,st ).trim();        // 一応、スペースは削除する。
200                        rtns[1] = body.substring( st ).trim();          //
201                }
202                else {
203                        rtns[1] = body.trim();
204                }
205
206                return rtns ;
207        }
208
209        /**
210         * サポートされているすべてのオプションを返します。
211         *
212         * @return サポートされているすべてのオプションを含むセット、存在しない場合は空のセット
213         */
214        @Override
215        public Set<? extends Option> getSupportedOptions() {
216                final Option[] options = {
217                        new AbstractOption( "-outfile", "-systemId" ) {
218
219                                /**
220                                 * 必要に応じてオプションと引数を処理します。
221                                 *
222                                 * @param  opt オプション名
223                                 * @param  arguments 引数をカプセル化したリスト
224                                 * @return 操作が成功した場合はtrue、そうでない場合はfalse
225                                 */
226                                @Override
227                                public boolean process(final String opt, final List<String> arguments) {
228                                        if( "-outfile".equalsIgnoreCase(opt) ) {
229                                                outfile = arguments.get(0);
230                                        }
231                                        else if( "-systemId".equalsIgnoreCase(opt) ) {
232                                                systemId = arguments.get(0);
233                                        }
234                                        return true;
235                                }
236                        }
237                };
238                return new HashSet<>(Arrays.asList(options));
239        }
240}