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 */
016// 7.4.4.0 (2021/06/30) openGionV8事前準備(taglet2→taglet)
017//package org.opengion.fukurou.taglet2;
018package org.opengion.fukurou.taglet;
019
020
021import jdk.javadoc.doclet.DocletEnvironment      ;
022// import jdk.javadoc.doclet.Doclet  ;
023// import jdk.javadoc.doclet.Reporter ;
024// import javax.lang.model.element.Element      ;
025import javax.lang.model.element.Modifier ;
026import javax.lang.model.element.TypeElement;
027// import javax.lang.model.element.ElementKind  ;
028// import javax.lang.model.element.VariableElement;
029// import javax.lang.model.SourceVersion         ;
030import javax.lang.model.type.TypeMirror;
031// import javax.lang.model.type.PrimitiveType;
032import javax.lang.model.util.ElementFilter       ;
033import javax.lang.model.util.Elements ;
034// import javax.lang.model.util.Types    ;
035import javax.tools.Diagnostic.Kind       ;
036import com.sun.source.doctree.DocCommentTree  ;
037import com.sun.source.util.DocTrees  ;
038import com.sun.source.doctree.DocTree  ;
039
040// import java.util.Locale ;
041import java.util.Set;
042import java.util.List;
043import java.util.HashSet;
044import java.util.Arrays;
045import java.util.Map;
046import java.util.HashMap;
047
048// import java.io.IOException;
049// import java.io.File;
050// import java.io.PrintWriter;
051
052// import org.opengion.fukurou.util.FileUtil;
053// import org.opengion.fukurou.util.StringUtil;
054
055/**
056 * ソースコメントから、パラメータ情報を取り出す Doclet クラスです。
057 * og.paramLevel タグと og.cryptography タグを切り出します。
058 * これらは、システムパラメータとしてGE12テーブルに設定される値をクラスより抽出する
059 * のに使用します。
060 *
061 * @version  7.3
062 * @author      Kazuhiko Hasegawa
063 * @since        JDK11.0,
064 */
065public class DocTreePlugin extends AbstractDocTree {
066        private static final String OG_FOR_SMPL  = "og.formSample";
067
068        /** 6.4.3.1 (2016/02/12) PMD refactoring. HashMap → ConcurrentHashMap に置き換え。  */
069        // 6.4.3.3 (2016/03/04) 匿名クラスとインスタンス初期化子による、Mapの初期化処理。
070        /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */
071        private static final Map<String,AttKeySet> ATT_KEY_MAP = new HashMap<>();
072        static {
073                int no = 0;                             // 7.2.2.0 (2020/03/27) 連番の自動生成
074                ATT_KEY_MAP.put( "org.opengion.hayabusa.db.Query"                                       , new AttKeySet( "Query"                        ,no++, "queryType"              ));
075                ATT_KEY_MAP.put( "org.opengion.hayabusa.db.CellRenderer"                        , new AttKeySet( "Renderer"                     ,no++, "renderer"               ));
076                ATT_KEY_MAP.put( "org.opengion.hayabusa.db.CellEditor"                          , new AttKeySet( "Editor"                       ,no++, "editor"                 ));
077                ATT_KEY_MAP.put( "org.opengion.hayabusa.db.DBType"                                      , new AttKeySet( "DBType"                       ,no++, "dbType"                 ));
078                ATT_KEY_MAP.put( "org.opengion.hayabusa.db.TableFilter"                         , new AttKeySet( "TableFilter"          ,no++, "tableFilter"    ));
079                ATT_KEY_MAP.put( "org.opengion.hayabusa.db.Selection"                           , new AttKeySet( "Selection"            ,no++, "selection"              ));
080                ATT_KEY_MAP.put( "org.opengion.hayabusa.db.DBConstValue"                        , new AttKeySet( "DBConstValue"         ,no++, "cnstVal"                ));             // 5.6.3.3 (2013/04/19)
081                ATT_KEY_MAP.put( "org.opengion.hayabusa.html.ViewForm"                          , new AttKeySet( "ViewForm"                     ,no++, "viewFormType"   ));
082                ATT_KEY_MAP.put( "org.opengion.hayabusa.io.TableWriter"                         , new AttKeySet( "TableWriter"          ,no++, "writerClass"    ));
083                ATT_KEY_MAP.put( "org.opengion.hayabusa.io.TableReader"                         , new AttKeySet( "TableReader"          ,no++, "readerClass"    ));
084//              ATT_KEY_MAP.put( "org.opengion.hayabusa.report.DBTableReport"           , new AttKeySet( "DBTableReport"        ,no++, "tableReport"    ));             // 7.0.1.5 (2018/12/10) 削除
085                ATT_KEY_MAP.put( "org.opengion.hayabusa.resource.CalendarQuery"         , new AttKeySet( "CalendarQuery"        ,no++, "calDB"                  ));
086                ATT_KEY_MAP.put( "org.opengion.hayabusa.resource.CalendarData"          , new AttKeySet( "CalendarData"         ,no++, "calData"                ));             // 5.6.3.3 (2013/04/19)
087                ATT_KEY_MAP.put( "org.opengion.fukurou.process.HybsProcess"                     , new AttKeySet( "Process"                      ,no++, "process"                ));
088//              ATT_KEY_MAP.put( "org.opengion.fukurou.transfer.TransferExec"           , new AttKeySet( "TransferExec"         ,no++, "kbExec"                 ));             // 5.5.3.5 (2012/06/21)
089//              ATT_KEY_MAP.put( "org.opengion.fukurou.transfer.TransferRead"           , new AttKeySet( "TransferRead"         ,no++, "kbRead"                 ));             // 5.5.3.5 (2012/06/21)
090                ATT_KEY_MAP.put( "org.opengion.fukurou.util.HybsTimerTask"                      , new AttKeySet( "Daemon"                       ,no++, "daemon"                 ));             // 4.3.4.4 (2009/01/01)
091                ATT_KEY_MAP.put( "org.opengion.fukurou.util.ConnectIF   "                       , new AttKeySet( "ConnectIF"            ,no++, "connIF"                 ));             // 5.6.3.3 (2013/04/19)
092                ATT_KEY_MAP.put( "org.opengion.fukurou.xml.JspParserFilter"                     , new AttKeySet( "JspCreate"            ,no++, "jspParser"              ));             // 5.6.3.3 (2013/04/19)
093        }
094
095        private String version  ;
096        private String outfile  ;
097
098//      private DocTrees docUtil;
099//      private Elements eleUtil ;
100
101        /**
102         * Doclet のエントリポイントメソッドです(昔の startメソッド)。
103         *
104         * @og.rev 7.3.0.0 (2021/01/06) 新しいJavaDoc対応
105         *
106         * @param docEnv ドックレットを1回呼び出す操作環境
107         *
108         * @return 正常実行時 true
109         */
110        @Override
111        public boolean run( final DocletEnvironment docEnv ) {
112                try( DocTreeWriter writer = new DocTreeWriter( outfile,ENCODE ) ) {
113                        // 5.7.1.1 (2013/12/13) タグのインデントを止める。
114                        writer.printTag( "<?xml version=\"1.0\" encoding=\"", ENCODE, "\" ?>" );
115                        writer.printTag( "<javadoc>" );
116                        writer.printTag( "  <version>",version,"</version>" );
117                        writer.printTag( "  <description></description>" );
118                        writeContents( docEnv,writer );
119                        writer.printTag( "</javadoc>" );
120                }
121                catch( final Throwable th ) {
122                        reporter.print(Kind.ERROR, th.getMessage());
123                }
124
125                return true;
126        }
127
128        /**
129         * DocletEnvironmentよりコンテンツを作成します。
130         *
131         * @og.rev 7.3.0.0 (2021/01/06) 新しいJavaDoc対応
132         *
133         * @param docEnv        ドックレットの最上位
134         * @param writer        DocTreeWriterオブジェクト
135         */
136        private void writeContents( final DocletEnvironment docEnv, final DocTreeWriter writer ) {
137//              docUtil = docEnv.getDocTrees();
138//              eleUtil = docEnv.getElementUtils();
139
140//              // get the DocTrees utility class to access document comments
141                final DocTrees docUtil = docEnv.getDocTrees();
142                final Elements eleUtil  = docEnv.getElementUtils();
143
144                // クラス単位にループする。
145                for( final TypeElement typEle : ElementFilter.typesIn(docEnv.getIncludedElements())) {
146                        if( !typEle.getModifiers().contains( Modifier.PUBLIC ) ) { continue; }
147
148                        final String fullName   = String.valueOf( typEle.getQualifiedName() ) ;
149//                      final String fullName = String.valueOf(typEle);
150        //              System.out.println(typEle.getKind() + ":" + fullName);
151                        writer.setClassName( fullName );
152
153                        final AttKeySet attSet = getAttGroupName( typEle,eleUtil ) ;
154                        if( attSet == null ) { continue; }              // map に登録されていない。
155
156                        final int ed = fullName.lastIndexOf( '.' );
157                        String attKey = null;
158                        if( ed > 0 ) {
159                                final String name = fullName.substring( ed+1 );
160                                attKey = attSet.getAttKey( name );
161                        }
162                        if( attKey == null ) { continue; }              // 対象クラス名が、一致しない。
163
164                        final DocCommentTree docTree = docUtil.getDocCommentTree(typEle);               // ドキュメンテーション・コメントが見つからない場合、null が返る。
165
166                        final List<? extends DocTree> desc      = docTree == null ? EMPTY_LIST : docTree.getFirstSentence();
167                        final List<? extends DocTree> cmnt      = docTree == null ? EMPTY_LIST : docTree.getFullBody();
168
169                        final Map<String,List<String>> blkTagMap = blockTagsMap(docTree);
170                        final String smplTags   = getBlockTag( OG_FOR_SMPL, blkTagMap, "" );
171
172//                      String smplTags = "";
173//                      if( docTree != null ) {
174//                              for( final DocTree dt : docTree.getBlockTags() ) {
175//                                      final String tag = String.valueOf(dt);
176//                                      if( tag.contains( OG_FOR_SMPL ) ) {
177//                                              smplTags = tag.substring( OG_FOR_SMPL.length() + 1 ).trim();
178//                                      }
179//                              }
180//                      }
181
182                        // 5.7.1.1 (2013/12/13) タグのインデントを止める。
183                        writer.printTag( "<classDoc>" );
184                        writer.printTag( "  <attClass>"         ,fullName                               ,"</attClass>"          );
185                        writer.printTag( "  <seq>"                      ,attSet.getSeq()                ,"</seq>"                       );
186                        writer.printTag( "  <attKey>"           ,attKey                                 ,"</attKey>"            );
187                        writer.printTag( "  <valueName>"        ,attSet.getValueName()  ,"</valueName>"         );
188                        writer.printTag( "  <description>"      ,desc                                   ,"</description>"       );
189                        writer.printTag( "  <contents>"         ,cmnt                                   ,"</contents>"          );
190                        writer.printTag( "  <formSample>"       ,smplTags                               ,"</formSample>"        );
191                        writer.printTag( "</classDoc>" );
192                }
193        }
194
195        /**
196         * 指定の ClassDoc が、処理する属性クラスのMapに含まれている場合、
197         * その AttKeySet クラスのオブジェクトを返します。
198         * 存在しない場合、null を返します。
199         *
200         * @og.rev 7.3.0.0 (2021/01/06) 新しいJavaDoc対応
201         *
202         * @param       typEle TypeElementオブジェクト
203         * @param       eleUtil Elementsユーティリティ
204         *
205         * @return      typEleに対応する AttKeySetオブジェクト
206         */
207        private static AttKeySet getAttGroupName( final TypeElement typEle,final Elements eleUtil ) {
208                if( typEle == null ) { return null; }
209
210                final String fullName = String.valueOf(typEle);
211                AttKeySet attKey = ATT_KEY_MAP.get( fullName );
212                if( attKey == null ) {
213                        for( final TypeElement tp : eleUtil.getAllTypeElements(fullName) ) {
214                                if( typEle.equals( tp ) ) { continue; }
215                                attKey = getAttGroupName( tp,eleUtil );
216                                if( attKey != null ) { return attKey; }
217                        }
218
219                        final TypeMirror stype = typEle.getSuperclass();                        // 親クラスタイプ
220                        if( stype != null ) {
221                                final String suCls = String.valueOf( stype );
222                                attKey = ATT_KEY_MAP.get( suCls );      // 親クラス
223                                if( attKey == null ) {
224                                        for( final TypeElement tp : eleUtil.getAllTypeElements(suCls) ) {
225                                                if( typEle.equals( tp ) ) { continue; }
226                                                attKey = getAttGroupName( tp,eleUtil );
227                                                if( attKey != null ) { return attKey; }
228                                        }
229                                }
230                        }
231
232                        if( attKey == null ) {
233                                for( final TypeMirror itype : typEle.getInterfaces() ) {                // 直近インターフェース
234                                        final String intFce = String.valueOf( itype );
235                                        attKey = ATT_KEY_MAP.get( intFce );
236                                        if( attKey != null ) { return attKey; }
237                                        else {
238                                                for( final TypeElement tp : eleUtil.getAllTypeElements(intFce) ) {
239                                                        if( typEle.equals( tp ) ) { continue; }
240                                                        attKey = getAttGroupName( tp,eleUtil );
241                                                        if( attKey != null ) { return attKey; }
242                                                }
243                                        }
244                                }
245                        }
246                }
247
248                return attKey;
249        }
250
251        /**
252         * 属性情報を管理する、AttKeySet クラスです。
253         *
254         * @og.rev 7.3.0.0 (2021/01/06) 新しいJavaDoc対応
255         *
256         * @version  4.0
257         * @author   Kazuhiko Hasegawa
258         * @since    JDK5.0,
259         */
260        private static final class AttKeySet {
261                private final String searchKey ;
262                private final int    len ;
263                private final String seq ;
264                private final String valueName ;
265
266                /**
267                 * コンストラクター
268                 *
269                 * @param searchKey  検索キー
270                 * @param seq        シーケンス番号
271                 * @param valueName  属性名
272                 *
273                 */
274                /* default */ AttKeySet( final String searchKey,final int seq,final String valueName ) {
275                        this.searchKey          = searchKey ;
276                        this.seq                = String.valueOf( seq );
277                        this.valueName          = valueName ;
278
279                        len = searchKey.length();
280                }
281
282                /**
283                 * シーケンス番号を返します。
284                 *
285                 * @return シーケンス番号
286                 *
287                 */
288                /* default */ String getSeq() {
289                        return seq;
290                }
291
292                /**
293                 * 属性名を返します。
294                 *
295                 * @return 属性名
296                 *
297                 */
298                /* default */ String getValueName() {
299                        return valueName;
300                }
301
302                /**
303                 * クラス名の先頭一致の場合の、**** 部分を返します。
304                 * インターフェースも扱えるように修正しましたので、先頭が _ の場合は、
305                 * _ を削除して返します。
306                 *
307                 * @param name クラスの名称 (例:DBCellEditor_**** , ViewForm_****)
308                 * @return クラス名の**** 部分
309                 */
310                /* default */ String getAttKey( final String name ) {
311                        // 6.1.0.0 (2014/12/26) refactoring
312                        String rtn = null;                                                              // 一致しなかった。
313
314                        if( name.equals( searchKey ) ) {                                // 完全一致:インターフェース
315                                rtn =  "(Interface)" + name ;
316                        }
317                        else if( name.indexOf( searchKey ) == 0 ) {             // 先頭一致した。
318                                rtn = name.substring( len );
319                                if( rtn.charAt(0) == '_' ) { rtn = rtn.substring( 1 ); }        // 先頭が _ の場合は、_ を削除
320                        }
321
322                        return rtn ;
323                }
324        }
325
326        /**
327         * サポートされているすべてのオプションを返します。
328         *
329         * @return サポートされているすべてのオプションを含むセット、存在しない場合は空のセット
330         */
331        @Override
332        public Set<? extends Option> getSupportedOptions() {
333                final Option[] options = {
334                        new AbstractOption( "-outfile", "-version" ) {
335
336                                /**
337                                 * 必要に応じてオプションと引数を処理します。
338                                 *
339                                 * @param  opt オプション名
340                                 * @param  arguments 引数をカプセル化したリスト
341                                 * @return 操作が成功した場合はtrue、そうでない場合はfalse
342                                 */
343                                @Override
344                                public boolean process(final String opt, final List<String> arguments) {
345                                        if( "-outfile".equalsIgnoreCase(opt) ) {
346                                                outfile = arguments.get(0);
347                                        }
348                                        else if( "-version".equalsIgnoreCase(opt) ) {
349                                                version = arguments.get(0);
350                                        }
351                                        return true;
352                                }
353                        }
354                };
355                return new HashSet<>(Arrays.asList(options));
356        }
357}