OSDN Git Service

Ver8.5.2.0
[opengion/opengionV8.git] / uap / webapps / gf / src / org / opengion / fukurou / taglet / DocTreeTaglib.java
1 /*
2  * Copyright (c) 2009 The openGion Project.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
13  * either express or implied. See the License for the specific language
14  * governing permissions and limitations under the License.
15  */
16 package org.opengion.fukurou.taglet;            // 7.4.4.0 (2021/06/30) openGionV8事前準備(taglet2→taglet)
17
18 import jdk.javadoc.doclet.DocletEnvironment      ;
19 // import jdk.javadoc.doclet.Doclet  ;
20 // import jdk.javadoc.doclet.Reporter ;
21 // import javax.lang.model.element.Element      ;
22 import javax.lang.model.element.Modifier ;
23 import javax.lang.model.element.TypeElement;
24 // import javax.lang.model.element.ElementKind  ;
25 // import javax.lang.model.element.VariableElement;
26 import javax.lang.model.element.ExecutableElement;
27 // import javax.lang.model.SourceVersion ;
28 import javax.lang.model.type.TypeMirror;
29 import javax.lang.model.type.TypeKind;
30 import javax.lang.model.util.ElementFilter ;
31 import javax.lang.model.util.Elements ;
32 import javax.tools.Diagnostic.Kind ;
33 import com.sun.source.doctree.DocCommentTree  ;
34 import com.sun.source.util.DocTrees  ;
35 // import com.sun.source.util.DocSourcePositions  ;
36 // import com.sun.source.doctree.DocTree  ;
37
38 // import java.util.Locale ;
39 import java.util.Set;
40 import java.util.Map;
41 // import java.util.HashMap;
42 import java.util.List;
43 import java.util.HashSet;
44 import java.util.Arrays;
45 // import java.util.stream.Stream;                                                                              // 6.4.3.4 (2016/03/11)
46 // import java.util.stream.Collectors;                                                                  // 6.4.3.4 (2016/03/11)
47
48 // import java.io.IOException;
49 // import java.io.File;
50 // import java.io.PrintWriter;
51
52 // import org.opengion.fukurou.util.FileUtil;
53 // import org.opengion.fukurou.util.StringUtil;
54
55 /**
56  * ソースコメントから、パラメータ情報を取り出す Doclet クラスです。
57  * og.paramLevel タグと og.cryptography タグを切り出します。
58  * これらは、システムパラメータとしてGE12テーブルに設定される値をクラスより抽出する
59  * のに使用します。
60  *
61  * @version  7.3
62  * @author      Kazuhiko Hasegawa
63  * @since        JDK11.0,
64  */
65 public class DocTreeTaglib extends AbstractDocTree {
66         private static final String OG_FOR_SMPL = "og.formSample";
67         private static final String OG_TAG_NAME = "og.tag";
68         private static final String OG_GROUP    = "og.group";
69
70         private static final String     DOC_PARAM       = "param";              // 6.1.1.0 (2015/01/17)
71
72         private static final String OG_TAG_CLASS = "org.opengion.hayabusa.taglib";
73
74         private String  version         ;
75         private String  outfile         ;
76
77 //      private DocTrees docUtil;
78 //      private Elements eleUtil ;
79
80         /**
81          * デフォルトコンストラクター
82          *
83          * @og.rev 7.3.0.0 (2021/01/06) PMD refactoring. Each class should declare at least one constructor.
84          */
85         public DocTreeTaglib() { super(); }             // これも、自動的に呼ばれるが、空のメソッドを作成すると警告されるので、明示的にしておきます。
86
87         /**
88          * Doclet のエントリポイントメソッドです(昔の startメソッド)。
89          *
90          * @og.rev 7.3.0.0 (2021/01/06) 新しいJavaDoc対応
91          *
92          * @param docEnv ドックレットを1回呼び出す操作環境
93          *
94          * @return 正常実行時 true
95          */
96         @Override
97         public boolean run( final DocletEnvironment docEnv ) {
98                 try( DocTreeWriter writer = new DocTreeWriter( outfile,ENCODE ) ) {
99                         writer.printTag( "<?xml version=\"1.0\" encoding=\"", ENCODE , "\" ?>" );
100                         writer.printTag( "<javadoc>" );
101                         writer.printTag( "  <version>",version,"</version>" );
102                         writer.printTag( "  <description></description>" );
103                         writeContents( docEnv,writer );
104                         writer.printTag( "</javadoc>" );
105                 }
106                 catch( final Throwable th ) {
107                         reporter.print(Kind.ERROR, th.getMessage());
108                 }
109
110                 return true;
111         }
112
113         /**
114          * DocletEnvironmentよりコンテンツを作成します。
115          *
116          * @og.rev 7.3.0.0 (2021/01/06) 新しいJavaDoc対応
117          * @og.rev 8.0.2.1 (2021/12/10) tagGroupがdescriptionと合わせて出力されるため、【】でくくります。
118          * @og.rev 8.0.2.1 (2021/12/10) コメント分割で『。』と半角の『。』の両方対応しておく。
119          *
120          * @param docEnv        ドックレットの最上位
121          * @param writer        DocTreeWriterオブジェクト
122          */
123         private void writeContents( final DocletEnvironment docEnv, final DocTreeWriter writer ) {
124 //              docUtil = docEnv.getDocTrees();
125 //              eleUtil = docEnv.getElementUtils();
126
127 //              // get the DocTrees utility class to access document comments
128                 final DocTrees docUtil = docEnv.getDocTrees();
129                 final Elements eleUtil  = docEnv.getElementUtils();
130
131                 final Set<String> mtdClsSet = new HashSet<>();                  //  6.4.3.1 (2016/02/12) 変数名も変えておきます。
132
133                 // クラス単位にループする。
134                 for( final TypeElement typEle : ElementFilter.typesIn(docEnv.getIncludedElements())) {
135                         final String fullName   = String.valueOf( typEle.getQualifiedName() ) ;
136 //                      final String fullName = String.valueOf( typEle ) ;
137                         writer.setClassName( fullName );
138
139                         if( !typEle.getModifiers().contains( Modifier.PUBLIC ) ||
140                                 !fullName.contains( OG_TAG_CLASS ) ) { continue; }              // public かつ taglib に絞る
141
142                         final DocCommentTree docTree = docUtil.getDocCommentTree(typEle);               // ドキュメンテーション・コメントが見つからない場合、null が返る。
143
144 //                      final List<? extends DocTree> desc      = docTree == null ? EMPTY_LIST : docTree.getFirstSentence();
145 //                      final List<? extends DocTree> cmnt      = docTree == null ? EMPTY_LIST : docTree.getFullBody();
146                         final String[] cmnts = getTitleCmnt( docTree );                                                 // 8.0.2.1 (2021/12/10)
147
148                         final Map<String,List<String>> blkTagMap = blockTagsMap(docTree);
149                         final String smplTags   = getBlockTag( OG_FOR_SMPL, blkTagMap, ""  );
150                         final String grpTags    = getBlockTag( OG_GROUP   , blkTagMap, "," );
151
152 //                      String smplTags         = "";
153 //                      final StringBuilder grpBuf = new StringBuilder();
154 //                      if( docTree != null ) {
155 //                              for( final DocTree dt : docTree.getBlockTags() ) {
156 //                                      final String tag = String.valueOf(dt);
157 //                                      if(      tag.contains( OG_FOR_SMPL      ) ) { smplTags  = cutTag( tag,OG_FOR_SMPL       ); }
158 //                                      else if( tag.contains( OG_GROUP         ) ) { grpBuf.append( '【' ).append( cutTag( tag,OG_GROUP ) ).append( "】," ); }
159 //                              }
160 //                      }
161 //                      final String grpTags = grpBuf.length() == 0 ? "" : grpBuf.substring(0,grpBuf.length()-1);       // 最後のカンマを削除
162
163                         // 5.7.1.1 (2013/12/13) タグのインデントを止める。
164                         writer.printTag( "<classDoc>" );
165                         writer.printTag( "  <tagClass>"         ,fullName       ,"</tagClass>"          );
166                         writer.printTag( "  <tagGroup>【"      ,grpTags        ,"】</tagGroup>"       );              // 8.0.2.1 (2021/12/10)
167 //                      writer.printTag( "  <description>"      ,desc           ,"</description>"       );
168                         writer.printTag( "  <description>"      ,cmnts[0]       ,"</description>"       );              // 8.0.2.1 (2021/12/10)
169 //                      writer.printTag( "  <contents>"         ,cmnt           ,"</contents>"          );
170                         writer.printTag( "  <contents>"         ,cmnts[1]       ,"</contents>"          );              // 8.0.2.1 (2021/12/10)
171                         writer.printTag( "  <formSample>"       ,smplTags       ,"</formSample>"        );
172
173                         mtdClsSet.clear();
174                         String className = String.valueOf( typEle );
175                         TypeElement loopEle = typEle;
176                         while(  loopEle != null                                         &&
177                                         className.contains( OG_TAG_CLASS ) ) {
178
179                                 writer.setClassName( className );
180                                 final String extendFlag = String.valueOf( className.contains( "HTMLTagSupport" ) );
181
182                                 // メソッドのみフィルタリングして取得する
183                                 for( final ExecutableElement ele : ElementFilter.methodsIn(loopEle.getEnclosedElements())) {            // メソッドだけに絞る
184                                         if( !ele.getModifiers().contains( Modifier.PUBLIC ) ) { continue; }                                             // public だけに絞る
185
186                                         final DocCommentTree mdoc = docUtil.getDocCommentTree(ele);             // ドキュメンテーション・コメントが見つからない場合、null が返る。
187                                         if( mdoc == null ) { continue; }
188
189                                         final Map<String,List<String>> blkTagMap2 = blockTagsMap(mdoc);
190                                         final String tags = getBlockTag( OG_TAG_NAME , blkTagMap2, "" );
191
192 //                                      String tags = "";
193 //                                      for( final DocTree dt : mdoc.getBlockTags() ) {
194 //                                              final String tag = String.valueOf(dt);
195 //                                              if( tag.contains( OG_TAG_NAME ) ) { tags = cutTag( tag,OG_TAG_NAME      ); }
196 //                                      }
197
198                                         if( !tags.isEmpty() ) {
199                                                 final String fname = String.valueOf( ele );
200                                                 if( !mtdClsSet.add( fname ) ) { continue; }             // 継承もとに同じメソッド名がある場合は、無視する。
201
202                                                 final String methodName = removeSetter( String.valueOf( ele.getSimpleName() ) );
203
204 //                                              final List<? extends DocTree> ftag      = mdoc.getFirstSentence();
205 //                                              final List<? extends DocTree> mcmnt     = mdoc.getFullBody();
206                                                 final String[] fcmnts = getTitleCmnt( mdoc );                                                   // 8.0.2.1 (2021/12/10)
207
208                                                 final String[] keylblCd = methodLabelCode( mdoc );
209
210 //                                              final List<? extends DocTree> doc1      = mdoc.getPostamble();
211 //                                              final List<? extends DocTree> doc2      = mdoc.getPreamble();
212
213                                                 // 5.7.1.1 (2013/12/13) タグのインデントを止める。
214                                                 writer.printTag( "  <method>" );
215                                                 writer.printTag( "    <name>"           ,methodName     ,"</name>" );
216                                                 writer.printTag( "    <label>"          ,keylblCd[1],"</label>" );              // 6.1.1.0 (2015/01/17)
217                                                 writer.printTag( "    <comment>"        ,keylblCd[2],"</comment>" );    // 6.2.5.0 (2015/06/05)
218                                                 writer.printTag( "    <code>"           ,keylblCd[3],"</code>" );               // 6.1.1.0 (2015/01/17)
219                                                 writer.printTag( "    <htmlExtend>"     ,extendFlag     ,"</htmlExtend>" );
220 //                                              writer.printTag( "    <description>",ftag               ,"</description>" );    // 8.0.2.1 (2021/12/10)
221                                                 writer.printTag( "    <description>",fcmnts[0]  ,"</description>" );
222 //                                              writer.printTag( "    <contents>"       ,mcmnt          ,"" );
223                                                 writer.printTag( "    <contents>"       ,fcmnts[0]      ,"" );                                  // 8.0.2.1 (2021/12/10)
224                                                 writer.printTag( ""                                     ,tags           ,"</contents>" );
225                                                 writer.printTag( "  </method>");
226                                         }
227                                 }
228
229                                 final TypeMirror superType      = loopEle.getSuperclass();
230                                 className = String.valueOf( superType );
231                                 loopEle = null;                                                 // while ループの終了
232                                 if( !TypeKind.NONE.equals( superType.getKind() ) ) {
233                                         for( final TypeElement tp : eleUtil.getAllTypeElements(className) ) {
234                                                 if( className.equals( String.valueOf(tp) ) ) {
235                                                         loopEle = tp ; break;
236                                                 }
237                                         }
238                                 }
239                         }
240                         writer.printTag( "</classDoc>" );
241                 }
242         }
243
244         /**
245          * セッターメソッドの setXXXX の set を削除し、次の文字を小文字化します。
246          * つまり、セッターメソッドから属性値を推測します。
247          * (超特殊処理)セッターメソッドのset以下2文字目が大文字の場合は、
248          * 1文字目も大文字と考えて小文字化を行いません。
249          * 例えば、setSYS や setUSER など、RequestValueTag.javaに使用するケースです。
250          *
251          * @param target 処理対象となる文字列
252          *
253          * @return オプション文字列
254          */
255         private String removeSetter( final String target ) {
256                 if( target != null && target.startsWith( "set" ) ) {
257                         char[] chs = target.toCharArray();
258                         if( chs.length > 4 && !( chs[4] >= 'A' && chs[4] <= 'Z' ) ) {
259                                 chs[3] = Character.toLowerCase( chs[3] ) ;
260                         }
261                         return new String( chs,3,chs.length-3 );
262                 }
263                 return target;
264         }
265
266         /**
267          * MethodDocを受け取り、0:パラメータ、1:ラベル、2:コメント、3:コードを文字列配列に入れて返します。
268          *
269          * これは、タグリブのラベルリソース登録時に使用する情報です。
270          * タグリブのローカルルールとして、0:パラメータ 1:ラベル 2:ラベル以降の解説 3:コード
271          * という記述を行う事を前提にしています。
272          *
273          * 0:パラメータは、引数です。メソッド名ではありませんので、ご注意ください。
274          * 1:ラベルは、パラメータの次の空白文字から、次の空白文字、または、"[" までの文字です。
275          * 2:コメントは、ラベル以降の文字列で、コードの記述部分も含みます。
276          * 3:コード は、特別な処理を行います。"[" と "]" 内に記述された内容を取り出します。
277          *
278          * @og.rev 7.3.0.0 (2021/01/06) 新しいJavaDoc対応
279          *
280          * @param       mdoc DocCommentTreeオブジェクト
281          *
282          * @return      0:パラメータ、1:ラベル、2:コメント、3:コードを文字列配列に詰めた値(長さ4の配列)
283          * @og.rtnNotNull
284          */
285         private String[] methodLabelCode( final DocCommentTree mdoc ) {
286                 final String[] arys = new String[] { "","","","" } ;    // 後で内容を更新する。
287
288                 final Map<String,List<String>> blkTagMap = blockTagsMap(mdoc);
289                 final String prmTag = getBlockTag( DOC_PARAM, blkTagMap, "" );
290
291 //              String prmTag = "";
292 //              for( final DocTree dt : mdoc.getBlockTags() ) {
293 //                      final String tag = String.valueOf(dt);
294 //                      if( tag.contains( DOC_PARAM ) ) {
295 //                              prmTag = cutTag( tag,DOC_PARAM ); break;                // Taglibのsetter は、paramは一つだけのハズ
296 //                      }
297 //              }
298
299                 // 最大3つ と指定しているが、0:パラメータと1:ラベルの2つしか保証されていない。
300                 final String[] temp = prmTag.split( "[\\s]+",3 );               // 空白文字で3つに分解する。
301                 System.arraycopy( temp,0,arys,0,temp.length );                  // 6.3.6.0 (2015/08/16)
302
303                 // 3:コード があれば、2:コメントから取り出す。
304                 final int st1 = arys[2].indexOf( '[' );
305                 if( st1 >= 0 ) {
306                         final int st2 = arys[2].indexOf( ']',st1 );
307                         if( st2 > 0 ) {
308                                 // 前後の [] は、取り除き、'/' があれば、' ' に置換する。(コード文字列化)
309                                 arys[3] = arys[2].substring( st1+1,st2 ).replace( '/' , ' ' );
310                         }
311                 }
312
313                 return arys ;
314         }
315
316         /**
317          * サポートされているすべてのオプションを返します。
318          *
319          * @return サポートされているすべてのオプションを含むセット、存在しない場合は空のセット
320          */
321         @Override
322         public Set<? extends Option> getSupportedOptions() {
323                 final Option[] options = {
324                         new AbstractOption( "-outfile", "-version" ) {
325
326                                 /**
327                                  * 必要に応じてオプションと引数を処理します。
328                                  *
329                                  * @param  opt オプション名
330                                  * @param  arguments 引数をカプセル化したリスト
331                                  * @return 操作が成功した場合はtrue、そうでない場合はfalse
332                                  */
333                                 @Override
334                                 public boolean process(final String opt, final List<String> arguments) {
335                                         if( "-outfile".equalsIgnoreCase(opt) ) {
336                                                 outfile = arguments.get(0);
337                                         }
338                                         else if( "-version".equalsIgnoreCase(opt) ) {
339                                                 version = arguments.get(0);
340                                         }
341                                         return true;
342                                 }
343                         }
344                 };
345                 return new HashSet<>(Arrays.asList(options));
346         }
347 }