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;
019
020import com.sun.javadoc.RootDoc;
021import com.sun.javadoc.ClassDoc;
022import com.sun.javadoc.Type;
023import com.sun.javadoc.Tag;
024import java.util.Map;
025import java.util.HashMap;
026import java.io.IOException;
027
028/**
029 * ソースコメントから、属性情報を取り出す Doclet クラスです。
030 *
031 * @version  4.0
032 * @author   Kazuhiko Hasegawa
033 * @since    JDK5.0,
034 */
035public final class DocletPlugin {
036        private static Map<String,AttKeySet> map = new HashMap<String,AttKeySet>();
037
038        private static final String OG_FOR_SMPL  = "og.formSample";
039        private static final String ENCODE = "UTF-8";
040
041        /**
042         * すべてが staticメソッドなので、コンストラクタを呼び出さなくしておきます。
043         *
044         */
045        private DocletPlugin() {}
046
047        /**
048         * Doclet のエントリポイントメソッドです。
049         *
050         * @og.rev 5.7.1.1 (2013/12/13) タグのインデントを止める。
051         *
052         * @param root ドキュメントルートオブジェクト
053         *
054         * @return 正常実行時 true
055         */
056        public static boolean start( final RootDoc root ) {
057                String version = DocletUtil.getOption( "-version" , root.options() );
058                String file    = DocletUtil.getOption( "-outfile" , root.options() );
059
060                mapInit();
061
062                DocletTagWriter writer = null;
063                try {
064                        writer = new DocletTagWriter( file,ENCODE );
065
066                        // 5.7.1.1 (2013/12/13) タグのインデントを止める。
067                        writer.printTag( "<?xml version=\"1.0\" encoding=\"", ENCODE, "\" ?>" );
068                        writer.printTag( "<javadoc>" );
069                        writer.printTag(   "<version>",version,"</version>" );
070                        writer.printTag(   "<description></description>" );
071                        writeContents( root.classes(),writer );
072                        writer.printTag( "</javadoc>" );
073                }
074                catch( IOException ex ) {
075                        LogWriter.log( ex );
076                }
077                finally {
078                        if( writer != null ) { writer.close(); }
079                }
080                return true;
081        }
082
083        /**
084         * ClassDoc 配列よりコンテンツを作成します。
085         * インターフェースも処理の対象とします。
086         *
087         * @og.rev 5.5.4.1 (2012/07/06) コメントは文字列でなく、Tag配列として処理させる。
088         * @og.rev 5.7.1.1 (2013/12/13) タグのインデントを止める。
089         *
090         * @param classes       ClassDoc配列
091         * @param writer        DocletTagWriterオブジェクト
092         */
093        private static void writeContents( final ClassDoc[] classes,final DocletTagWriter writer ) {
094                for(int i=0; i< classes.length; i++) {
095                        ClassDoc classDoc      = classes[i] ;
096                        if( ! classDoc.isPublic() ) { continue; }
097
098                        AttKeySet attSet = getAttGroupName( classDoc ) ;
099
100                        if( attSet == null ) { continue; }              // map に登録されていない。
101
102                        String attKey   = attSet.getAttKey( classDoc.name() );
103
104                        if( attKey == null ) { continue; }              // 対象クラス名が、一致しない。
105
106                        String attClass = classDoc.qualifiedName() ;    // Class Full Name
107                        Tag[]  desc     = classDoc.firstSentenceTags();
108                        Tag[]  cmnt     = classDoc.inlineTags();                                                                        // 5.5.4.1 (2012/07/06)
109                        Tag[] smplTags  = classDoc.tags(OG_FOR_SMPL);
110
111                        // 5.7.1.1 (2013/12/13) タグのインデントを止める。
112                        writer.printTag( "<classDoc>" );
113                        writer.printTag(   "<attClass>"         ,attClass                               ,"</attClass>"          );
114                        writer.printTag(   "<seq>"                      ,attSet.getSeq()                ,"</seq>"                       );
115                        writer.printTag(   "<attKey>"           ,attKey                                 ,"</attKey>"            );
116                        writer.printTag(   "<valueName>"        ,attSet.getValueName()  ,"</valueName>"         );
117                        writer.printTag(   "<description>"      ,desc                                   ,"</description>"       );
118                        writer.printTag(   "<contents>"         ,cmnt                                   ,"</contents>"          );
119                        writer.printTag(   "<formSample>"       ,smplTags                               ,"</formSample>"        );
120                        writer.printTag( "</classDoc>" );
121                }
122        }
123
124        /**
125         * 処理する属性クラスのMapを初期化します。
126         * 指定できるのは、親クラスか、直接のインターフェースです。
127         *
128         * @og.rev 4.3.5.0 (2008/02/01) daemonパッケージ追加
129         * @og.rev 5.5.3.5 (2012/06/21) ChartWriter 削除、TransferExec,TransferRead 追加
130         * @og.rev 5.6.3.3 (2013/04/19) DBTableReport,CalendarData,DBConstValue,JspParserFilter,ConnectIF 追加
131         *
132         */
133        private static void mapInit() {
134                map.put( "org.opengion.hayabusa.db.Query"                               , new AttKeySet( "Query"                        ,0, "queryType"         ));
135                map.put( "org.opengion.hayabusa.db.CellRenderer"                , new AttKeySet( "Renderer"                     ,1, "renderer"          ));
136                map.put( "org.opengion.hayabusa.db.CellEditor"                  , new AttKeySet( "Editor"                       ,2, "editor"            ));
137                map.put( "org.opengion.hayabusa.db.DBType"                              , new AttKeySet( "DBType"                       ,3, "dbType"            ));
138                map.put( "org.opengion.hayabusa.db.TableFilter"                 , new AttKeySet( "TableFilter"          ,4, "tableFilter"       ));
139                map.put( "org.opengion.hayabusa.db.Selection"                   , new AttKeySet( "Selection"            ,5, "selection"         ));
140                map.put( "org.opengion.hayabusa.html.ViewForm"                  , new AttKeySet( "ViewForm"                     ,6, "viewFormType"      ));
141                map.put( "org.opengion.hayabusa.io.TableWriter"                 , new AttKeySet( "TableWriter"          ,7, "writerClass"       ));
142                map.put( "org.opengion.hayabusa.io.TableReader"                 , new AttKeySet( "TableReader"          ,8, "readerClass"       ));
143                map.put( "org.opengion.hayabusa.resource.CalendarQuery" , new AttKeySet( "CalendarQuery"        ,10, "calDB"            ));
144                map.put( "org.opengion.fukurou.process.HybsProcess"             , new AttKeySet( "Process"                      ,11, "process"          ));
145                map.put( "org.opengion.fukurou.transfer.TransferExec"   , new AttKeySet( "TransferExec"         ,12, "kbExec"           ));             // 5.5.3.5 (2012/06/21)
146                map.put( "org.opengion.fukurou.transfer.TransferRead"   , new AttKeySet( "TransferRead"         ,13, "kbRead"           ));             // 5.5.3.5 (2012/06/21)
147                map.put( "org.opengion.fukurou.util.HybsTimerTask"              , new AttKeySet( "Daemon"                       ,14, "daemon"           ));             // 4.3.4.4 (2009/01/01)
148
149                map.put( "org.opengion.hayabusa.report.DBTableReport"   , new AttKeySet( "DBTableReport"        ,15, "tableReport"      ));             // 5.6.3.3 (2013/04/19)
150                map.put( "org.opengion.hayabusa.resource.CalendarData"  , new AttKeySet( "CalendarData"         ,16, "calData"          ));             // 5.6.3.3 (2013/04/19)
151                map.put( "org.opengion.hayabusa.db.DBConstValue"                , new AttKeySet( "DBConstValue"         ,17, "cnstVal"          ));             // 5.6.3.3 (2013/04/19)
152                map.put( "org.opengion.fukurou.xml.JspParserFilter"             , new AttKeySet( "JspCreate"            ,18, "jspParser"        ));             // 5.6.3.3 (2013/04/19)
153                map.put( "org.opengion.fukurou.util.ConnectIF   "               , new AttKeySet( "ConnectIF"            ,19, "connIF"           ));             // 5.6.3.3 (2013/04/19)
154        }
155
156        /**
157         * 指定の ClassDoc が、処理する属性クラスのMapに含まれている場合、
158         * その AttKeySet クラスのオブジェクトを返します。
159         * 存在しない場合、null を返します。
160         *
161         * @param       classDoc ClassDocオブジェクト
162         *
163         * @return      ClassDocに対応する AttKeySetオブジェクト
164         */
165        private static AttKeySet getAttGroupName( final ClassDoc classDoc ) {
166                if( classDoc == null ) { return null; }
167
168                String classFullName = classDoc.qualifiedName() ;
169                AttKeySet attKey = map.get( classFullName );
170                if( attKey == null ) {
171                        Type type = classDoc.superclassType();  // 親クラスタイプ
172                        if( type != null ) {
173                                attKey = getAttGroupName( type.asClassDoc() );  // 親クラス
174                        }
175
176                        if( attKey == null ) {
177                                Type[] itface = classDoc.interfaceTypes();              // 直近インターフェース
178                                for( int i=0; i<itface.length; i++ ) {
179                                        attKey = getAttGroupName( itface[i].asClassDoc() );
180                                        if( attKey != null ) { break; }
181                                }
182                        }
183                }
184                return attKey;
185        }
186
187        /**
188         * カスタムオプションを使用するドックレットの必須メソッド optionLength(String) です。
189         *
190         * ドックレットに認識させる各カスタムオプションに、 optionLength がその
191         * オプションを構成する要素 (トークン) の数を返さなければなりません。
192         * このカスタムオプションでは、 -tag オプションそのものと
193         * その値の 2 つの要素で構成されるので、作成するドックレットの
194         * optionLengthメソッドは、 -tag オプションに対して 2 を返さなくては
195         * なりません。また、認識できないオプションに対しては、0 を返します。
196         *
197         * @param option オプション文字列
198         *
199         * @return 要素 (トークン) の数
200         */
201        public static int optionLength( final String option ) {
202                if("-version".equalsIgnoreCase(option)) {
203                        return 2;
204                }
205                else if("-outfile".equalsIgnoreCase(option)) {
206                        return 2;
207                }
208                return 0;
209        }
210}