    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.hayabusa.taglib;
    017
    018import org.opengion.hayabusa.common.HybsSystem;
    019import org.opengion.hayabusa.common.HybsSystemException;
    020import org.opengion.hayabusa.db.DBTableModel;
    021import org.opengion.hayabusa.develop.JspCreateFactory;
    022import org.opengion.hayabusa.develop.JspConvertEntity;
    023import org.opengion.fukurou.util.ErrorMessage;
    024import org.opengion.fukurou.util.StringUtil;
    025import static org.opengion.fukurou.util.StringUtil.nval ;
    026import org.opengion.fukurou.xml.JspSaxParser;
    027
    028import java.util.Map;
    029import java.util.HashMap;
    030import java.util.List;
    031import java.util.ArrayList;
    032import java.util.Locale ;
    033
    034import java.io.File;
    035import java.io.ObjectOutputStream;
    036import java.io.ObjectInputStream;
    037import java.io.IOException;
    038
    039/**
    040 * JspCreateTag は、画面定義情報より、JSP画面を自動作成するツールです。
    041 *
    042 * 画面作成するにあたり、３箇所の参照元が存在します。
    043 *
    044 *   １．画面属性の設定 ： 雛形   → 仮画面   ・・・ hpgid で指定の画面ID
    045 *   ２．仮画面修正     ： 仮画面 → 仮画面   ・・・ jsp/customUserDef/画面ID
    046 *   ３．本環境修正     ： 本画面 → 本画面   ・・・ jsp/画面ID
    047 *
    048 * それぞれ、作成先の画面IDフォルダが存在する場合は、取込元を作成先に設定します。
    049 * つまり、一度作成すると、それ以降は、作成された画面を基準に処理を行います。
    050 *
    051 * @og.formSample
    052 * ●形式：&lt;og:jspCreate outdir="…" pgid="…" /&gt;
    053 * ●body：なし
    054 *
    055 * ●Tag定義：
    056 *   &lt;og:jspCreate
    057 *       pgid             ○【TAG】プログラムIDを指定します(必須)。
    058 *       outdir             【TAG】作成先のディレクトリを指定します
    059 *       hpgid              【TAG】雛形のプログラムIDを指定します
    060 *       useUserDef         【TAG】仮環境を使用するかどうか[true/false]を指定します(初期値:true:使用する)
    061 *       tagNames           【TAG】処理を行うタグを部分指定します(初期値:内部登録タグすべて)
    062 *       tableId            【TAG】(通常は使いません)DBTableModel が登録されているメモリのキーを指定します
    063 *       scope              【TAG】キャッシュする場合のスコープ[request/page/session/applicaton]を指定します(初期値:session)
    064 *       debug              【TAG】デバッグ情報を出力するかどうか[true/false]を指定します(初期値:false)
    065 *   /&gt;
    066 *
    067 * ●使用例
    068 *    ・先に、query タグでDBTableModel が作成済み
    069 *          &lt;og:jspCreate
    070 *              outdir      = "{&#064;SYS.REAL_PATH}jsp/"    ：出力先フォルダ
    071 *              pgid        = "{&#064;PGID}"                 ：作成画面ID
    072 *              hpgid       = "{&#064;HPGID}"                ：雛形画面ID
    073 *              useUserDef  = "true/false"                   ：仮環境の使用可否(初期値:true 使用する)
    074 *          /&gt;
    075 *
    076 * @og.group 開発補助
    077 * @og.rev 5.1.9.0 (2010/08/01) 新規作成
    078 *
    079 * @version  0.9.0  2000/10/17
    080 * @author   Kazuhiko Hasegawa
    081 * @since    JDK1.6,
    082 */
    083public class JspCreateTag extends CommonTagSupport {
    084        //* このプログラムのVERSION文字列を設定します。   {@value} */
    085        private static final String VERSION = "5.6.8.0 (2013/09/06)" ;
    086
    087        private static final long serialVersionUID = 568020130906L ;    // 5.6.8.0 (2013/09/06)
    088
    089//      private static final String ENCODE = "UTF-8" ;
    090
    091//      private static String JSP_DIR = "C:/opengion/uap/webapps/gf/jsp/";
    092        private static String JSP_DIR = HybsSystem.sys( "REAL_PATH" ) + "jsp/" ;
    093
    094        private static final String CUST_DEF = "customUserDef/" ;
    095
    096        private transient DBTableModel  table   = null;
    097
    098        private String          tableId         = HybsSystem.TBL_MDL_KEY;
    099        private String          outdir          = JSP_DIR;                                              // 出力先フォルダ
    100        private String          pgid            = null;                                                 // 作成画面ID
    101        private String          hpgid           = null;                                                 // 雛形画面ID
    102        private String[]        tagNames        = null;                                                 // 5.6.8.0 (2013/09/06) 処理を行うタグを部分指定
    103        private boolean         useUserDef      = true;                                                 // 仮環境の使用可否(初期値:true 使用する)
    104
    105//      private static final String[] JCF_LIST = new String[] { "COMMENT" , "COLUMN" , "ORDER_BY" , "QUERY" , "VIEW" , "TABLE_UPDATE" };
    106        private static final String[] JCF_LIST = new String[] { "COMMENT" , "HIDEMENU" , "COLUMN" , "ORDER_BY" , "QUERY" , "VIEW" , "TABLE_UPDATE" };   // 5.6.4.4 (2013/05/31)
    107
    108        /**
    109         * Taglibの開始タグが見つかったときに処理する doStartTag() を オーバーライドします。
    110         *
    111         * @return      後続処理の指示(SKIP_BODY)
    112         */
    113        @Override
    114        public int doStartTag() {
    115                table = (DBTableModel)getObject( tableId );
    116
    117                return(SKIP_BODY);                              // Body を評価しない
    118//              return ( EVAL_BODY_BUFFERED );  // Body を評価する
    119        }
    120
    121        /**
    122         * Taglibのタグ本体を処理する doAfterBody() を オーバーライドします。
    123         *
    124         * @return      int
    125         */
    126//      @Override
    127//      public int doAfterBody() {
    128//              body = nval( getBodyString(),body );
    129//
    130//              return(SKIP_BODY);
    131//      }
    132
    133        /**
    134         * Taglibの終了タグが見つかったときに処理する doEndTag() を オーバーライドします。
    135         *
    136         * @return      後続処理の指示
    137         */
    138        @Override
    139        public int doEndTag() {
    140                // デバッグ時には、オブジェクト内部情報を表示する。
    141                if( isDebug() ) {
    142                        debugPrint();
    143                }
    144
    145                boolean okFlag = execute();
    146
    147                if( okFlag )  {         // 正常
    148                        return(EVAL_PAGE);
    149                }
    150                else {
    151                        return(SKIP_PAGE);
    152                }
    153        }
    154
    155        /**
    156         * タグリブオブジェクトをリリースします。
    157         * キャッシュされて再利用されるので、フィールドの初期設定を行います。
    158         *
    159         * @og.rev 5.6.8.0 (2013/09/06) tagNames 追加
    160         */
    161        @Override
    162        protected void release2() {
    163                super.release2();
    164                table           = null;
    165                tableId         = HybsSystem.TBL_MDL_KEY;
    166                outdir          = JSP_DIR;
    167                pgid            = null;
    168                hpgid           = null;
    169                useUserDef      = true;
    170                tagNames        = null;                                                 // 5.6.8.0 (2013/09/06) 処理を行うタグを部分指定
    171        }
    172
    173        /**
    174         * DBTableModel処理を実行します。
    175         *
    176         * @og.rev 5.2.1.0 (2010/10/01) 実行クラスのクラス名を変更します。 _OG_ を削除
    177         * @og.rev 5.5.2.6 (2012/05/25) findbugs対応。JspConvertEntity.DBKEY を、JspConvertEntity.getDBKEY() に変更。
    178         * @og.rev 5.6.8.0 (2013/09/06) 処理対象タグの部分指定対応 (tagNames 追加)
    179         *
    180         * @return      処理の実行結果
    181         */
    182        public boolean execute() {
    183                boolean okFlag = false;
    184
    185                // 出力先(セーブ先)のフォルダ
    186                File saveDir = (useUserDef) ? new File( outdir + CUST_DEF , pgid ) : new File( outdir , pgid ) ;
    187
    188                // 雛形(参照元)のフォルダ
    189                final File refDir ;
    190                if( saveDir.exists() ) {                // 出力先フォルダが存在した場合
    191                        refDir = saveDir ;                      // 出力先フォルダが、雛形フォルダになる。
    192                }
    193                else {                                                  // 出力先フォルダが存在しない場合
    194                        refDir = new File( outdir , hpgid );                    // 雛形画面IDをそのまま使用します。
    195                        if( ! saveDir.mkdirs() ) {
    196                                String errMsg = "出力先のフォルダが作成できませんでした。[" + saveDir + "]" ;
    197                                throw new HybsSystemException( errMsg );
    198                        }
    199                }
    200
    201                if( ! refDir.exists() ) {       // 雛形(参照元)フォルダが存在しない場合、エラー
    202                        String errMsg = "雛形(参照元)フォルダが存在しません。[" + refDir + "]" ;
    203                        throw new HybsSystemException( errMsg );
    204                }
    205
    206//              PrintWriter writer = null;
    207
    208//              int[] clmNo = getTableColumnNo( JspConvertEntity.DBKEY );
    209                int[] clmNo = getTableColumnNo( JspConvertEntity.getDBKEY() );          // 5.5.2.6 (2012/05/25) findbugs対応
    210                int rowCnt  = table.getRowCount();
    211
    212                int row = 0;
    213                boolean unCmntSet = true;
    214                String[] data = null;
    215                try {
    216                        //JSPを書く為に必要な情報を設定
    217                        Map<String,List<JspConvertEntity>> tables = new HashMap<String,List<JspConvertEntity>>();
    218
    219                        for( row=0; row<rowCnt; row++ ) {
    220                                data = table.getValues( row );
    221                                JspConvertEntity entry = JspConvertEntity.newInstance( data, clmNo );
    222
    223                                if( entry != null ) {
    224                                        List<JspConvertEntity> array = tables.get( entry.getType() );
    225                                        if( array == null ) { array = new ArrayList<JspConvertEntity>(); }
    226                                        array.add( entry );
    227                                        tables.put( entry.getType(),array );
    228                                        if( unCmntSet ) {
    229                                                tables.put( "COMMENT",array );
    230                                                unCmntSet = false;
    231                                        }
    232                                }
    233                        }
    234
    235                        // 参照先フォルダから、出力先フォルダに、XMLコピー処理を行います。
    236                        JspSaxParser spar = new JspSaxParser();
    237
    238                        // 5.2.1.0 (2010/10/01) 実行クラスのクラス名を変更します。 _OG_ を削除
    239//                      spar.addFilter( JspCreateFactory.newInstance( "COMMENT" ,tables) );
    240//                      spar.addFilter( JspCreateFactory.newInstance( "COLUMN"  ,tables) );
    241//                      spar.addFilter( JspCreateFactory.newInstance( "SELECT"  ,tables) );
    242//                      spar.addFilter( JspCreateFactory.newInstance( "QUERY"   ,tables) );
    243//                      spar.addFilter( JspCreateFactory.newInstance( "VIEW"    ,tables) );
    244
    245                        // 5.6.8.0 (2013/09/06) 処理対象タグの部分指定対応 (tagNames 追加)
    246                        if( tagNames == null ) { tagNames = JCF_LIST; }
    247//                      for( String jcf : JCF_LIST ) {
    248                        for( String jcf : tagNames ) {
    249                                spar.addFilter( JspCreateFactory.newInstance( jcf , tables ) );
    250                        }
    251
    252                        spar.copyDirectry( refDir,saveDir );
    253
    254//                      //query.jsp作成
    255//                      writer = FileUtil.getPrintWriter( new File( saveDir,"query.jsp" ),ENCODE );
    256//                      writer.print(writeQueryJSP( refDir , tables  ));
    257//                      writer.println();
    258//                      writer.flush();
    259//
    260//                      //result.jsp作成
    261//                      writer = FileUtil.getPrintWriter( new File( saveDir,"result.jsp" ),ENCODE );
    262//                      writer.print(writeResultJSP( refDir , tables  ));
    263//                      writer.println();
    264//                      writer.flush();
    265
    266                        okFlag = true;
    267                }
    268                catch( RuntimeException ex ) {
    269                        ex.printStackTrace();
    270                        ErrorMessage errMessage = new ErrorMessage( "JspCreateTag Error" );
    271                        errMessage.addMessage( row+1,ErrorMessage.NG,"JSPOUT",ex.getMessage() );
    272                        errMessage.addMessage( row+1,ErrorMessage.NG,"JSPOUT",StringUtil.array2csv( data ) );
    273                        errMessage.addMessage( row+1,ErrorMessage.NG,"JSPOUT","PRGID=[" + pgid + "]" );
    274                        // BAT から呼び出す場合があるため、標準エラー出力にも情報を出しておきます。
    275                        System.out.println( errMessage );
    276                }
    277//              finally {
    278//                      Closer.ioClose( writer );
    279//              }
    280
    281                return okFlag;
    282        }
    283
    284        /**
    285         * query.jspファイルの内容を生成します。
    286         *
    287         * @param refDir
    288         * @param tables
    289         *
    290         * @return 生成した内容
    291         */
    292//      private String writeQueryJSP( File refDir , HashMap<String , ArrayList<JspConvertEntity>> tables ) {
    293//              String jsp = "";
    294//              try{
    295//                      //利用する生成クラスを設定
    296//                      HashMap< String , JspCreate > generates = new HashMap< String , JspCreate >();
    297//                      generates.put( "og:comment"     , JspCreateFactory.newInstance( "OG_COMMENT",tables) );
    298//                      generates.put( "table"          , JspCreateFactory.newInstance( "OG_COLUMN",tables) );
    299//                      generates.put( "og:select"      , JspCreateFactory.newInstance( "OG_SELECT",tables) );
    300//
    301//                      //JSPの作成処理を実施。
    302//                      JspHandler handler = new JspHandler();
    303//                      jsp = handler.generate( new File( refDir , "query.jsp" ), ENCODE , generates);
    304//
    305//              }catch(Throwable ex){
    306//                      ex.printStackTrace();
    307//                      throw new RuntimeException(ex);
    308//              }
    309//              return jsp;
    310//      }
    311
    312        /**
    313         * result.jspファイルの内容を生成します。
    314         *
    315         * @param refDir
    316         * @param tables
    317         *
    318         * @return 生成した内容
    319         */
    320//      private String writeResultJSP(File refDir , HashMap<String , ArrayList<JspConvertEntity>> tables ) {
    321//              String jsp = "";
    322//              try{
    323//                      //利用する生成クラスを設定
    324//                      HashMap< String , JspCreate > generates = new HashMap< String , JspCreate >();
    325//                      generates.put( "og:comment"     , JspCreateFactory.newInstance( "OG_COMMENT",tables) );
    326//                      generates.put( "og:query"       , JspCreateFactory.newInstance( "OG_QUERY",tables ) );
    327//                      generates.put( "og:view"        , JspCreateFactory.newInstance( "OG_VIEW",tables) );
    328//
    329//                      //JSPの作成処理を実施。
    330//                      JspHandler handler = new JspHandler();
    331//                      jsp = handler.generate( new File( refDir , "result.jsp" ) , ENCODE  , generates);
    332//
    333//              }catch(Throwable ex){
    334//                      ex.printStackTrace();
    335//                      throw new RuntimeException(ex);
    336//              }
    337//              return jsp;
    338//      }
    339
    340        /**
    341         * 【TAG】(通常は使いません)結果のDBTableModelを、sessionに登録するときのキーを指定します
    342         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY}])。
    343         *
    344         * @og.tag
    345         * 検索結果より、DBTableModelオブジェクトを作成します。これを、下流のviewタグ等に
    346         * 渡す場合に、通常は、session を利用します。その場合の登録キーです。
    347         * query タグを同時に実行して、結果を求める場合、同一メモリに配置される為、
    348         * この tableId 属性を利用して、メモリ空間を分けます。
    349         *              (初期値:HybsSystem#TBL_MDL_KEY[={@og.value org.opengion.hayabusa.common.HybsSystem#TBL_MDL_KEY}])。
    350         *
    351         * @param       id sessionに登録する時の ID
    352         */
    353        public void setTableId( final String id ) {
    354                tableId = nval( getRequestParameter( id ),tableId );
    355        }
    356
    357        /**
    358         * 【TAG】作成先のディレクトリを指定します。
    359         *
    360         * @og.tag
    361         * 作成先のディレクトリを指定します。
    362         * 初期値は、実際に実行しているアプリケーションの REAL_PATH + jsp フォルダ以下です。
    363         * 作成先のフォルダも、useUserDef の設定によって異なります。
    364         *
    365         * @param       dir     出力先のディレクトリ
    366         */
    367        public void setOutdir( final String dir ) {
    368                outdir = nval( getRequestParameter( dir ),outdir );
    369        }
    370
    371        /**
    372         * 【TAG】プログラムIDを指定します。
    373         *
    374         * @og.tag
    375         * 作成先のプログラムIDを指定します。
    376         * ただし、作成先の実際のフォルダは、useUserDef の設定によって異なります。
    377         *
    378         * @param       id      プログラムID
    379         */
    380        public void setPgid( final String id ) {
    381                pgid = nval( getRequestParameter( id ),pgid );
    382        }
    383
    384        /**
    385         * 【TAG】雛形のプログラムIDを指定します。
    386         *
    387         * @og.tag
    388         * 雛形のプログラムIDをパースして、実際のプログラムを作成します。
    389         * ただし、作成先の実際のフォルダは、useUserDef の設定によって異なります。
    390         * また、パースするのは、作成先の画面IDのフォルダが存在しない場合のみです。
    391         * すでに、存在している場合は、元の画面IDのフォルダを読み取って、パースを
    392         * 行います。基本的に、作成先のソースを手で修正した場合でも、パースと
    393         * 無関係な箇所の修正はそのまま反映のこされます。
    394         *
    395         * @param       id      雛形のプログラムID
    396         */
    397        public void setHpgid( final String id ) {
    398                hpgid = nval( getRequestParameter( id ),hpgid );
    399        }
    400
    401        /**
    402         * 【TAG】仮環境を使用するかどうか[true/false]を指定します(初期値:true:使用する)。
    403         *
    404         * @og.tag
    405         * true:使用する を設定すると、"customUserDef" フォルダの下に、画面IDの
    406         * フォルダを作成します。
    407         * false:使用しない を設定すると、実際の リアルパス(REAL_PATH/jsp)の下に、
    408         * 画面IDのフォルダを作成します。こちらは、実際の画面と同様に、画面リソース等を
    409         * 作成してアクセスすることになります。
    410         *
    411         * @param       flag    仮環境を使用するかどうか [true:使用する/false:使用しない]
    412         */
    413        public void setUseUserDef( final String flag ) {
    414                useUserDef = nval( getRequestParameter( flag ),useUserDef );
    415        }
    416
    417        /**
    418         * 【TAG】処理を行うタグを部分指定します(初期値:内部登録タグすべて)。
    419         *
    420         * @og.tag
    421         * 処理を行うタグは、内部的に、COMMENT,HIDEMENU,COLUMN,ORDER_BY,QUERY,VIEW,TABLE_UPDATE だけ
    422         * 予約されており、初期値は、すべてのタグを処理します。
    423         * ここでは、その一部のみ実行できるように、カンマ区切り文字で指定できるようにします。
    424         * 実行不可のタグ名を指定すると、エラーになります。
    425         *
    426         * @og.rev 5.6.8.0 (2013/09/06) 新規追加
    427         *
    428         * @param       tags    処理を行うタグを部分指定する。
    429         */
    430        public void setTagNames( final String tags ) {
    431                String tagNms = nval( getRequestParameter( tags ),null );
    432
    433                if( tagNms != null ) {
    434                        tagNames = tagNms.split( "," );
    435
    436                        for( int i=0; i<tagNames.length; i++ ) {
    437                                String tag = tagNames[i].trim().toUpperCase(Locale.JAPAN);
    438                                if( ! check( tag, JCF_LIST ) ) {
    439                                        String errMsg = "指定の tagNames は、下記の範囲で指定してください。"
    440                                                                        + "tagNames=" + tagNms + " (NG=" + tag + ") : "
    441                                                                        + JCF_LIST.toString();
    442                                        throw new HybsSystemException( errMsg );
    443                                }
    444                                tagNames[i] = tag ;             // 大文字に変換した値を戻す。
    445                        }
    446                }
    447        }
    448
    449        /**
    450         *  カラム名配列(String[])より、対応するカラムNo配列(int[])を作成します。
    451         *
    452         * @param       nameArray カラム名配列
    453         *
    454         * @return      カラムNo配列
    455         */
    456        private int[] getTableColumnNo( final String[] nameArray ) {
    457                int[] clmNo = new int[ nameArray.length ];
    458                for( int i=0; i<clmNo.length; i++ ) {
    459                        clmNo[i] = table.getColumnNo( nameArray[i] );
    460                }
    461                return clmNo;
    462        }
    463
    464        /**
    465         * シリアライズ用のカスタムシリアライズ書き込みメソッド
    466         *
    467         * @param       strm    ObjectOutputStreamオブジェクト
    468         * @serialData 一部のオブジェクトは、シリアライズされません。
    469         *
    470         * @throws IOException  入出力エラーが発生した場合
    471         */
    472        private void writeObject( final ObjectOutputStream strm ) throws IOException {
    473                strm.defaultWriteObject();
    474        }
    475
    476        /**
    477         * シリアライズ用のカスタムシリアライズ読み込みメソッド
    478         *
    479         * ここでは、transient 宣言された内部変数の内、初期化が必要なフィールドのみ設定します。
    480         *
    481         * @param       strm    ObjectInputStreamオブジェクト
    482         * @see #release2()
    483         * @serialData 一部のオブジェクトは、シリアライズされません。
    484         *
    485         * @throws IOException  シリアライズに関する入出力エラーが発生した場合
    486         * @throws ClassNotFoundException       クラスを見つけることができなかった場合
    487         */
    488        private void readObject( final ObjectInputStream strm ) throws IOException , ClassNotFoundException {
    489                strm.defaultReadObject();
    490        }
    491
    492        /**
    493         * このオブジェクトの文字列表現を返します。
    494         * 基本的にデバッグ目的に使用します。
    495         *
    496         * @return このクラスの文字列表現
    497         */
    498        @Override
    499        public String toString() {
    500                return org.opengion.fukurou.util.ToString.title( this.getClass().getName() )
    501                                .println( "VERSION"                     ,VERSION                )
    502                                .println( "tableId"                     ,tableId                )
    503                                .println( "outdir"                      ,outdir                 )
    504                                .println( "pgid"                        ,pgid                   )
    505                                .println( "hpgid"                       ,hpgid                  )
    506                                .println( "useUserDef"          ,useUserDef             )
    507                                .fixForm().toString() ;
    508        }
    509}