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    }