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 Tag[] cmnt = classDoc.inlineTags(); // 5.5.4.1 (2012/07/06) 110 Tag[] smplTags = classDoc.tags(OG_FOR_SMPL); 111 Tag[] grpTags = classDoc.tags(OG_GROUP); 112 113 // 5.7.1.1 (2013/12/13) タグのインデントを止める。 114 writer.printTag( "<classDoc>" ); 115 writer.printTag( "<tagClass>" ,classFullName ,"</tagClass>" ); 116 // 5.6.6.1 (2013/07/12) og.group を、tagGroup として独立させる。 117 writer.printTag( "<tagGroup>" ,makeGroupTag( grpTags ) ,"</tagGroup>" ); 118 writer.printTag( "<description>" ,desc ,"</description>" ); 119 writer.printTag( "<contents>" ,cmnt ,"</contents>" ); 120 writer.printTag( "<formSample>" ,smplTags ,"</formSample>" ); 121 122 map.clear(); 123 String className = classDoc.name(); 124 while( ! "BodyTagSupport".equals( className ) && 125 ! "TagSupport".equals( className ) ) { 126 String extendFlag = "false"; 127 if( "HTMLTagSupport".equals( className ) ) { 128 extendFlag = "true" ; 129 } 130 MethodDoc[] methods = classDoc.methods(); 131 for(int j=0; j < methods.length; j++) { 132 if( ! methods[j].isPublic() ) { continue; } 133 Tag[] tags = methods[j].tags(OG_TAG_NAME); 134 if(tags.length > 0) { 135 String methodName = DocletUtil.removeSetter( methods[j].name() ); 136 if( map.containsKey( methodName ) ) { continue; } 137 map.put( methodName,className ); 138 Tag[] ftag = methods[j].firstSentenceTags(); 139 cmnt = methods[j].inlineTags(); // 5.5.4.1 (2012/07/06) 140 141 // 5.7.1.1 (2013/12/13) タグのインデントを止める。 142 writer.printTag( "<method>" ); 143 writer.printTag( "<name>" ,methodName ,"</name>" ); 144 writer.printTag( "<htmlExtend>" ,extendFlag ,"</htmlExtend>" ); 145 writer.printTag( "<description>",ftag ,"</description>" ); 146 // 5.7.1.1 (2013/12/13) cmnt と tags の間に改行をセット 147 writer.printTag( "<contents>" ,cmnt ,"" ); 148 writer.printTag( "" ,tags ,"</contents>" ); 149 writer.printTag( "</method>"); 150 } 151 } 152 Type type = classDoc.superclassType(); 153 if( type == null ) { break; } 154 classDoc = type.asClassDoc() ; 155 className = classDoc.name(); 156 } 157 writer.printTag( " </classDoc>" ); 158 } 159 } 160 161 /** 162 * タグ配列を受け取り、タグ出力します。 163 * 複数のタグを出力する場合に、カンマ区切り文字で連結します。 164 * 165 * @og.rev 5.5.4.1 (2012/07/06) DocletUtil.htmlFilter → StringUtil.htmlFilter に変更 166 * @og.rev 5.6.6.1 (2013/07/12) og.group の表示方法を変更する。 167 * 168 * @param tag タグ配列 169 * 170 * @return タグ出力文字列 171 */ 172 private static String makeGroupTag( final Tag[] tag ) { 173 StringBuilder but = new StringBuilder( 200 ); 174 for( int i=0; i<tag.length; i++ ) { 175 String data = StringUtil.htmlFilter( tag[i].text() ); // 5.5.4.1 (2012/07/06) DocletUtil → StringUtil に変更 176 if( i > 0 ) { but.append( "," ); } 177 but.append( "【" ).append( data ).append( "】" ); // 5.6.6.1 (2013/07/12) og.group の表示方法を変更 178 } 179 return but.toString() ; // 5.6.6.1 (2013/07/12) 180 } 181 182 /** 183 * カスタムオプションを使用するドックレットの必須メソッド optionLength(String) です。 184 * 185 * ドックレットに認識させる各カスタムオプションに、 optionLength がその 186 * オプションを構成する要素 (トークン) の数を返さなければなりません。 187 * このカスタムオプションでは、 -tag オプションそのものと 188 * その値の 2 つの要素で構成されるので、作成するドックレットの 189 * optionLengthメソッドは、 -tag オプションに対して 2 を返さなくては 190 * なりません。また、認識できないオプションに対しては、0 を返します。 191 * 192 * @param option カスタムオプションのキーワード 193 * 194 * @return 要素 (トークン) の数 195 */ 196 public static int optionLength( final String option ) { 197 if("-version".equalsIgnoreCase(option)) { 198 return 2; 199 } 200 else if("-outfile".equalsIgnoreCase(option)) { 201 return 2; 202 } 203 return 0; 204 } 205}