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