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 java.lang.reflect.Field;
019    
020    import com.sun.javadoc.Tag;
021    import com.sun.javadoc.Doc;
022    import com.sun.javadoc.MethodDoc;
023    import com.sun.javadoc.ClassDoc;
024    import com.sun.javadoc.PackageDoc;
025    import com.sun.javadoc.ProgramElementDoc;
026    
027    /**
028     * Doclet をå?ç�?�™るã?ログラãƒ?�§共通して使用される簡易メソãƒ?ƒ‰群(ユーãƒ?‚£リãƒ?‚£クラス)ですã?
029     *
030     * @version  4.0
031     * @author   Kazuhiko Hasegawa
032     * @since    JDK5.0,
033     */
034    public final class DocletUtil {
035            /** リターンコーãƒ? System.getProperty("line.separator")  */
036            public static final String CR = System.getProperty("line.separator");
037    
038            private static final String CLS = "org.opengion.hayabusa.common.BuildNumber";           // package.class
039            private static final String FLD = "VERSION_NO";                                                                         // field
040            private static String versionNo = null; // æœ??にä¸?º¦ã�?�‘取得しておきますã?
041    
042            /**
043             * すべてã�?staticメソãƒ?ƒ‰なので、コンストラクタを呼び出さなくしておきますã?
044             *
045             */
046            private DocletUtil() {}
047    
048            /**
049             * 入力文字å?の HTML æ–?­—をフィルタリングしますã?
050             * "&" はã€?&amp;#38;" ã€?<" はã€?&amp;lt;" ã€?>" はã€?&amp;gt;" に変換しますã?
051             * StringUtil.htmlFilter との違いはã€?;' â†?"&#59;" への変換があることですã?
052             *
053             * @og.rev 5.5.4.1 (2012/07/06) DocletUtil.htmlFilter â†?StringUtil.htmlFilter に変更のため、å»?­¢
054             *
055             * @param input String
056             *
057             * @return 変換後文字å?
058             */
059    //      public static String htmlFilter( final String input ) {
060    //              if( input == null ) { return ""; }
061    //
062    //              int len = input.length();
063    //
064    //              StringBuilder rtn = new StringBuilder( len + 50 );
065    //              char ch;
066    //              for(int i=0; i<len; i++) {
067    //                      ch = input.charAt(i);
068    //                      switch( ch ) {
069    //                              case '<'  : rtn.append("&lt;");   break;
070    //                              case '>'  : rtn.append("&gt;");   break;
071    //                              case '"'  : rtn.append("&quot;"); break;
072    //                              case '\'' : rtn.append("&#39;");  break;
073    //                              case '&'  : rtn.append("&amp;");  break;
074    //                              case ';'  : rtn.append("&#59;");  break;
075    //                              default   : rtn.append(ch);
076    //                      }
077    //              }
078    //              return( rtn.toString() );
079    //      }
080    
081            /**
082             * target æ–?­—å?に含まれる from æ–?­—å?ã‚?to æ–?­—å?に置き換えますã?
083             *
084             * @param       target  å…??æ–?­—å?
085             * @param       from    置換å?FROM
086             * @param       to              置換å?TO
087             *
088             * @return      変換後文字å?
089             */
090            public static String replace( final String target,final String from,final String to ) {
091                    if( target == null || from == null || to == null ) { return target; }
092                    StringBuilder strBuf = new StringBuilder( 200 );
093    
094                    int start = 0;
095                    int end   = target.indexOf( from,start );
096                    while( end >= 0  ) {
097                            strBuf.append( target.substring( start,end ) );
098                            strBuf.append( to );
099                            start = end + from.length();
100                            end   = target.indexOf( from,start );
101                    }
102                    strBuf.append( target.substring( start ) );
103    
104                    return strBuf.toString();
105            }
106    
107            /**
108             * コメント部のæ–?­—å?を取得しますã?
109             *
110             * @og.rev 5.5.4.1 (2012/07/06) コメントã?æ–?­—å?でなくã?Tag配å?として処ç�?�•せるã€?
111             *
112             * @param cmnt String
113             *
114             * @return コメント文字å?
115             */
116    //      public static String commentText( final String cmnt ) {
117    //              if( cmnt == null ) { return ""; }
118    //
119    //              String rtn = cmnt;
120    //              int indx = cmnt.indexOf( "{@value}" );
121    //              if( indx >= 0 ) {
122    //                      rtn = cmnt.substring( indx+8 ); // {@value} 以前を削除
123    //              }
124    //              return htmlFilter( rtn );
125    //      }
126    
127            /**
128             * セãƒ?‚¿ーメソãƒ?ƒ‰の setXXXX の set を削除しã?次のæ–?­—を小文字化しますã?
129             * つまりã?セãƒ?‚¿ーメソãƒ?ƒ‰から属æ?値を推測しますã?
130             * (è¶?‰¹殊å?ç�?セãƒ?‚¿ーメソãƒ?ƒ‰のset以下2文字目が大æ–?­—ã?場合ã?ã€?
131             * ?‘文字目も大æ–?­—とè€?�ˆて小文字化を行いませんã€?
132             * 例えば、setSYS ã‚?setUSER など、RequestValueTag.javaに使用するケースですã?
133             *
134             * @param target 処ç�?¯¾象となる文字å?
135             *
136             * @return オプションæ–?­—å?
137             */
138            public static String removeSetter( final String target ) {
139                    if( target != null && target.startsWith( "set" ) ) {
140                            char[] chs = target.toCharArray();
141                            if( chs.length > 4 && !( chs[4] >= 'A' && chs[4] <= 'Z' ) ) {
142                                    chs[3] = Character.toLowerCase( chs[3] ) ;
143                            }
144                            return new String( chs,3,chs.length-3 );
145                    }
146                    return target;
147            }
148    
149            /**
150             * オプション配å?æ–?­—å?より、指定ã?キーに対応するオプション値を返しますã?
151             *
152             * @param       key             キー
153             * @param       options オプション配å?æ–?­—å?
154             *
155             * @return      オプションæ–?­—å?
156             */
157            public static String getOption( final String key , final String[][] options ) {
158                    String rtn = "";
159                    if( key == null || options == null ) { return rtn; }
160    
161                    for( int i=0; i<options.length; i++ ) {
162                            if( key.equalsIgnoreCase( options[i][0] ) ) {
163                                    rtn = options[i][1];
164                                    break ;
165                            }
166                    }
167                    return rtn ;
168            }
169    
170            /**
171             * {&#064;og.value package.class#field} 形式ã?valueタグを文字å?に置き換えますã?
172             *
173             * 処ç�?š„には、リフレクションで、å?を取得しますã?値は、staticフィールドã?み取得可能ですã?
174             *
175             * @og.rev 5.5.4.1 (2012/07/06) 新規追åŠ?
176             * @og.rev 5.5.5.6 (2012/08/31) クラス名ã?取得で、ProgramElementDoc で処ç�?�™るよã�?�«変更
177             *
178             * @param tag Tagオブジェクãƒ?
179             *
180             * @return valueタグの解析結果のæ–?­—å?
181             */
182            public static String valueTag( final Tag tag ) {
183                    String txt = tag.text();
184                    if( txt != null ) {
185                            String cls = null;              // package.class
186                            String fld = null;              // field
187    
188                            // package.class#field 形式ã?解析ã?
189                            int adrs = txt.indexOf('#') ;
190                            if( adrs > 0 ) {
191                                    cls = txt.substring( 0,adrs );          // package.class
192                                    fld = txt.substring( adrs+1 );          // field
193                            }
194                            else if( adrs == 0 ) {
195                                    fld = txt.substring( 1 );                       // #field
196                            }
197                            else {
198                                    String errMsg = "警å‘?{@value package.class#field} 形式ã? フィールド名 #field がありませんã€? + CR
199                                                                    + tag.position() + " : " + txt + CR ;
200                                    System.err.println( errMsg );
201                                    // # を付け忘れたとè€?�ˆ、è?åˆ??身のクラスを利用
202                                    fld = txt;                                                      // field
203                            }
204    
205                            // package.class をきちんと作æ?するã€?
206                            Doc doc = tag.holder();
207    //                      if( doc.isMethod() ) {
208    //                              MethodDoc mdoc = (MethodDoc)doc;
209    //                              ClassDoc cdoc = mdoc.containingClass();
210    //                              if( cls == null ) {                                     // package.class が登録されてã�?�ªã�??合ã?
211    //                                      cls = cdoc.qualifiedName() ;
212    //                              }
213    //                              else if( cls.indexOf('.') < 0 ) {    // class のみが登録されてã�?‚‹場合ã?findClass で、package 込の正式クラス名を検索するã€?
214    //                                      ClassDoc pdoc = cdoc.findClass( cls );
215    //                                      cls = pdoc.qualifiedName() ;
216    //                              }
217    //                      }
218    
219                            // 5.5.5.6 (2012/08/31) ProgramElementDoc で処ç�?�™るよã�?�«変更
220                            if( doc instanceof ProgramElementDoc ) {
221                                    ProgramElementDoc pdoc = (ProgramElementDoc)doc;
222                                    ClassDoc cdoc = pdoc.containingClass();
223                                    if( cdoc != null ) {
224                                            if( cls == null ) {                                     // package.class が登録されてã�?�ªã�??合ã?
225                                                    cls = cdoc.qualifiedName() ;
226                                            }
227                                            else if( cls.indexOf('.') < 0 ) {    // class のみが登録されてã�?‚‹場合ã?findClass で、package 込の正式クラス名を検索するã€?
228                                                    ClassDoc fdoc = cdoc.findClass( cls );
229                                                    if( fdoc != null ) {
230                                                            cls = fdoc.qualifiedName() ;
231                                                    }
232                                            }
233                                    }
234                                    else {
235                                            if( cls == null ) {                                     // package.class が登録されてã�?�ªã�??合ã?
236                                                    cls = pdoc.qualifiedName() ;
237                                            }
238                                    }
239                            }
240    
241                            //  5.6.3.3 (2013/04/19) メソãƒ?ƒ‰化で共有しますã?
242                            txt = getStaticField( cls,fld );
243    
244    //                      try {
245    //                              Field fldObj = Class.forName( cls ).getDeclaredField( fld );
246    //                              // privateフィールドへのアクセスã€?セキュリãƒ?‚£ーマネージャーによってアクセス制限がかけられてã�?�ªã�??å�?
247    //                              if( !fldObj.isAccessible() ) { fldObj.setAccessible( true ); }
248    //                              txt = String.valueOf( fldObj.get( null ) );             // static フィールドã?、引数 null で値を取å¾?
249    //                      }
250    //                      catch( Exception ex ) {
251    //                              String errMsg = "警å‘?{@value package.class#field} 形式ã?対象がありませんã€? + CR
252    //                                                              + tag.position() + " : " + tag.text() + CR
253    //                                                              + ex.getMessage() + CR;
254    //                              System.err.println( errMsg );
255    //                      }
256                    }
257                    return txt ;
258            }
259    
260            /**
261             * {&#064;og.doc03Link queryType Query_**** クラス} 形式ã?doc03Linkタグをリンクæ–?­—å?に置き換えますã?
262             *
263             * <a href="/gf/jsp/DOC03/index.jsp?command=NEW&GAMENID=DOC03&VERNO=X.X.X.X&VALUENAME=queryType" target="CONTENTS">Query_**** クラス</a>
264             * のようなリンクを作æ?しますã?
265             * 第ä¸?¼•数は、VALUENAME の引数ですã?
266             * それ以降ã?ãƒ?‚­ストã?、リンクæ–?­—å?のドキュメントになりますã?
267             * DOC03 画面へのリンクを作æ?するに当たりã?バã?ジョンがå¿?¦�ですã?org.opengion.hayabusa.common.BuildNumber#VERSION_NO から取得しますがã€?
268             * パッケージの優先é?の関係で、リフレクションを使用しますã?
269             *
270             * @og.rev 5.6.3.3 (2013/04/19) 新規作æ?
271             *
272             * @param tag Tagオブジェクãƒ?
273             *
274             * @return valueタグの解析結果のæ–?­—å?
275             */
276            public static String doc03LinkTag( final Tag tag ) {
277                    if( versionNo == null ) { versionNo = getStaticField( CLS , FLD ); }
278    
279                    String txt = tag.text();
280                    if( txt != null ) {
281                            String valnm = null;                    // VALUENAME
282                            String body  = null;                    // ドキュメンãƒ?
283    
284                            int adrs = txt.indexOf(' ') ;   // æœ??のスペã?スでåˆ?›¢しますã?
285                            if( adrs > 0 ) {
286                                    valnm = txt.substring( 0,adrs );                // VALUENAME
287                                    body  = txt.substring( adrs+1 );                // ドキュメンãƒ?
288                            }
289                            else {
290                                    valnm = txt;                                                    // VALUENAME
291                                    body  = txt;                                                    // ドキュメンãƒ?
292                            }
293    
294                            txt = "&lt;a href=\"/gf/jsp/DOC03/index.jsp?command=NEW&amp;GAMENID=DOC03"
295                                            + "&amp;VERNO="     + versionNo
296                                            + "&amp;VALUENAME=" + valnm
297                                            + "\" target=\"CONTENTS\"&gt;"
298                                            + body
299                                            + "&lt;/a&gt;" ;
300                    }
301                    return txt ;
302            }
303    
304            /**
305             * パッケージ.クラスå�?と、フィールド名 から、staticフィールドã?値を取得しますã?
306             *
307             * Field fldObj = Class.forName( cls ).getDeclaredField( fld ); で、Fieldオブジェクトを呼出しã?
308             * String.valueOf( fldObj.get( null ) ); で、å?を取得してã�?�¾すã?
309             * static フィールドã?、引数 null で値を取得できますã?
310             *
311             * 例ï¼?
312         *      String cls = "org.opengion.hayabusa.common.BuildNumber";        // package.class
313         *      String fld = "VERSION_NO";                                      // field
314             *
315             * @og.rev 5.6.3.3 (2013/04/19) 新規作æ?
316             *
317             * @param cls パッケージ.クラスå�?
318             * @param fld フィールド名
319             * @return 取得å?
320             */
321            public static String getStaticField( final String cls , final String fld ) {
322    
323                    String txt = null;
324                    try {
325                            Field fldObj = Class.forName( cls ).getDeclaredField( fld );
326                            // privateフィールドへのアクセスã€?セキュリãƒ?‚£ーマネージャーによってアクセス制限がかけられてã�?�ªã�??å�?
327                            if( !fldObj.isAccessible() ) { fldObj.setAccessible( true ); }
328                            txt = String.valueOf( fldObj.get( null ) );             // static フィールドã?、引数 null で値を取å¾?
329                    }
330                    catch( Exception ex ) {
331                            String errMsg = "package.class = " + cls + " field = " + fld + " の取得に失敗しましたã€?
332                                                            + ex.getMessage() + CR;
333                            System.err.println( errMsg );
334                    }
335    
336                    return txt ;
337            }
338    }