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以下2文字目が大文字の場合は、 076 * 1文字目も大文字と考えて小文字化を行いません。 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 * {@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 * {@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 = "<a href=\"/gf/jsp/DOC03/index.jsp?command=NEW&GAMENID=DOC03" 214 + "&VERNO=" + versionNo 215 + "&VALUENAME=" + valnm 216 + "\" target=\"CONTENTS\">" 217 + body 218 + "</a>" ; 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}