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    package org.opengion.fukurou.taglet;
017    
018    import org.opengion.fukurou.util.LogWriter;
019    
020    import java.util.Set;
021    import java.util.HashSet;
022    import java.io.IOException;
023    import java.lang.reflect.Field;
024    
025    import com.sun.javadoc.RootDoc;
026    import com.sun.javadoc.ClassDoc;
027    import com.sun.javadoc.MethodDoc;
028    import com.sun.javadoc.FieldDoc;
029    import com.sun.javadoc.Doc;
030    import com.sun.javadoc.ConstructorDoc;
031    import com.sun.javadoc.ExecutableMemberDoc;
032    import com.sun.javadoc.Type;
033    import com.sun.javadoc.Parameter;
034    import com.sun.javadoc.Tag;
035    import com.sun.javadoc.SourcePosition;
036    import com.sun.javadoc.AnnotationDesc;
037    import com.sun.javadoc.AnnotationTypeDoc;
038    
039    /**
040     * ソースコメントから?タグ??を取り??Doclet クラスです?
041     * クラスファイルの仕様を表現する為、og.formSample , og.rev , og.group ,
042     * version , author , since の?グコメントより?を抽出します?
043     * また??ラスの継承関係?インターフェース、メソ?なども抽出します?
044     * これら?抽出結果をDB化し、EXCELファイルに帳票出力する事で、クラスファイルの
045     * ソースから仕様書を?作?します?
046     *
047     * @version  4.0
048     * @author   Kazuhiko Hasegawa
049     * @since    JDK5.0,
050     */
051    public final class DocletSpecific {
052            private static final String  SELECT_PACKAGE     = "org.opengion" ;
053            private static final boolean NOT_PRIVATE        = false ;
054            private static final String  ENCODE                     = "UTF-8";
055    
056            private static final String     OG_FOR_SMPL             = "og.formSample";
057            private static final String     OG_REV                  = "og.rev";
058            private static final String     OG_GROUP                = "og.group";
059            private static final String     DOC_VERSION             = "version";
060            private static final String     DOC_AUTHOR              = "author";
061            private static final String     DOC_SINCE               = "since";
062    
063            private static final String     DOC_PARAM               = "param";              // 5.1.9.0 (2010/08/01) チェ?用
064            private static final String     DOC_RETURN              = "return";             // 5.1.9.0 (2010/08/01) チェ?用
065    
066            private static final String     CONSTRUCTOR             = "コンストラクタ" ;
067            private static final String     METHOD                  = "メソ?" ;
068            private static final Set<String> methodSet        = new HashSet<String>();
069    
070            private static       int        debugLevel              = 0;    // 0:な? 1:?チェ?  2:日本語化   3:体?
071    
072            /**
073             * すべて?staticメソ?なので、コンストラクタを呼び出さなくしておきます?
074             *
075             */
076            private DocletSpecific() {}
077    
078            /**
079             * Doclet のエントリポイントメソ?です?
080             *
081             * @og.rev 5.5.4.1 (2012/07/06) Tag出力時の CR ?BR 変換を行わな?にする?
082             * @og.rev 5.7.1.1 (2013/12/13) タグのイン?トを止める?
083             *
084             * @param       root    エントリポイント?RootDocオブジェク?
085             *
086             * @return 正常実行時 true
087             */
088            public static boolean start( final RootDoc root ) {
089                    String version  = DocletUtil.getOption( "-version" , root.options() );
090                    String file             = DocletUtil.getOption( "-outfile" , root.options() );
091                    String dbgLvl   = DocletUtil.getOption( "-debugLevel" , root.options() );               // 5.5.4.1 (2012/07/06) パラメータ引数
092                    if( dbgLvl != null ) { debugLevel = Integer.parseInt( dbgLvl ); }
093    
094                    DocletTagWriter writer = null;
095                    try {
096    //                      writer = new DocletTagWriter( file,ENCODE,true );
097                            writer = new DocletTagWriter( file,ENCODE );            // 5.5.4.1 (2012/07/06)
098    
099                            // 5.7.1.1 (2013/12/13) タグのイン?トを止める?
100                            writer.printTag( "<?xml version=\"1.0\" encoding=\"", ENCODE, "\" ?>" );
101                            writer.printTag( "<javadoc>" );
102                            writer.printTag(   "<version>",version,"</version>" );
103                            writer.printTag(   "<description></description>" );
104                            writeContents( root.classes(),writer );
105                            writer.printTag( "</javadoc>" );
106                    }
107                    catch( IOException ex ) {
108                            LogWriter.log( ex );
109                    }
110                    finally {
111                            if( writer != null ) { writer.close(); }
112                    }
113                    return true;
114            }
115    
116            /**
117             * ClassDoc 配?よりコン??作?します?
118             *
119             * @og.rev 5.5.4.1 (2012/07/06) コメント???でなく?Tag配?として処?せる?
120             * @og.rev 5.6.6.0 (2013/07/05) VERSION staticフィールドと、@og.rev コメント?比?ェ?
121             * @og.rev 5.7.1.1 (2013/12/13) タグのイン?トを止める?
122             *
123             * @param classes       ClassDoc配?
124             * @param writer        Tagを書き?すWriterオブジェク?
125             */
126            private static void writeContents( final ClassDoc[] classes,final DocletTagWriter writer ) {
127                    for(int i=0; i< classes.length; i++) {
128                            ClassDoc classDoc       = classes[i] ;
129                            String className        = classDoc.name();
130                            String fullName         = classDoc.qualifiedName() ;
131                            String modifiers        = (classDoc.modifiers()
132                                                                    + ( classDoc.isClass() ? " class" : "" ) ).trim();
133    
134                            Type superType = classDoc.superclassType();
135                            String superClass = ( superType == null ) ? "" : superType.qualifiedTypeName();
136    
137                            Type[] interfaceTypes = classDoc.interfaceTypes();
138                            StringBuilder buf = new StringBuilder( 200 );
139                            for( int j=0; j<interfaceTypes.length; j++ ) {
140                                    buf.append( interfaceTypes[j].qualifiedTypeName() ).append( "," );
141                            }
142                            if( interfaceTypes.length > 0 ) { buf.deleteCharAt( buf.length()-1 ); }
143                            String intFase = buf.toString();
144    
145                            Tag[] desc = classDoc.firstSentenceTags();
146    //                      String cmnt = DocletUtil.htmlFilter( classDoc.commentText() );                  // 5.5.4.1 (2012/07/06)
147                            Tag[] cmnt = classDoc.inlineTags();                                                                     // 5.5.4.1 (2012/07/06)
148                            Tag[] smplTags  = classDoc.tags(OG_FOR_SMPL);
149                            Tag[] revTags   = classDoc.tags(OG_REV);
150                            Tag[] createVer = classDoc.tags(DOC_VERSION);
151                            Tag[] author    = classDoc.tags(DOC_AUTHOR);
152                            Tag[] since             = classDoc.tags(DOC_SINCE);
153                            Tag[] grpTags   = classDoc.tags(OG_GROUP);
154    
155                            // 5.7.1.1 (2013/12/13) タグのイン?トを止める?
156                            writer.printTag( "<classDoc>" );
157                            writer.printTag(   "<fullName>"           ,fullName               ,"</fullName>"            );
158                            writer.printTag(   "<modifiers>"  ,modifiers              ,"</modifiers>"           );
159                            writer.printTag(   "<className>"  ,className              ,"</className>"           );
160                            writer.printTag(   "<superClass>" ,superClass             ,"</superClass>"  );
161                            writer.printTag(   "<interface>"  ,intFase                ,"</interface>"           );
162                            writer.printTag(   "<createVer>"  ,createVer              ,"</createVer>"           );
163                            writer.printTag(   "<author>"             ,author                 ,"</author>"              );
164                            writer.printTag(   "<since>"              ,since                  ,"</since>"                       );
165                            writer.printTag(   "<description>"        ,desc                   ,"</description>" );
166                            writer.printTag(   "<contents>"           ,cmnt                   ,"</contents>"            );
167                            writer.printTag(   "<classGroup>" );
168                            writer.printCSVTag(             grpTags         );
169                            writer.printTag(   "</classGroup>"        );
170                            writer.printTag(   "<formSample>" ,smplTags               ,"</formSample>"  );
171                            writer.printTag(   "<history>"            ,revTags                ,"</history>"             );
172    
173                            // 5.1.9.0 (2010/08/01) ソースチェ?用(コメントや概要が無??合?スーパ?クラスは省く)
174    //                      if( ( cmnt.length() == 0 || desc.length == 0 ) && superClass.length() == 0 ) {
175                            if( debugLevel >= 2 && ( cmnt.length == 0 || desc.length == 0 ) && superClass.length() == 0 ) {
176                                    System.err.println( "警?:コメン?=\t" + classDoc.position() );
177                            }
178    
179    //                      methodSet.clear();              // 5.5.4.1 (2012/07/06) メソ?の重???定?、クラス名も含めて行うので、clear() しな??
180                            int extendFlag = 0;             // 0:オリジナル 1:org.opengion関連Extend 2:Java関連Extend
181            //              while( fullName.startsWith( SELECT_PACKAGE ) ) {
182    
183                            // 5.6.6.0 (2013/07/05) VERSION staticフィールドと、@og.rev コメント?比?ェ?
184                            // while 以下で、fullName と classDoc を?番に上にさかのぼって?ので、?にチェ?します?
185                            checkTag2( fullName,classDoc );
186    
187                            while( true ) {
188    //                              ConstructorDoc[] cnstrctrs = classDoc.constructors();
189                                    ConstructorDoc[] cnstrctrs = classDoc.constructors( false );    // 5.1.9.0 (2010/08/01) チェ?用
190                                    for(int j=0; j < cnstrctrs.length; j++) {
191                                            if( isAction( cnstrctrs[j],extendFlag ) ) {
192                                                    if( extendFlag < 2 ) { checkTag( cnstrctrs[j] ); }           // 5.5.4.1 (2012/07/06)  チェ?を?離
193                                                    menberTag( cnstrctrs[j],CONSTRUCTOR,writer,extendFlag );
194                                            }
195                                    }
196    
197    //                              MethodDoc[] methods = classDoc.methods();
198                                    MethodDoc[] methods = classDoc.methods( false );        // 5.1.9.0 (2010/08/01) チェ?用
199                                    for(int j=0; j < methods.length; j++) {
200                                            if( isAction( methods[j],extendFlag ) ) {
201                                                    if( extendFlag < 2 ) { checkTag( methods[j] ); }             // 5.5.4.1 (2012/07/06)  チェ?を?離
202                                                    menberTag( methods[j],METHOD,writer,extendFlag );
203                                            }
204                                    }
205    
206                                    // 対象クラス(オリジナル)から、上に上がって??
207                                    Type type = classDoc.superclassType();
208                                    if( type == null ) { break; }
209                                    classDoc  = type.asClassDoc() ;
210                                    fullName = classDoc.qualifiedName();
211                                    // java.lang.Object クラスは対象が多いため、??ません?
212                                    if( "java.lang.Object".equals( fullName ) || classDoc.isEnum() ) {
213                                            break;
214                                    }
215                                    else if( fullName.startsWith( SELECT_PACKAGE ) ) {
216                                            extendFlag = 1;
217                                    }
218                                    else {
219                                            extendFlag = 2;
220                                    }
221                            }
222    
223                            writer.printTag( "  </classDoc>" );
224                    }
225            }
226    
227            /**
228             * メンバ?クラスのXML化を行うかど?[true/false]を判定します?
229             *
230             * 以下?条件に合?する場合?、??行いません?false を返します?)
231             *
232             * ?.同?ラスを??にEXTENDで継承?さかのぼる?合?すでに同じシグネチャのメソ??
233             *     存在して??
234             * ?.NOT_PRIVATE ?true の時? private メソ?
235             * ?.extendFlag ?0以?1,2)の時? private メソ?
236             * ?.メソ?名におかしな記号(&lt;など)が含まれて?場?
237             *
238             * @og.rev  5.5.4.1 (2012/07/06) メソ?の重???定?、クラス名も含めて行う
239             *
240             * @param       menber ExecutableMemberDocオブジェク?
241             * @param       extendFlag      0:オリジナル 1:org.opengion関連Extend 2:Java関連Extend
242             *
243             * @return      XML化を行うかど?[true/false]
244             */
245            private static boolean isAction( final ExecutableMemberDoc menber,final int extendFlag ) {
246                    String menberName = menber.name() ;
247    //              String signature  = menberName + menber.signature();
248    //              boolean rtn =   ( ! methodSet.add( signature ) )
249                    boolean rtn =   ( ! methodSet.add( menber.toString() ) )        // 5.5.4.1 (2012/07/06) メソ?の重???定?、クラス名も含めて行う
250                                            ||      ( NOT_PRIVATE    && menber.isPrivate() )
251                                            ||      ( extendFlag > 0 && menber.isPrivate() )
252                                            ||      ( menberName.charAt(0) == '<' ) ;
253    
254                    return ! rtn ;
255            }
256    
257            // 5.1.9.0 (2010/08/01) ソースチェ?用(半角文字+空白??み)
258            private static java.util.regex.Pattern PTN = java.util.regex.Pattern.compile("[\\w\\s]+");
259    
260            /**
261             * param,return 等?整合?をチェ?します?
262             *
263             * @og.rev 5.5.4.1 (2012/07/06) 新規作??
264             * @og.rev 5.6.6.1 (2013/07/12) Deprecated アノテーション のチェ?
265             *
266             * @param menber ExecutableMemberDocオブジェク?
267             */
268            private static void checkTag( final ExecutableMemberDoc menber ) {
269    
270                    // 親?Enum クラスの場合?処?ません?
271                    Type prntType = menber.containingClass().superclassType();
272                    String prntClass = ( prntType == null ) ? "" : prntType.qualifiedTypeName();
273                    if( "java.lang.Enum".equals( prntClass ) ) { return; }
274    
275                    SourcePosition posi = menber.position();
276                    String modifiers = null;
277    
278                    if( menber instanceof MethodDoc ) {
279                            // メソ?の処?コンストラクターを省?
280                            Type    rtnType = ((MethodDoc)menber).returnType();
281                            String  typNm   = rtnType.typeName();
282    
283                            StringBuilder modifyBuf = new StringBuilder( 200 );
284                            modifyBuf.append( menber.modifiers() ).append( " " ).append( typNm );
285                            if( rtnType.dimension() != null ) { modifyBuf.append( rtnType.dimension() ); }
286                            modifiers = modifyBuf.toString();
287    
288                            String wormMsg = "=\t" + posi + "\t" + modifiers ;
289    
290                            // 5.1.9.0 (2010/08/01) ソースチェ?用(@return との整合?チェ?)
291                            Tag[] docReturn = menber.tags(DOC_RETURN);              // 5.1.9.0 (2010/08/01) チェ?用
292                            if( docReturn.length > 0 ) {
293                                    String data = (docReturn[0].text()).trim();                     // 5.5.4.1 (2012/07/06) trim でスペ?ス等?削除
294                                    wormMsg = wormMsg + "\t" + data ;
295    
296                                    // 5.5.4.1 (2012/07/06) ソースチェ?用(@return と引数の個数が異なる??
297                                    if( debugLevel >= 1 && "void".equals( typNm ) ) {
298                                            System.err.println( "警?:RTNコメント不? + wormMsg );
299                                    }
300                                    // ?@return 解説? の形式で、解説に日本語がなければ、警?
301    //                              if( debugLevel >= 2 && PTN.matcher( data ).matches() && data.indexOf( ' ' ) < 0 && data.indexOf( '\t' ) < 0 ) {
302                                    if( debugLevel >= 2 && PTN.matcher( data ).matches() ) {
303                                            System.err.println( "警?:RTN未解説" + wormMsg );
304                                    }
305                                    // ?@return    String? の形式?場合?警?
306                                    if( debugLevel >= 2 && data.equals( typNm ) ) {
307                                            System.err.println( "警?:RTN??" + wormMsg );
308                                    }
309                                    // ?@return    String[]? など??列や?String>などが含まれる場合?警?
310                                    if( debugLevel >= 2 && ( data.indexOf( "[]" ) >= 0 || data.indexOf( '<' ) >= 0 ) ) {
311                                            System.err.println( "警?:RTN配?" + wormMsg );
312                                    }
313                                    // ?@return    String 解説? の場合?警?後ろにスペ?スか?タブがある場?
314                                    if( debugLevel >= 3 && (data.indexOf( typNm + " " ) >= 0 || data.indexOf( typNm + "\t" ) >= 0 ) ) {
315                                            System.err.println( "警?:RTNタイ? + wormMsg );
316                                    }
317                                    // ?@return    xxxx 解説? の場合で、最初?スペ?スまでが?すべて英数字?みの場合?警?
318                                    int adrs1 = data.indexOf( ' ' );
319                                    if( debugLevel >= 3 && adrs1 > 0 ) {
320                                            boolean flag = true;
321                                            for( int j=0; j<adrs1; j++ ) {
322                                                    char ch = data.charAt( j );
323                                                    if( ( ch < '0' || ch > '9' ) && ( ch < 'a' || ch > 'z' ) && ( ch < 'A' || ch > 'Z' )  && ch != '[' && ch != ']' ) {
324                                                            flag = false;   // 英数字でな?号が現れた場?
325                                                            break;
326                                                    }
327                                            }
328                                            if( flag ) {    // すべてが英数字?場合??
329                                                    System.err.println( "警?:RTN値" + wormMsg );
330                                            }
331                                    }
332                            }
333                            else {  // Tag上には、@return 記述が存在しな??
334                                    // 5.5.4.1 (2012/07/06) ソースチェ?用(@return と引数の個数が異なる??
335                                    if( debugLevel >= 1 && !"void".equals( typNm ) ) {
336                                            System.err.println( "警?:RTNコメントな? + wormMsg );
337                                    }
338                            }
339    
340                            // オーバ?ライドチェ??アノテーションの記述漏れ
341                            // そ???、コンパイラが警告してくれる?
342                            MethodDoc mdoc= ((MethodDoc)menber).overriddenMethod();
343                            if( debugLevel >= 3 && mdoc != null ) {
344                                    AnnotationDesc[] annotations = menber.annotations();
345                                    // 本来は、Override の有無を調べるべきだが?Deprecated と SuppressWarnings の付いて?
346                                    // 旧のメソ?に、いち?Overrideを付けな??で、何もなければと条件を緩めます?
347                                    if( annotations.length == 0 ) {
348                                            System.err.println( "警?:@Overrideな? + wormMsg );
349                                    }
350                            }
351                    }
352    
353                    Parameter[] prm = menber.parameters();
354    
355                    // 5.1.9.0 (2010/08/01) ソースチェ?用(@param と引数の個数が異なる??
356                    Tag[] docParam  = menber.tags(DOC_PARAM);               // 5.1.9.0 (2010/08/01) チェ?用
357                    if( debugLevel >= 1 && docParam.length != prm.length ) {
358                            System.err.println( "警?:PRM個数違い=\t" + posi );
359                    }
360    
361                    for( int k=0; k<prm.length; k++ ) {
362                            String typNm = prm[k].type().typeName();
363                            String prmNm = prm[k].name();
364    
365                            // 5.1.9.0 (2010/08/01) ソースチェ?用(@param と引数の個数が異なる??
366                            if( docParam.length > k ) {
367                                    String data  = (docParam[k].text()).trim();                     // 5.5.4.1 (2012/07/06) trim でスペ?ス等?削除
368                                    String data2 = data.replaceAll( prmNm,"" ).trim();
369                                    String data3 = data2.replaceAll( typNm,"" ).replaceAll( "\\[\\]","" ).trim();
370                                    String wormMsg = "=\t" + posi + "\t" + data ;
371    
372                                    // ?@param     aaa     解説?形式で、aaa(引数?がな???
373                                    if( debugLevel >= 1 && data.indexOf( prmNm ) < 0 ) {
374                                            System.err.println( "警?:PRM引数? + wormMsg );
375                                    }
376                                    // 引数の??の長さが?文字?場?
377                                    if( debugLevel >= 2 && prmNm.length() == 1 ) {
378                                            System.err.println( "警?:PRM短? + wormMsg );
379                                    }
380                                    // ?@param     aaa     解説?形式で、解説に日本語がな??また?、解説がなければ、警?
381    //                              if( debugLevel >= 2 && PTN.matcher( data ).matches() && data.indexOf( ' ' ) < 0 && data.indexOf( '\t' ) < 0 ) {
382                                    if( debugLevel >= 2 && ( PTN.matcher( data2 ).matches() || data3.length() == 0 ) ) {
383                                            System.err.println( "警?:PRM未解説" + wormMsg );
384                                    }
385                                    // ?@param     aaa     String[]?など??列や?String>などが含まれる場合?警?
386                                    if( debugLevel >= 2 && ( data.indexOf( "[]" ) >= 0 || data.indexOf( '<' ) >= 0 ) ) {
387                                            System.err.println( "警?:PRM配?" + wormMsg );
388                                    }
389                                    // ?@param     aaa     解説?形式で、String が有って、その後ろにスペ?スか?タブがあれば警?
390                                    // data2 を使??は、パラメータ?xxxMap)にタイプ名(Map)が含まれて?ケースの対?
391                                    if( debugLevel >= 3 && (data2.indexOf( typNm + " " ) >= 0 || data2.indexOf( typNm + "\t" ) >= 0 ) ) {
392                                            System.err.println( "警?:PRMタイ? + wormMsg );
393                                    }
394                                    // ?@param     aaa     解説?形式で、解説がな???
395    //                              if( debugLevel >= 3 && data3.length() == 0 ) {
396    //                                      System.err.println( "警?:PRM解説な? + wormMsg );
397    //                              }
398                            }
399                    }
400    
401                    Tag[]   desc    = menber.firstSentenceTags();
402                    Tag[]   cmnt    = menber.inlineTags();                                                                  // 5.5.4.1 (2012/07/06)
403    //              String  extClass = ( extendFlag == 0 ) ? "" : menber.containingClass().qualifiedName() ;
404    
405                    // 5.1.9.0 (2010/08/01) ソースチェ?用
406                    if( ( cmnt.length == 0 || desc.length == 0 )            // コメントや概要が無?
407    //                              && extClass.length() == 0                                       // 拡張クラスが存在しな?
408                                    && ( menber instanceof MethodDoc )                      // メソ?に限?
409                                    && !menber.isSynthetic()                                        // コンパイラによって合?されて??
410                                    && !menber.isNative()                                           // ネイ?ブメソ?でな?
411                                    && debugLevel >= 2 ) {                                               // debugLevel ?2 以?
412    
413                            // さらに、親?Enum クラス以?
414    //                      Type prntType = menber.containingClass().superclassType();
415    //                      String prntClass = ( prntType == null ) ? "" : prntType.qualifiedTypeName();
416    //                      if( debugLevel >= 2 && !"java.lang.Enum".equals( prntClass ) ) {
417                                    System.err.println( "警?:コメン?=" + "\t" + posi + "\t" + menber.name() );
418    //                      }
419                    }
420    
421                    // 5.6.6.1 (2013/07/12) Deprecated アノテーション のチェ?
422                    AnnotationDesc[] descList = menber.annotations();
423                    for( int i=0; i<descList.length; i++ ) {
424                            AnnotationTypeDoc annDoc = descList[i].annotationType();
425                            if( "Deprecated".equalsIgnoreCase( annDoc.name() ) ) {
426                                    String text = menber.commentText();
427                                    if( text != null && text.indexOf( "【?? ) < 0 ) {
428                                            System.err.println( "警?:【??" + "\t" + posi + "\t" + menber.name() );
429                                    }
430                            }
431                    }
432            }
433    
434            /**
435             * VERSION staticフィールドと、@og.rev コメント?比?ェ?を行います?
436             * エンジン?では、serialVersionUID は、この、VERSION を?に作?して?ため?
437             * そ?値もチェ?します?
438             *
439             * @og.rev 5.6.6.0 (2013/07/05) 新規作?
440             * @og.rev 5.7.1.1 (2013/12/13) VERSION の値を?Class.forName ではなく?FieldDoc から取得する?
441             *
442             * @param fullName オリジナルのクラス?
443             * @param classDoc ClassDocオブジェク?
444             */
445            private static void checkTag2( final String fullName, final ClassDoc classDoc ) {
446    //              String cnstVar = getFieldVERSION( fullName ) ;                          // VERSION ??    ?5.6.6.0 (2013/07/05)
447    //              String seriUID = getSerialVersionUID( fullName ) ;                      // serialVersionUID  ?566020130705L
448    
449                    FieldDoc cnstVarFld = findFieldDoc( classDoc , "VERSION" ) ;                            // VERSION ??    ?5.6.6.0 (2013/07/05)
450    
451                    // VERSION ?? か?serialVersionUID のどちらかがあれ?処?ます?
452    //              if( cnstVar != null || seriUID != null ) {
453                    if( cnstVarFld != null ) {                                                      // 5.7.1.1 (2013/12/13) cnstVarFid のみ初めにチェ?
454                            String cnstVar = cnstVarFld.constantValueExpression() ;
455                            if( cnstVar != null ) {
456                                    if( cnstVar.length() > 1 && 
457                                            cnstVar.charAt(0) == '"' && cnstVar.charAt(cnstVar.length()-1) == '"' ) {
458                                                    cnstVar = cnstVar.substring( 1,cnstVar.length()-1 );
459                                    }
460                            }
461                            else {
462                                    cnstVar = "0.0.0.0 (0000/00/00)";               // 初期値
463                            }
464    
465    //                      SourcePosition posi = null;
466    
467    //                      String maxRev = ( cnstVar != null ) ? cnstVar : "4.0.0.0 (2005/01/31)" ;                // Ver4 の?古?
468                            String maxRev = cnstVar ;               // 5.7.1.1 (2013/12/13) 初期値
469                            int    lenVar = maxRev.length();                                        // 比?に使用する長?
470                            boolean isChange = false;                                                       // max が?れ替わったら、true
471    
472                            // 本体?コンストラクタ、フィールド?メソ??ら??の @og.rev の値を取得します?
473                            Doc[][] docs = new Doc[4][] ;
474    
475                            docs[0] = new Doc[] { classDoc } ;
476                            docs[1] = classDoc.constructors( false ) ;
477                            docs[2] = classDoc.fields( false ) ;
478                            docs[3] = classDoc.methods( false ) ;
479    
480                            for( int i=0; i<docs.length; i++ ) {
481                                    for( int j=0; j < docs[i].length; j++ ) {
482                                            Doc doc = docs[i][j];
483    
484                                            Tag[] revTags = doc.tags(OG_REV);
485                                            for( int k=0 ; k<revTags.length; k++ ) {
486                                                    String rev = revTags[k].text();
487    
488                                                    if( rev.length() < lenVar ) {
489                                                            System.err.println( "警?:og.revが短?" + "\t" + rev + "\t" + doc.position() );
490                                                            continue;
491                                                    }
492    
493                                                    rev = rev.substring( 0,lenVar );
494    
495                                                    if( maxRev.compareTo( rev ) < 0 ) {                  // revTags の og.rev が大きい場?
496                                                            maxRev = rev ;
497                                                    //      posi   = doc.position();                                // ?に入れ替わった位置 = ?のrevの位置
498                                                            isChange = true;
499                                                    }
500                                            }
501                                    }
502                            }
503    
504                            // VERSION ?? の定義があり?かつ、max の入れ替えが発生した?合?み、警?:VERSIONが古?
505    //                      if( cnstVar != null && isChange ) {
506                            if( isChange ) {                        // 5.7.1.1 (2013/12/13) 入れ替えが発生した??
507    //                              // 以下?処??、VERSION のソースの位置(posi)を取り?すためだけに使用して?す?
508    //                              FieldDoc[] fileds = classDoc.fields( false );
509    //                              for( int i=0; i<fileds.length; i++ ) {
510    //                                      FieldDoc filed = fileds[i];
511    //                                      // private static final String VERSION で宣?れて?ので?
512    //                                      if( filed.isPrivate() && filed.isStatic() && filed.isFinal() ) {
513    //                                              String nm = filed.qualifiedName();
514    //
515    //                                              if( nm.endsWith( "VERSION" ) ) {
516    //                                                      posi = filed.position();
517    //                                                      break;
518    //                                              }
519    //                                      }
520    //                              }
521    //                              System.err.println( "警?:VERSIONが古?" + "\t" + cnstVar + " ?" + maxRev + "\t" + posi );
522                                    System.err.println( "警?:VERSIONが古?" + "\t" + cnstVar + " ?" + maxRev + "\t" + cnstVarFld.position() );
523                            }
524    
525                            // serialVersionUID の定義がある?
526                            FieldDoc seriUIDFld = findFieldDoc( classDoc , "serialVersionUID" ) ;           // serialVersionUID  ?566020130705L
527    //                      if( seriUID != null ) {
528                            if( seriUIDFld != null ) {              // 5.7.1.1 (2013/12/13)
529                                    StringBuilder buf = new StringBuilder();
530                                    // maxRev は、最大の Revか?初期のVERSION?? ?5.6.6.0 (2013/07/05)
531                                    for( int i=0; i<maxRev.length(); i++ ) {     // 
532                                            char ch = maxRev.charAt( i );
533                                            if( ch >= '0' && ch <= '9' ) { buf.append( ch ); }        // 数字だけ取り?す? ?566020130705
534                                    }
535                                    buf.append( 'L' );      // 強制?、L を追?る?
536                                    String maxSeriUID = buf.toString() ;
537    
538                                    // 5.7.1.1 (2013/12/13) 値の取?し?Long型を表?"L" も含まれて??
539                                    String seriUID = seriUIDFld.constantValueExpression() ;
540                                    if( !maxSeriUID.equals( seriUID ) ) {   // ??しな?
541    //                              if( !seriUID.equals( buf.toString() ) ) {
542    //                                      // 以下?処??、serialVersionUID のソースの位置(posi)を取り?すためだけに使用して?す?
543    //                                      FieldDoc[] fileds = classDoc.fields( false );
544    //                                      for( int i=0; i<fileds.length; i++ ) {
545    //                                              FieldDoc filed = fileds[i];
546    //                                              // private static final long serialVersionUID で宣?れて?ので?
547    //                                              if( filed.isPrivate() && filed.isStatic() && filed.isFinal() ) {
548    //                                                      String nm = filed.qualifiedName();
549    //                                                      if( nm.endsWith( "serialVersionUID" ) ) {
550    //                                      //                      String val = filed.constantValueExpression();   // これは、serialVersionUID の設定?の取得サンプル
551    //                                                              posi = filed.position();
552    //                                                              break;
553    //                                                      }
554    //                                              }
555    //                                      }
556    //                                      System.err.println( "警?:serialVersionUIDが古?" + "\t" + seriUID + " ?" + buf.toString() + "L\t" + posi );
557                                            System.err.println( "警?:serialVersionUIDが古?" + "\t" + seriUID + " ?" + maxSeriUID + "\t" + seriUIDFld.position() );
558                                    }
559                            }
560                    }
561            }
562    
563            /**
564             * メンバ?クラス(コンストラクタ、メソ?)をXML化します?
565             *
566             * @og.rev 5.5.4.1 (2012/07/06) コメント???でなく?Tag配?として処?せる?
567             *
568             * @param       menber          ExecutableMemberDocオブジェク?
569             * @param       menberType      メンバ?タイ?コンストラクタ、メソ?)
570             * @param       writer          Tagを書き?すWriterオブジェク?
571             * @param       extendFlag      0:オリジナル 1::org.opengion関連Extend 2:Java関連Extend
572             */
573            private static void menberTag(  final ExecutableMemberDoc menber,
574                                                                            final String menberType,
575                                                                            final DocletTagWriter writer,
576                                                                            final int extendFlag ) {
577    
578                    final String modifiers ;
579                    if( menber instanceof MethodDoc ) {
580                            // メソ?の処?
581                            Type rtnType = ((MethodDoc)menber).returnType();
582                            StringBuilder modifyBuf = new StringBuilder( 200 );
583                            modifyBuf.append( menber.modifiers() );
584            //              modifyBuf.append( " " ).append( rtnType.qualifiedTypeName() );
585                            modifyBuf.append( " " ).append( rtnType.typeName() );
586                            if( rtnType.dimension() != null ) { modifyBuf.append( rtnType.dimension() ); }
587    
588                            modifiers = modifyBuf.toString();
589                    }
590                    else {
591                            // コンストラクター処?
592                            modifiers  = menber.modifiers();
593                    }
594    
595                    String menberName = menber.name();
596    
597                    StringBuilder sigBuf = new StringBuilder( 200 );
598                    sigBuf.append( menberName ).append( "(" ) ;
599                    Parameter[] prm = menber.parameters();
600    
601                    for( int k=0; k<prm.length; k++ ) {
602    //                      sigBuf.append( prm[k].toString() ).append( "," );
603                            Type ptyp = prm[k].type();
604                            String prmNm =prm[k].name();
605    
606                            sigBuf.append( ptyp.typeName() ).append( ptyp.dimension() ).append( " " )
607                                            .append( prmNm ).append( "," );
608                    }
609    
610                    if( prm.length > 0 ) { sigBuf.deleteCharAt( sigBuf.length()-1 ); }
611                    sigBuf.append( ")" );
612                    String signature = sigBuf.toString();
613    
614                    Tag[]   desc    = menber.firstSentenceTags();
615    //              String  cmnt    = DocletUtil.htmlFilter( menber.commentText() );                // 5.5.4.1 (2012/07/06)
616                    Tag[]   cmnt    = menber.inlineTags();                                                                  // 5.5.4.1 (2012/07/06)
617                    Tag[]   tags    = menber.tags();
618                    Tag[]   revTags = menber.tags(OG_REV);
619                    String  extend  = String.valueOf( extendFlag );
620                    String  extClass = ( extendFlag == 0 ) ? "" : menber.containingClass().qualifiedName() ;
621    
622                    String  position = String.valueOf( menber.position().line() );
623    
624                    writer.printTag( "  <menber>" );
625                    writer.printTag( "    <type>"             ,menberType     ,"</type>"                        );
626                    writer.printTag( "    <name>"             ,menberName     ,"</name>"                        );
627                    writer.printTag( "    <modifiers>"        ,modifiers      ,"</modifiers>"           );
628                    writer.printTag( "    <signature>"        ,signature      ,"</signature>"           );
629                    writer.printTag( "    <position>" ,position       ,"</position>"            );
630                    writer.printTag( "    <extendClass>",extClass     ,"</extendClass>" );
631                    writer.printTag( "    <extendFlag>"       ,extend         ,"</extendFlag>"  );
632                    writer.printTag( "    <description>",desc         ,"</description>" );
633                    writer.printTag( "    <contents>" ,cmnt           ,"</contents>"            );
634                    writer.printTag( "    <tagText>" );
635                    writer.printTagsInfo(   tags );
636                    writer.printTag( "    </tagText>" );
637                    writer.printTag( "    <history>"  ,revTags        ,"</history>" );
638                    writer.printTag( "  </menber>");
639            }
640    
641            /**
642             * ??オブジェクト?  VERSION と、serialVersionUID staticフィールド?値を取得します?
643             *
644             * 結果は、文字?配?にして返します?
645             * どちらもなければ、null, どちらかあれば、文字?配?にして、?目は、VERSION。2つめ?、serialVersionUID ?
646             * ??にした値を返します?
647             *
648             * こ?メソ?のオリジナルは、org.opengion.hayabusa.servlet.HybsAdmin の private ?クラス ClassInfo にあります?
649             * 汎用性がな?、ソースのコピ????ーストで持ってきて?す??若干、修正もして?す?
650             *
651             * @og.rev 5.6.6.0 (2013/07/05) 新規作?
652             * @og.rev 5.7.1.1 (2013/12/13) ? ?findFieldDoc に変更
653             *
654             * @param       clsName ??クラスを表す名称
655             * @return      VERSION??( staticフィールド?値 ) と、serialVersionUIDを文字?にした値を含???
656             */
657    //      private static String getFieldVERSION( final String clsName ) {
658    //              String rtn ;
659    //
660    //              try {
661    //                      Class<?> cls = Class.forName( clsName ) ;
662    //                      Field fld = cls.getDeclaredField( "VERSION" ) ;
663    //
664    //                      // privateフィールド?取得には、accessibleフラグ?trueにする?があります?
665    //                      fld.setAccessible( true );
666    //                      rtn = (String)fld.get( null );
667    //              }
668    //              catch( Throwable ex ) {
669    //                      rtn = null;
670    //              }
671    //              return rtn ;
672    //      }
673    
674            /**
675             * ??オブジェクト?  VERSION と、serialVersionUID staticフィールド?値を取得します?
676             *
677             * 結果は、文字?配?にして返します?
678             * どちらもなければ、null, どちらかあれば、文字?配?にして、?目は、VERSION。2つめ?、serialVersionUID ?
679             * ??にした値を返します?
680             *
681             * こ?メソ?のオリジナルは、org.opengion.hayabusa.servlet.HybsAdmin の private ?クラス ClassInfo にあります?
682             * 汎用性がな?、ソースのコピ????ーストで持ってきて?す??若干、修正もして?す?
683             *
684             * @og.rev 5.6.6.0 (2013/07/05) 新規作?
685             * @og.rev 5.7.1.1 (2013/12/13) ? ?findFieldDoc に変更
686             *
687             * @param       clsName ??クラスを表す名称
688             * @return      VERSION??( staticフィールド?値 ) と、serialVersionUIDを文字?にした値を含???
689             */
690    //      private static String getSerialVersionUID( final String clsName ) {
691    //              String rtn ;
692    //
693    //              try {
694    //                      Class<?> cls = Class.forName( clsName );
695    //                      Field fld = cls.getDeclaredField( "serialVersionUID" ) ;
696    //                      // privateフィールド?取得には、accessibleフラグ?trueにする?があります?
697    //                      fld.setAccessible( true );
698    //                      rtn = String.valueOf( (Long)fld.get( null ) );
699    //              }
700    //              catch( Throwable ex ) {
701    //                      rtn = null;
702    //              }
703    //              return rtn ;
704    //      }
705    
706            /**
707             * ??キーの  FieldDoc オブジェクトを、ClassDoc から見つけて返します?
708             *
709             * キー??は、大??小文字?区別なく???に見つかった?フィールド名の 
710             * FieldDoc オブジェクトを見つけます?
711             * ??は、ループを回して検索して?す?で?効?す?
712             * 見つからな??合?、null を返します?
713             *
714             * @og.rev 5.7.1.1 (2013/12/13) 新規作?
715             *
716             * @param       classDoc        検索??ClassDoc
717             * @param       key                     検索するキー
718             * @return      FieldDocオブジェク?
719             */
720            private static FieldDoc findFieldDoc( final ClassDoc classDoc ,final String key ) {
721                    FieldDoc rtn = null;
722    
723                    FieldDoc[] fld = classDoc.fields( false ) ;
724    
725                    for( int i=0; i<fld.length; i++ ) {
726                            if( key.equalsIgnoreCase( fld[i].name() ) ) {
727                                    rtn = fld[i];
728                                    break;
729                            }
730                    }
731                    return rtn;
732            }
733    
734            /**
735             * カスタ?プションを使用するドックレ?の??メソ? optionLength(String) です?
736             *
737             * ドックレ?に認識させる?スタ?プションに?optionLength がその
738             * オプションを構?する要?(ト?クン) の数を返さなければなりません?
739             * こ?カスタ?プションでは?-tag オプションそ?も?と
740             * そ?値の 2 つの要?構?される?で、作?するドックレ?の
741             * optionLengthメソ?は?-tag オプションに対して 2 を返さなくては
742             * なりません。また?認識できな?プションに対しては? を返します?
743             *
744             * @param       option  オプション??
745             *
746             * @return      要?ト?クン) の数
747             */
748            public static int optionLength( final String option ) {
749                    if(option.equalsIgnoreCase("-version")) {
750                            return 2;
751                    }
752                    else if(option.equalsIgnoreCase("-outfile")) {
753                            return 2;
754                    }
755                    else if(option.equalsIgnoreCase("-debugLevel")) {
756                            return 2;
757                    }
758                    return 0;
759            }
760    }