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 org.opengion.fukurou.util.LogWriter; 019import org.opengion.fukurou.util.StringUtil; 020 021import com.sun.javadoc.RootDoc; 022import com.sun.javadoc.ClassDoc; 023import com.sun.javadoc.MethodDoc; 024import com.sun.javadoc.Type; 025import com.sun.javadoc.Tag; 026import java.util.Map; 027import java.util.HashMap; 028import java.io.IOException; 029 030/** 031 * ソースコメントから、タグ情報を取り出す Doclet クラスです。 032 * この Doclet は、":org.opengion.hayabusa.taglib" のみ対象として処理します。 033 * og.formSample , og.tag , og.group タグを切り出します。 034 * 035 * @version 4.0 036 * @author Kazuhiko Hasegawa 037 * @since JDK5.0, 038 */ 039public final class DocletTaglib { 040 private static Map<String,String> map = new HashMap<String,String>(); 041 042 private static final String OG_FOR_SMPL = "og.formSample"; 043 private static final String OG_TAG_NAME = "og.tag"; 044 private static final String OG_GROUP = "og.group"; 045 046 private static final String OG_TAG_CLASS = "org.opengion.hayabusa.taglib"; 047 private static final String ENCODE = "UTF-8"; 048 049 /** 050 * すべてが staticメソッドなので、コンストラクタを呼び出さなくしておきます。 051 * 052 */ 053 private DocletTaglib() {} 054 055 /** 056 * Doclet のエントリポイントメソッドです。 057 * 058 * @og.rev 5.7.1.1 (2013/12/13) タグのインデントを止める。 059 * 060 * @param root エントリポイントのRootDocオブジェクト 061 * 062 * @return 正常実行時 true 063 */ 064 public static boolean start( final RootDoc root ) { 065 String version = DocletUtil.getOption( "-version" , root.options() ); 066 String file = DocletUtil.getOption( "-outfile" , root.options() ); 067 068 DocletTagWriter writer = null; 069 try { 070 writer = new DocletTagWriter( file,ENCODE ); 071 072 // 5.7.1.1 (2013/12/13) タグのインデントを止める。 073 writer.printTag( "<?xml version=\"1.0\" encoding=\"", ENCODE, "\" ?>" ); 074 writer.printTag( "<javadoc>" ); 075 writer.printTag( "<version>",version,"</version>" ); 076 writer.printTag( "<description></description>" ); 077 writeContents( root.classes(),writer ); 078 writer.printTag( "</javadoc>" ); 079 } 080 catch( IOException ex ) { 081 LogWriter.log( ex ); 082 } 083 finally { 084 if( writer != null ) { writer.close(); } 085 } 086 return true; 087 } 088 089 /** 090 * ClassDoc 配列よりコンテンツを作成します。 091 * 092 * @og.rev 5.5.4.1 (2012/07/06) コメントは文字列でなく、Tag配列として処理させる。 093 * @og.rev 5.6.6.1 (2013/07/12) og.group を、tagGroup として独立させる。 094 * @og.rev 5.7.1.1 (2013/12/13) cmnt と tags の間に改行をセット 095 * @og.rev 5.7.1.1 (2013/12/13) タグのインデントを止める。 096 * 097 * @param classes ClassDoc配列 098 * @param writer DocletTagWriterオブジェクト 099 */ 100 private static void writeContents( final ClassDoc[] classes,final DocletTagWriter writer ) { 101 for(int i=0; i< classes.length; i++) { 102 ClassDoc classDoc = classes[i] ; 103 String classFullName = classDoc.qualifiedName() ; 104 105 if( ! classDoc.isPublic() || 106 classFullName.indexOf( OG_TAG_CLASS ) < 0 ) { continue; } 107 108 Tag[] desc = classDoc.firstSentenceTags(); 109// String cmnt = DocletUtil.htmlFilter( classDoc.commentText() ); // 5.5.4.1 (2012/07/06) 110 Tag[] cmnt = classDoc.inlineTags(); // 5.5.4.1 (2012/07/06) 111 Tag[] smplTags = classDoc.tags(OG_FOR_SMPL); 112 Tag[] grpTags = classDoc.tags(OG_GROUP); 113 114 // 5.7.1.1 (2013/12/13) タグのインデントを止める。 115 writer.printTag( "<classDoc>" ); 116 writer.printTag( "<tagClass>" ,classFullName ,"</tagClass>" ); 117 // 5.6.6.1 (2013/07/12) og.group を、tagGroup として独立させる。 118 writer.printTag( "<tagGroup>" ,makeGroupTag( grpTags ) ,"</tagGroup>" ); 119 writer.printTag( "<description>" ,desc ,"</description>" ); 120// writer.printTag( "<description>" ); 121//// writer.printTag( makeGroupTag( grpTags ) ); // 5.6.6.1 (2013/07/12) 122// writer.printTag( desc ); 123// writer.printTag( "</description>" ); 124 writer.printTag( "<contents>" ,cmnt ,"</contents>" ); 125 writer.printTag( "<formSample>" ,smplTags ,"</formSample>" ); 126 127 map.clear(); 128 String className = classDoc.name(); 129 while( ! "BodyTagSupport".equals( className ) && 130 ! "TagSupport".equals( className ) ) { 131 String extendFlag = "false"; 132 if( "HTMLTagSupport".equals( className ) ) { 133 extendFlag = "true" ; 134 } 135 MethodDoc[] methods = classDoc.methods(); 136 for(int j=0; j < methods.length; j++) { 137 if( ! methods[j].isPublic() ) { continue; } 138 Tag[] tags = methods[j].tags(OG_TAG_NAME); 139 if(tags.length > 0) { 140 String methodName = DocletUtil.removeSetter( methods[j].name() ); 141 if( map.containsKey( methodName ) ) { continue; } 142 map.put( methodName,className ); 143 Tag[] ftag = methods[j].firstSentenceTags(); 144// cmnt = DocletUtil.htmlFilter( methods[j].commentText() ); // 5.5.4.1 (2012/07/06) 145 cmnt = methods[j].inlineTags(); // 5.5.4.1 (2012/07/06) 146 147 // 5.7.1.1 (2013/12/13) タグのインデントを止める。 148 writer.printTag( "<method>" ); 149 writer.printTag( "<name>" ,methodName ,"</name>" ); 150 writer.printTag( "<htmlExtend>" ,extendFlag ,"</htmlExtend>" ); 151 writer.printTag( "<description>",ftag ,"</description>" ); 152 // 5.7.1.1 (2013/12/13) cmnt と tags の間に改行をセット 153 writer.printTag( "<contents>" ,cmnt ,"" ); 154 writer.printTag( "" ,tags ,"</contents>" ); 155// writer.printTag( " <contents>" ); 156// writer.printTag( cmnt ); 157// writer.printTag( tags ); 158// writer.printTag( " </contents>" ); 159 writer.printTag( "</method>"); 160 } 161 } 162 Type type = classDoc.superclassType(); 163 if( type == null ) { break; } 164 classDoc = type.asClassDoc() ; 165 className = classDoc.name(); 166 } 167 writer.printTag( " </classDoc>" ); 168 } 169 } 170 171 /** 172 * タグ配列を受け取り、タグ出力します。 173 * 複数のタグを出力する場合に、カンマ区切り文字で連結します。 174 * 175 * @og.rev 5.5.4.1 (2012/07/06) DocletUtil.htmlFilter → StringUtil.htmlFilter に変更 176 * @og.rev 5.6.6.1 (2013/07/12) og.group の表示方法を変更する。 177 * 178 * @param tag タグ配列 179 * 180 * @return タグ出力文字列 181 */ 182 private static String makeGroupTag( final Tag[] tag ) { 183 StringBuilder but = new StringBuilder( 200 ); 184 for( int i=0; i<tag.length; i++ ) { 185// String data = DocletUtil.htmlFilter( tag[i].text() ); 186 String data = StringUtil.htmlFilter( tag[i].text() ); // 5.5.4.1 (2012/07/06) DocletUtil → StringUtil に変更 187 if( i > 0 ) { but.append( "," ); } 188// but.append( data ); 189 but.append( "【" ).append( data ).append( "】" ); // 5.6.6.1 (2013/07/12) og.group の表示方法を変更 190 } 191 return but.toString() ; // 5.6.6.1 (2013/07/12) 192// if( but.length() > 0 ) { 193// return "【" + but.toString() + "】" ; 194// } 195// else { 196// return ""; 197// } 198 } 199 200 /** 201 * カスタムオプションを使用するドックレットの必須メソッド optionLength(String) です。 202 * 203 * ドックレットに認識させる各カスタムオプションに、 optionLength がその 204 * オプションを構成する要素 (トークン) の数を返さなければなりません。 205 * このカスタムオプションでは、 -tag オプションそのものと 206 * その値の 2 つの要素で構成されるので、作成するドックレットの 207 * optionLengthメソッドは、 -tag オプションに対して 2 を返さなくては 208 * なりません。また、認識できないオプションに対しては、0 を返します。 209 * 210 * @param option カスタムオプションのキーワード 211 * 212 * @return 要素 (トークン) の数 213 */ 214 public static int optionLength( final String option ) { 215 if(option.equalsIgnoreCase("-version")) { 216 return 2; 217 } 218 else if(option.equalsIgnoreCase("-outfile")) { 219 return 2; 220 } 221 return 0; 222 } 223}