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
018// import jdk.javadoc.doclet.DocletEnvironment;
019import jdk.javadoc.doclet.Doclet;
020import jdk.javadoc.doclet.Reporter;
021// import javax.lang.model.element.Element;
022// import javax.lang.model.element.Modifier;
023// import javax.lang.model.element.TypeElement;
024// import javax.lang.model.element.ElementKind;
025// import javax.lang.model.element.VariableElement;
026import javax.lang.model.SourceVersion;
027// import javax.lang.model.util.ElementFilter;
028// import javax.lang.model.util.Elements;
029import javax.tools.Diagnostic.Kind;
030import com.sun.source.doctree.DocCommentTree;
031// import com.sun.source.util.DocTrees;
032import com.sun.source.doctree.DocTree;
033
034import java.util.Locale;
035// import java.util.Set;
036import java.util.List;
037// import java.util.HashSet;
038import java.util.Arrays;
039import java.util.ArrayList;
040
041import java.util.Map;
042import java.util.HashMap;
043
044// import java.io.IOException;
045// import java.io.File;
046// import java.io.PrintWriter;
047
048// import org.opengion.fukurou.util.FileUtil;
049// import org.opengion.fukurou.util.StringUtil;
050
051/**
052 * ソースコメントから、パラメータ情報を取り出す Doclet クラスです。
053 * og.paramLevel タグと og.cryptography タグを切り出します。
054 * これらは、システムパラメータとしてGE12テーブルに設定される値をクラスより抽出する
055 * のに使用します。
056 *
057 * @version     7.3
058 * @author      Kazuhiko Hasegawa
059 * @since       JDK11.0,
060 */
061public abstract class AbstractDocTree implements Doclet {
062        /** エンコード {@value} */
063        public static final String ENCODE = "UTF-8";
064
065        /** 情報の出力 */
066        protected Reporter reporter;                                                                    // JavaDocの情報、警告、エラー情報の出力
067
068        /** 空DocTreeリスト */
069        protected static final List<DocTree> EMPTY_LIST = List.of();    // ゼロ要素を含む変更不可能なリスト
070
071        /**
072         * デフォルトコンストラクター
073         *
074         * @og.rev 7.3.0.0 (2021/01/06) PMD refactoring. Each class should declare at least one constructor.
075         */
076        public AbstractDocTree() { super(); }           // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
077
078        /**
079         * 指定されたロケールとエラー・レポータでこのドックレットを初期化します。
080         *
081         * @og.rev 7.3.0.0 (2021/01/06) 新しいJavaDoc対応
082         *
083         * @param       locale          使用されるロケール
084         * @param       reporter        使用するレポータ
085         */
086        @Override       // Doclet
087        public void init(final Locale locale, final Reporter reporter) {
088                reporter.print(Kind.NOTE, getName() + " Start!: ");             // NOTE:情報 WARNING:警告 ERROR:エラー
089                this.reporter = reporter;
090        }
091
092        /**
093         * ドックレットを識別する名前を返します。
094         *
095         * @return      名前
096         */
097        @Override       // Doclet
098        public String getName() {
099                return getClass().getSimpleName();
100        }
101
102        /**
103         * Doclet.Option を継承し、共通メソッドを実装したabstractクラス
104         *
105         * 単純に、メソッドのOverrideで共通化しているだけです。
106         */
107        protected static abstract class AbstractOption implements Option {
108                private final List<String> someOption ;
109
110                /**
111                 * コンストラクター。
112                 *
113                 * @param       prm     引数に対応するキーの可変引数
114                 */
115                AbstractOption( final String... prm ) {
116                        super();
117                        someOption = Arrays.asList( prm );
118                }
119
120                /**
121                 * このオプションが消費する引数の数を返します。
122                 *
123                 * @return      消費された引数の数
124                 */
125                @Override       // Doclet.Option
126                public int getArgumentCount() {
127                        return 1;
128                }
129
130                /**
131                 * オプションの説明を返します。
132                 *
133                 * @return      設定されている場合はdescription、そうでない場合は空のString
134                 */
135                @Override       // Doclet.Option
136                public String getDescription() {
137                        return "an option with aliases";
138                }
139
140                /**
141                 * オプションの種類を返します。
142                 *
143                 * @return      このオプションの種類
144                 */
145                @Override       // Doclet.Option
146                public Option.Kind getKind() {
147                        return Option.Kind.STANDARD;
148                }
149
150                /**
151                 * オプションを識別するために使用される可能性のある名前のリストを返します。
152                 *
153                 * @return      オプションの名前リスト
154                 */
155                @Override       // Doclet.Option
156                public List<String> getNames() {
157                        return someOption;
158                }
159
160                /**
161                 * オプションのパラメータを返します。
162                 *
163                 * @return      設定されている場合はパラメータ、それ以外の場合は空のString
164                 */
165                @Override       // Doclet.Option
166                public String getParameters() {
167                        return "file";
168                }
169        }
170
171        /**
172         * このドックレットでサポートされているJavaプログラミング言語のバージョンを返します。
173         *
174         * @return      通常は最新バージョン
175         */
176        @Override       // Doclet
177        public SourceVersion getSupportedSourceVersion() {
178                // support the latest release
179                return SourceVersion.latest();
180        }
181
182        /* ************************************************************************************ */
183
184//      /**
185//       * 指定の文字列から、開始文字と終了文字の間を切り抜いて返します。
186//       * 開始文字か、終了文字のどちらかが存在しない場合は、オリジナルの文字列を返します。
187//       *
188//       * @param       org     オリジナルの文字列
189//       * @param       stCh    開始文字
190//       * @param       edCh    終了文字
191//       * @return      切り抜かれた文字列
192//       */
193//      protected String cut( final String org , final char stCh , final char edCh ) {
194//              final int st = org.indexOf( stCh );
195//              final int ed = st > 0 ? org.indexOf( edCh , st ) : -1;
196//
197//              return ed > 0 ? org.substring( st+1,ed ) : org ;
198//      }
199
200//      /**
201//       * 指定の文字列から、開始文字と終了文字の間を切り抜いて返します。
202//       * 開始文字か、終了文字のどちらかが存在しない場合は、オリジナルの文字列を返します。
203//       *
204//       * @param       org     オリジナルの文字列
205//       * @param       omit    先頭から削除する文字列
206//       * @return      切り抜かれた文字列
207//       */
208//      protected String cutTag( final String org , final String omit ) {
209//              return org.substring( 1+omit.length() ).trim();
210//      }
211
212        /**
213         * BlockTagsのキーとリストのMapを作成して返します。
214         * キーと値を分離します。同じキーが複数存在しますので、それらは Listに入れて返します。
215         * docTreeは、null の場合もあるので、その場合は、空のMapを返します。
216         *
217         * @param       docTree DocCommentTreeオブジェクト
218         * @return      BlockTagsのキーとリストのMap
219         */
220        protected Map<String,List<String>> blockTagsMap( final DocCommentTree docTree ) {
221                final Map<String,List<String>> rtnMap = new HashMap<>();
222
223                if( docTree != null ) {
224                        for( final DocTree dt : docTree.getBlockTags() ) {
225                                final String tag = String.valueOf(dt).trim();
226                                final int ad = tag.indexOf( ' ' );                                                                      // 最初のスペースで分離
227                                final String key = ad > 0 ? tag.substring( 1,ad ).trim() : tag ;        // 最初の文字列は、@ なので。
228                                final String val = ad > 0 ? tag.substring( ad+1 ).trim() : "" ;
229
230                                rtnMap.computeIfAbsent(key, k -> new ArrayList<String>()).add( val );
231                        }
232                }
233
234                return rtnMap;
235        }
236
237        /**
238         * blockTagsMapで作成されたMapオブジェクトから、文字列を作成します。
239         * キーがMapに存在しない場合は、空文字列を返します。
240         * docTreeは、null の場合もあるので、その場合は、空のMapを返します。
241         *
242         * @param       key                     blockTagのキー
243         * @param       blcMap          blockTagsMapで作成されたMapオブジェクト
244         * @param       delimiter       複数タグを連結する場合の、区切り文字
245         * @return      指定のタグの文字列
246         */
247        protected String getBlockTag( final String key,final Map<String,List<String>> blcMap,final String delimiter ) {
248                final List<String> blkList = blcMap.get( key );
249
250                return blkList == null ? "" : String.join( delimiter,blkList );
251        }
252
253        /**
254         * DocTreeリストから、最初の1文(改行か『。』まで)と本文の文字列を切り出します。
255         *
256         * title が、docTree.getFirstSentence(); でうまく取れていないようです。
257         * docTree.getFullBody() で取ってきた最初の1文と、残りの本文を切り出します。
258         *
259         * @og.rev 8.0.1.0 (2021/10/29) titleを改行か『。』までの文字列を切り出す。
260         * @og.rev 8.0.2.1 (2021/12/10) コメント分割で『。』と半角の『。』の両方対応しておく。
261         * @og.rev 8.0.2.1 (2021/12/10) DocTreeParam → AbstractDocTree に移動
262         * @og.rev 8.5.1.0 (2023/06/30) docTreeの変換がunicodeの為、正しく動作しなかった『。』変換対応
263         *
264         * @param       docTree DocCommentTreeオブジェクト
265         * @return      最初の1文(改行か『。』まで)と本文の文字列を分割した配列
266         */
267        protected String[] getTitleCmnt( final DocCommentTree docTree ) {
268                final String[] rtns = { "","" };                                                                                // 初期値
269
270                if( docTree == null ) { return rtns; }
271                final List<? extends DocTree> doc = docTree.getFullBody();
272                if( doc.isEmpty() ) { return rtns; }
273//              final String body = String.valueOf( doc.get(0) );
274
275                final StringBuilder buf = new StringBuilder();                                                  // 8.0.2.1 (2021/12/10) & で切れる?
276                doc.forEach( val -> buf.append(val) );
277                final String body = buf.toString();
278
279//              int st = body.indexOf( '。' );
280//              int st = Math.max( body.indexOf( '。' ) , body.indexOf( '。' ) );         // 8.0.2.1 (2021/12/10)
281                int st = Math.max( body.indexOf( "u3002" ) , body.indexOf( "uff61" ) ); // 8.5.1.0 (2023/06/27) Modify
282
283                if( st < 0 ) {
284                        st = body.indexOf( '\n' );
285                }
286
287                if( st >= 0 ) {
288                        st += 5;                                                                                                                        // 8.5.1.0 (2023/06/27) Add
289                        rtns[0] = body.substring( 0,st ).trim();                                                        // 一応、スペースは削除する。
290                        rtns[1] = body.substring( st ).trim();                                                          // 一応、スペースは削除する。
291                        if( rtns[1].isEmpty() ) { rtns[1] = rtns[0]; }
292                }
293                else {
294                        rtns[0] = body.trim();
295                        rtns[1] = rtns[0];                                                                                                      // 8.0.2.1 (2021/12/10) 同じ値をセットする。
296                }
297
298                return rtns ;
299        }
300}