    001/*
    002 * Copyright (c) 2009 The openGion Project.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *     http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
    013 * either express or implied. See the License for the specific language
    014 * governing permissions and limitations under the License.
    015 */
    016package org.opengion.fukurou.taglet;
    017
    018import java.lang.reflect.Field;
    019
    020import com.sun.javadoc.Tag;
    021import com.sun.javadoc.Doc;
    022import com.sun.javadoc.ClassDoc;
    023import com.sun.javadoc.ProgramElementDoc;
    024
    025/**
    026 * Doclet を処理するプログラムで共通して使用される簡易メソッド群(ユーティリティクラス)です。
    027 *
    028 * @version  4.0
    029 * @author   Kazuhiko Hasegawa
    030 * @since    JDK5.0,
    031 */
    032public final class DocletUtil {
    033        /** リターンコード  System.getProperty("line.separator")  */
    034        public static final String CR = System.getProperty("line.separator");
    035
    036        private static final String CLS = "org.opengion.hayabusa.common.BuildNumber";           // package.class
    037        private static final String FLD = "VERSION_NO";                                                                         // field
    038        private static final String versionNo = getStaticField( CLS , FLD );
    039
    040        /**
    041         * すべてが staticメソッドなので、コンストラクタを呼び出さなくしておきます。
    042         *
    043         */
    044        private DocletUtil() {}
    045
    046        /**
    047         * target 文字列に含まれる from 文字列を to 文字列に置き換えます。
    048         *
    049         * @param       target  元の文字列
    050         * @param       from    置換元FROM
    051         * @param       to              置換先TO
    052         *
    053         * @return      変換後文字列
    054         */
    055        public static String replace( final String target,final String from,final String to ) {
    056                if( target == null || from == null || to == null ) { return target; }
    057                StringBuilder strBuf = new StringBuilder( 200 );
    058
    059                int start = 0;
    060                int end   = target.indexOf( from,start );
    061                while( end >= 0  ) {
    062                        strBuf.append( target.substring( start,end ) );
    063                        strBuf.append( to );
    064                        start = end + from.length();
    065                        end   = target.indexOf( from,start );
    066                }
    067                strBuf.append( target.substring( start ) );
    068
    069                return strBuf.toString();
    070        }
    071
    072        /**
    073         * セッターメソッドの setXXXX の set を削除し、次の文字を小文字化します。
    074         * つまり、セッターメソッドから属性値を推測します。
    075         * (超特殊処理)セッターメソッドのset以下２文字目が大文字の場合は、
    076         * １文字目も大文字と考えて小文字化を行いません。
    077         * 例えば、setSYS や setUSER など、RequestValueTag.javaに使用するケースです。
    078         *
    079         * @param target 処理対象となる文字列
    080         *
    081         * @return オプション文字列
    082         */
    083        public static String removeSetter( final String target ) {
    084                if( target != null && target.startsWith( "set" ) ) {
    085                        char[] chs = target.toCharArray();
    086                        if( chs.length > 4 && !( chs[4] >= 'A' && chs[4] <= 'Z' ) ) {
    087                                chs[3] = Character.toLowerCase( chs[3] ) ;
    088                        }
    089                        return new String( chs,3,chs.length-3 );
    090                }
    091                return target;
    092        }
    093
    094        /**
    095         * オプション配列文字列より、指定のキーに対応するオプション値を返します。
    096         *
    097         * @param       key             キー
    098         * @param       options オプション配列文字列
    099         *
    100         * @return      オプション文字列
    101         */
    102        public static String getOption( final String key , final String[][] options ) {
    103                String rtn = "";
    104                if( key == null || options == null ) { return rtn; }
    105
    106                for( int i=0; i<options.length; i++ ) {
    107                        if( key.equalsIgnoreCase( options[i][0] ) ) {
    108                                rtn = options[i][1];
    109                                break ;
    110                        }
    111                }
    112                return rtn ;
    113        }
    114
    115        /**
    116         * {&#064;og.value package.class#field} 形式のvalueタグを文字列に置き換えます。
    117         *
    118         * 処理的には、リフレクションで、値を取得します。値は、staticフィールドのみ取得可能です。
    119         *
    120         * @og.rev 5.5.4.1 (2012/07/06) 新規追加
    121         * @og.rev 5.5.5.6 (2012/08/31) クラス名の取得で、ProgramElementDoc で処理するように変更
    122         *
    123         * @param tag Tagオブジェクト
    124         *
    125         * @return valueタグの解析結果の文字列
    126         */
    127        public static String valueTag( final Tag tag ) {
    128                String txt = tag.text();
    129                if( txt != null ) {
    130                        String cls = null;              // package.class
    131                        String fld = null;              // field
    132
    133                        // package.class#field 形式の解析。
    134                        int adrs = txt.indexOf('#') ;
    135                        if( adrs > 0 ) {
    136                                cls = txt.substring( 0,adrs );          // package.class
    137                                fld = txt.substring( adrs+1 );          // field
    138                        }
    139                        else if( adrs == 0 ) {
    140                                fld = txt.substring( 1 );                       // #field
    141                        }
    142                        else {
    143                                String errMsg = "警告:{@value package.class#field} 形式の フィールド名 #field がありません。" + CR
    144                                                                + tag.position() + " : " + txt + CR ;
    145                                System.err.println( errMsg );
    146                                // # を付け忘れたと考え、自分自身のクラスを利用
    147                                fld = txt;                                                      // field
    148                        }
    149
    150                        // package.class をきちんと作成する。
    151                        Doc doc = tag.holder();
    152
    153                        // 5.5.5.6 (2012/08/31) ProgramElementDoc で処理するように変更
    154                        if( doc instanceof ProgramElementDoc ) {
    155                                ProgramElementDoc pdoc = (ProgramElementDoc)doc;
    156                                ClassDoc cdoc = pdoc.containingClass();
    157                                if( cdoc != null ) {
    158                                        if( cls == null ) {                                     // package.class が登録されていない場合。
    159                                                cls = cdoc.qualifiedName() ;
    160                                        }
    161                                        else if( cls.indexOf('.') < 0 ) {       // class のみが登録されている場合。findClass で、package 込の正式クラス名を検索する。
    162                                                ClassDoc fdoc = cdoc.findClass( cls );
    163                                                if( fdoc != null ) {
    164                                                        cls = fdoc.qualifiedName() ;
    165                                                }
    166                                        }
    167                                }
    168                                else {
    169                                        if( cls == null ) {                                     // package.class が登録されていない場合。
    170                                                cls = pdoc.qualifiedName() ;
    171                                        }
    172                                }
    173                        }
    174
    175                        //  5.6.3.3 (2013/04/19) メソッド化で共有します。
    176                        txt = getStaticField( cls,fld );
    177                }
    178                return txt ;
    179        }
    180
    181        /**
    182         * {&#064;og.doc03Link queryType Query_**** クラス} 形式のdoc03Linkタグをリンク文字列に置き換えます。
    183         *
    184         * <a href="/gf/jsp/DOC03/index.jsp?command=NEW&GAMENID=DOC03&VERNO=X.X.X.X&VALUENAME=queryType" target="CONTENTS">Query_**** クラス</a>
    185         * のようなリンクを作成します。
    186         * 第一引数は、VALUENAME の引数です。
    187         * それ以降のテキストは、リンク文字列のドキュメントになります。
    188         * DOC03 画面へのリンクを作成するに当たり、バージョンが必要です。org.opengion.hayabusa.common.BuildNumber#VERSION_NO から取得しますが、
    189         * パッケージの優先順の関係で、リフレクションを使用します。
    190         *
    191         * @og.rev 5.6.3.3 (2013/04/19) 新規作成
    192         *
    193         * @param tag Tagオブジェクト
    194         *
    195         * @return valueタグの解析結果の文字列
    196         */
    197        public static String doc03LinkTag( final Tag tag ) {
    198                String txt = tag.text();
    199                if( txt != null ) {
    200                        String valnm = null;                    // VALUENAME
    201                        String body  = null;                    // ドキュメント
    202
    203                        int adrs = txt.indexOf(' ') ;   // 最初のスペースで分離します。
    204                        if( adrs > 0 ) {
    205                                valnm = txt.substring( 0,adrs );                // VALUENAME
    206                                body  = txt.substring( adrs+1 );                // ドキュメント
    207                        }
    208                        else {
    209                                valnm = txt;                                                    // VALUENAME
    210                                body  = txt;                                                    // ドキュメント
    211                        }
    212
    213                        txt = "&lt;a href=\"/gf/jsp/DOC03/index.jsp?command=NEW&amp;GAMENID=DOC03"
    214                                        + "&amp;VERNO="     + versionNo
    215                                        + "&amp;VALUENAME=" + valnm
    216                                        + "\" target=\"CONTENTS\"&gt;"
    217                                        + body
    218                                        + "&lt;/a&gt;" ;
    219                }
    220                return txt ;
    221        }
    222
    223        /**
    224         * パッケージ.クラス名 と、フィールド名 から、staticフィールドの値を取得します。
    225         *
    226         * Field fldObj = Class.forName( cls ).getDeclaredField( fld ); で、Fieldオブジェクトを呼出し、
    227         * String.valueOf( fldObj.get( null ) ); で、値を取得しています。
    228         * static フィールドは、引数 null で値を取得できます。
    229         *
    230         * 例；
    231     *      String cls = "org.opengion.hayabusa.common.BuildNumber";        // package.class
    232     *      String fld = "VERSION_NO";                                      // field
    233         *
    234         * @og.rev 5.6.3.3 (2013/04/19) 新規作成
    235         *
    236         * @param cls パッケージ.クラス名
    237         * @param fld フィールド名
    238         * @return 取得値
    239         */
    240        public static String getStaticField( final String cls , final String fld ) {
    241
    242                String txt = null;
    243                try {
    244                        Field fldObj = Class.forName( cls ).getDeclaredField( fld );
    245                        // privateフィールドへのアクセス。(セキュリティーマネージャーによってアクセス制限がかけられていない場合)
    246                        if( !fldObj.isAccessible() ) { fldObj.setAccessible( true ); }
    247                        txt = String.valueOf( fldObj.get( null ) );             // static フィールドは、引数 null で値を取得
    248                }
    249                catch( Exception ex ) {
    250                        String errMsg = "package.class = " + cls + " field = " + fld + " の取得に失敗しました。"
    251                                                        + ex.getMessage() + CR;
    252                        System.err.println( errMsg );
    253                }
    254
    255                return txt ;
    256        }
    257}