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