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     */
016    package org.opengion.fukurou.process;
017    
018    import org.opengion.fukurou.util.Argument;
019    import org.opengion.fukurou.util.HybsEntry ;
020    import org.opengion.fukurou.xml.XSLT;
021    import org.opengion.fukurou.util.LogWriter;
022    
023    import java.util.Map ;
024    import java.util.LinkedHashMap ;
025    import java.io.File;
026    
027    /**
028     * XSLT変換結果を指定ã?ファイルに出力しますã?
029     *
030     * Process_XSLT は、AbstractProcess を継承した、ChainProcess インターフェース
031     * の実è£?‚¯ラスですã?
032     * 上æµ?プロセスチェインのãƒ??タは上流から渡されますã?)からのLineModel の
033     * ファイルオブジェクトに対して、指定ã? XSL ファイルを適用して、XSL変換を行いますã?
034     * 出力結果は、ファイル、またã? 標準å?力に出力できますã?
035     *
036     * 上流ã?ロセスでは、Name 属æ?として、ã?File』を持ち、å?は、Fileオブジェクãƒ?
037     * である、Process_FileSearch を使用するのがã?便利ですã?それ以外ã?クラスã‚?
038     * 使用する場合でもã?Name属æ?と、File オブジェクトを持つ LineModel を受け渡ã�?
039     * できれば、使用可能ですã?
040     *
041     * -param_XXXX=固定å? を使用して、XSLTにパラメータを設定できますã?
042     *
043     * それ以外では、org.opengion.fukurou.xml.XSLT で、å?力ファイルæƒ??の設定が可能に
044     * なってã�?‚‹為、å?部æƒ??を使用するかどã�?�‹ -useFileInfo を指定できますã?
045     * -useFileInfo=true とセãƒ?ƒˆすると、以下ã??”é?目がå?部çš?�«セãƒ?ƒˆされますã?
046     *
047     * 入力ファイル(inXMLのフルパス)     : FILEPATH  (ä¾? G:\webapps\gf\jsp\DOC10\query.jsp)
048     * 入力親フォルãƒ?inXMLの親フォルãƒ? : ADDRESS   (ä¾? DOC10)
049     * 入力ファイル(inXMLのファイルå�?   : FILENAME  (ä¾? query.jsp)
050     * 入力ファイル(inXMLの更新日ä»? )   : MODIFIED  (ä¾? yyyyMMddHHmmss形å¼?
051     *
052     * xsl ファイルでは、xsl:param で宣è¨?�—、xsl:value-of で取り出しますã?
053     * <xsl:param name="ADDRESS" select="" /> と宣è¨?�—ておき、å¿?¦�なç®?‰€で
054     * <xsl:value-of select="$ADDRESS"     /> とすれば、取得できますã?
055     *
056     * 引数æ–?­—å?中にスペã?スを含ã‚??合ã?、ダブルコーãƒ??ション("") で括って下さã�??
057     * 引数æ–?­—å?の ã€?』ã?前後には、スペã?スは挟めません。å¿?�šã€?key=value の様に
058     * 繋げてくださいã€?
059     *
060     * @og.formSample
061     *  Process_XSLT -xslfile=xslファイル -outfile=OUTFILE -append=true
062     *
063     *    -xslfile=xslファイル        ?š変換を行う XSLファイル
064     *   [-outfile=出力ファイルå�?  ] ?š変換結果の出力ファイルå�?
065     *   [-append=[false/true]      ] ?šå?力ファイルをã?追記すã‚?true)か新規作æ?する(false)ã�?
066     *   [-useFileInfo=[false/true] ] ?šå?力ファイルæƒ??をã?XSLTのパラメータにセãƒ?ƒˆする(true)かしなã�?�‹(false)ã�?
067     *   [-addROWSET=ãƒ??ブルå�?    ] ?šã?ãƒ?ƒ€ー/フッターに ROWSET を追記しますã?
068     *   [-headerXX=ヘッãƒ??æ–?­—å?  ] ?šå?力ファイルに、ã?ãƒ?ƒ€ーæ–?­—å?を追記しますã?
069     *                                         添えå­?XX)が異なれã?è¤?•°のヘッãƒ??が指定できますã?
070     *   [-footerXX=フッターæ–?­—å?  ] ?šå?力ファイルに、フãƒ?‚¿ーæ–?­—å?を追記しますã?
071     *                                         添えå­?XX)が異なれã?è¤?•°のフッターが指定できますã?
072     *   [-param_XXXX=固定å?        ] ??param_SYSTEM_ID=GE
073     *                                    XSLパã?サーに対して、paramater を設定しますã?
074     *                                    キーが異なれã?、è¤?•°のパラメータを指定できますã?
075     *   [ -errAbend=[true/false]   ] ?š異常発生時に、å?ç�?‚’中断(true)するかã?継ç¶?false)するかをæŒ?®šすã‚?初期値:true[中断する])
076     *   [ -errXmlIn=[false/true]   ] ?š異常発生時に、å?力ファイルに、XML形式でエラーを追記するかを指定すã‚?初期値:false[使用しない])
077     *   [ -jspInclude=[true/false] ] ?šjsp:directive.include 発見時に、そのファイルã‚?INCLUDE するかをæŒ?®šすã‚?初期値:true[使用する])
078     *   [ -realPath=実際の実行環å¢?] ?šjspInclude="true" 時にã€?jsp/common/以下ã?ファイルの取得å?を指定しまã�?初期値:null)
079     *   [ -display=[false/true]    ] ?š結果を標準å?力に表示する(true)かしなã�?false)ã�?初期値:false[表示しない])
080     *   [ -debug=[false/true]      ] ?šデバッグæƒ??を標準å?力に表示する(true)かしなã�?false)ã�?初期値:false[表示しない])
081     *
082     * @version  4.0
083     * @author   Kazuhiko Hasegawa
084     * @since    JDK5.0,
085     */
086    public class Process_XSLT extends AbstractProcess implements ChainProcess {
087            private static final String PARAM_KEY   = "param_" ;
088            private static final String HEADER_KEY  = "header" ;
089            private static final String FOOTER_KEY  = "footer" ;
090            private static final String FILE_KEY    = "File";
091    
092            private static final String HEADER_XML    = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" ;
093            private static final String HEADER_ROWSET = "<ROWSET tableName=\"TABLENAME\">" ;
094            private static final String FOOTER_ROWSET = "</ROWSET>" ;
095    
096            private XSLT            xslt            = null ;
097            private HybsEntry[]     footerEntry     = null;
098            private String          xslfile         = null ;
099            private String          outfile         = null ;
100            private boolean         errAbend        = true;         // 中断する
101            private boolean         errXmlIn        = false;        // エラーXML形å¼?
102            private boolean         jspInclude      = true;         // 4.2.3.0 (2008/05/26)
103            private String          realPath        = null ;        // 5.7.6.2 (2014/05/16) 追åŠ?
104            private boolean         display         = false;        // 表示しなã�?
105            private boolean         debug           = false;        // 5.7.3.0 (2014/02/07) ãƒ?ƒ�ãƒ?‚°æƒ??
106    
107            private int             clmNo           = -1;
108            private int             inCount         = 0;
109            private int             errCount        = 0;
110            private String  tableName       = null;
111    
112            private static final Map<String,String> mustProparty   ;          // ?»プロパティ?½å¿??チェãƒ?‚¯用 Map
113            private static final Map<String,String> usableProparty ;          // ?»プロパティ?½整合æ?チェãƒ?‚¯ Map
114    
115            static {
116                    mustProparty = new LinkedHashMap<String,String>();
117                    mustProparty.put( "xslfile",    "変換を行う XSLファイル(å¿??)" );
118    
119                    usableProparty = new LinkedHashMap<String,String>();
120                    usableProparty.put( "outfile",          "変換結果の出力ファイルå�? );
121                    usableProparty.put( "append",           "出力ファイルをã?追記すã‚?true)か新規作æ?する(false)ã�? );
122                    usableProparty.put( "useFileInfo",      "入力ファイルæƒ??をã?XSLTのパラメータにセãƒ?ƒˆする(true)かしなã�?�‹(false)ã�? );
123                    usableProparty.put( "addROWSET" ,       "ヘッãƒ??/フッターに ROWSET を追記しますã?");
124                    usableProparty.put( "header",           "出力ファイルに、ã?ãƒ?ƒ€ーæ–?­—å?を追記しますã?" +
125                                                                            CR + "添えå­?XX)が異なれã?è¤?•°のヘッãƒ??が指定できますã?" );
126                    usableProparty.put( "footer",           "出力ファイルに、フãƒ?‚¿ーæ–?­—å?を追記しますã?" +
127                                                                            CR + "添えå­?XX)が異なれã?è¤?•°のヘッãƒ??が指定できますã?" );
128                    usableProparty.put( "param_",           "XSLパã?サーに対して、paramater を設定しますã?" +
129                                                                            CR + "キーが異なれã?、è¤?•°のパラメータを指定できますã?" +
130                                                                            CR + "ä¾? -param_SYSTEM_ID=GE" );
131                    usableProparty.put( "errAbend", "異常発生時に、å?ç�?‚’中断(true)するかã?継ç¶?false)するã�? +
132                                                                            CR + "(初期値:true:中断する)" );
133                    usableProparty.put( "errXmlIn", "異常発生時に、å?力ファイルに、XML形式でエラーを追記するかを指定すã‚? +
134                                                                            CR + "(初期値:false:使用しなã�?" );
135                    usableProparty.put( "jspInclude","jsp:directive.include 発見時に、そのファイルã‚?INCLUDE するかをæŒ?®šすã‚? +
136                                                                            CR + "(初期値:true:使用する)" );
137                    usableProparty.put( "realPath","jspInclude=\"true\" 時にã€?jsp/common/以下ã?ファイルの取得å?を指定しますã?" +
138                                                                            CR + "(初期値:null)" );          // 5.7.6.2 (2014/05/16) 追åŠ?
139                    usableProparty.put( "display",  "結果を標準å?力に表示する(true)かしなã�?false)ã�? +
140                                                                            CR + "(初期値:false:表示しなã�?" );
141                    usableProparty.put( "debug",    "ãƒ?ƒ�ãƒ?‚°æƒ??を標準å?力に表示する(true)かしなã�?false)ã�? +
142                                                                            CR + "(初期値:false:表示しなã�?" );                // 5.7.3.0 (2014/02/07) ãƒ?ƒ�ãƒ?‚°æƒ??
143            }
144    
145            /**
146             * ãƒ?ƒ•ォルトコンストラクターã€?
147             * こã?クラスは、動çš?½œæ?されますã?ãƒ?ƒ•ォルトコンストラクターでã€?
148             * super クラスに対して、å¿?¦�な初期化を行っておきますã?
149             *
150             */
151            public Process_XSLT() {
152                    super( "org.opengion.fukurou.process.Process_XSLT",mustProparty,usableProparty );
153            }
154    
155            /**
156             * プロセスの初期化を行いますã?初めにä¸?º¦ã�?�‘、呼び出されますã?
157             * 初期処ç�?ファイルオープンã€?¼¤?¢オープンç­?に使用しますã?
158             *
159             * @og.rev 4.2.3.0 (2008/05/26) jsp:directive.include 処ç�??実施可否を引数æŒ?®šしますã?
160             * @og.rev 5.7.6.2 (2014/05/16) realPath 引数を追åŠ?�—ますã?
161             *
162             * @param   paramProcess ãƒ??タベã?スの接続å?æƒ??などを持ってã�?‚‹オブジェクãƒ?
163             */
164            public void init( final ParamProcess paramProcess ) {
165                    Argument arg = getArgument();
166    
167                    xslfile                         = arg.getProparty( "xslfile" );
168                    outfile                         = arg.getProparty( "outfile" );
169                    tableName                       = arg.getProparty( "addROWSET" );
170                    boolean isAppend        = arg.getProparty( "append",false );
171                    boolean useFileInfo     = arg.getProparty( "useFileInfo",false );
172                    HybsEntry[] paramEntry  = arg.getEntrys( PARAM_KEY );           // 配å?
173                    HybsEntry[] headerEntry = arg.getEntrys( HEADER_KEY );          // 配å?
174                    footerEntry                     = arg.getEntrys( FOOTER_KEY );                  // 配å?
175                    errAbend                        = arg.getProparty("errAbend",errAbend);
176                    errXmlIn                        = arg.getProparty("errXmlIn",errXmlIn);
177                    jspInclude                      = arg.getProparty("jspInclude",jspInclude);             // 4.2.3.0 (2008/05/26) 追åŠ?
178                    realPath                        = arg.getProparty("realPath"  ,realPath);               // 5.7.6.2 (2014/05/16) 追åŠ?
179                    display                         = arg.getProparty("display",display);
180                    debug                           = arg.getProparty("debug",debug);                               // 5.7.3.0 (2014/02/07) ãƒ?ƒ�ãƒ?‚°æƒ??
181    
182                    if( outfile != null ) {
183                            File file = new File( outfile );                // 5.5.2.6 (2012/05/25) findbugs対å¿?
184                            File dir = file.getParentFile() ;
185    
186                            // 親ãƒ?‚£レクトリを示さなã�??合ã? null 。ディレクトリが存在しなã�??かつ、ディレクトリが作æ?できなã�??合ã?処ç�?
187                            if( dir != null && ! dir.exists() && ! dir.mkdirs() ) {
188                                    String errMsg = "ãƒ?‚£レクトリが作æ?できませんでしたã€?" + dir + "]" ;
189                                    throw new RuntimeException( errMsg );
190                            }
191                    }
192                    else {
193                            // 出力å?ファイル名が、指定されてã�?�ªã�??å�?
194                            String errMsg = "outfile が指定されてã�?�¾せんã€?;
195                            throw new RuntimeException( errMsg );
196                    }
197    
198                    xslt = new XSLT();
199    
200                    xslt.setOutFile( outfile,isAppend );
201                    xslt.setXslFile( xslfile );
202                    xslt.setParamEntry( paramEntry );
203                    xslt.useFileInfo( useFileInfo );
204                    xslt.errClose( errAbend );                      // エラー時に出力ファイルを閉じるかどã�?�‹ã€?
205                    xslt.useErrXmlIn( errXmlIn );           // エラー時にXML形式で出力ファイルに追記するかどã�?�‹ã€?
206                    xslt.jspInclude( jspInclude );          // 4.2.3.0 (2008/05/26) jsp:directive.include するかどã�?�‹
207                    xslt.setRealPath( realPath );           // 5.7.6.2 (2014/05/16) realPath 引数を追åŠ?�—ますã?
208    
209                    if( tableName != null ) {
210                            xslt.setOutData( HEADER_XML );
211                            xslt.setOutData( HEADER_ROWSET.replace( "TABLENAME",tableName ) );
212                    }
213    
214                    int size   = headerEntry.length;
215                    for( int i=0; i<size; i++ ) {
216                            xslt.setOutData( headerEntry[i].getValue() );
217                    }
218            }
219    
220            /**
221             * 引数の LineModel をå?ç�?�™るメソãƒ?ƒ‰ですã?
222             * 変換処ç�?¾Œã? LineModel を返しますã?
223             * 後続å?ç�?‚’行わなã�??å�?ãƒ??タのフィルタリングを行う場å�?はã€?
224             * null ãƒ??タを返しますã?つまりã?null ãƒ??タは、後続å?ç�?‚’行わなã�?
225             * フラグの代わりにも使用してã�?�¾すã?
226             * なおã?変換処ç�?¾Œã? LineModel と、オリジナルの LineModel がã?
227             * 同ä¸?�‹、コピã?(クローン)かã?、各処ç�?ƒ¡ソãƒ?ƒ‰å†?�§決めてã�?�¾すã?
228             * ドキュメントに明記されてã�?�ªã�??合ã?、副作用が問題になるå?合ã?ã€?
229             * å�??ç�?�”とに自åˆ?�§コピã?(クローン)して下さã�??
230             *
231             * @param   data        オリジナルのLineModel
232             *
233             * @return      処ç�?¤‰換後ã?LineModel
234             */
235            public LineModel action( final LineModel data ) {
236                    inCount++ ;
237                    if( display ) { println( data.dataLine() ); }
238                    if( clmNo < 0 ) { clmNo = data.getColumnNo( FILE_KEY ); }
239                    File file = (File)data.getValue( clmNo );
240    
241                    if( ! file.isFile() ) { return data; }
242    
243                    String filePath = file.getPath();
244    
245                    try {
246                            if( debug ) { println( filePath ); }                    // 5.7.3.0 (2014/02/07) ãƒ?ƒ�ãƒ?‚°æƒ??
247                            xslt.transform( filePath );
248                    }
249                    catch( RuntimeException ex ) {
250                            errCount++ ;
251                            if( errAbend ) { throw ex; }
252                            else {
253                                    logging( ex.getMessage() );
254                                    logging( "xslfile  = " + xslfile );
255                                    logging( "outfile  = " + outfile );
256                                    logging( "xmlFile  = " + filePath );
257                            }
258                    }
259    
260                    return data ;
261            }
262    
263            /**
264             * プロセスの終äº?‚’行いますã?æœ?¾Œにä¸?º¦ã�?�‘、呼び出されますã?
265             * 終äº??ç�?ファイルクローズã€?¼¤?¢クローズç­?に使用しますã?
266             *
267             * @param   isOK トã?タルで、OKã�?�£たかどã�?�‹[true:成功/false:失敗]
268             */
269            public void end( final boolean isOK ) {
270                    if( xslt != null ) {
271                            if( isOK ) {
272                                    int size = footerEntry.length;
273                                    for( int i=0; i<size; i++ ) {
274                                            xslt.setOutData( footerEntry[i].getValue() );
275                                    }
276                                    if( tableName != null ) {
277                                            xslt.setOutData( FOOTER_ROWSET );
278                                    }
279                            }
280                            xslt.close();
281                    }
282            }
283    
284            /**
285             * プロセスの処ç�?µ�果のレポã?ト表現を返しますã?
286             * 処ç�??ログラãƒ?��、å?力件数、å?力件数などのæƒ??ですã?
287             * こã?æ–?­—å?をそのまま、標準å?力に出すことで、結果レポã?トと出来るよã�?�ª
288             * 形式で出してくださいã€?
289             *
290             * @return   処ç�?µ�果のレポã?ãƒ?
291             */
292            public String report() {
293                    String report = "[" + getClass().getName() + "]" + CR
294                                    + TAB + "XSL File   : " + xslfile   + CR
295                                    + TAB + "OUT File   : " + outfile   + CR
296                                    + TAB + "Table Name : " + tableName + CR
297                                    + TAB + "File Count : " + inCount   + CR
298                                    + TAB + "Err  Count : " + errCount ;
299    
300                    return report ;
301            }
302    
303            /**
304             * こã?クラスの使用方法を返しますã?
305             *
306             * @return      こã?クラスの使用方æ³?
307             */
308            public String usage() {
309                    StringBuilder buf = new StringBuilder();
310    
311                    buf.append( "XSLT変換結果を指定ã?ファイルに出力しますã?"                                                                       ).append( CR );
312                    buf.append( CR );
313                    buf.append( "Process_XSLT は、AbstractProcess を継承した、ChainProcess インターフェース"     ).append( CR );
314                    buf.append( "の実è£?‚¯ラスですã?"                                                                                                                  ).append( CR );
315                    buf.append( "上æµ?プロセスチェインのãƒ??タは上流から渡されますã?)からのLineModel の"            ).append( CR );
316                    buf.append( "ファイルオブジェクトに対して、指定ã? XSL ファイルを適用して、XSL変換ã‚?                ).append( CR );
317                    buf.append( "行いますã?出力結果は、ファイル、またã? 標準å?力に出力できますã?"                              ).append( CR );
318                    buf.append( CR );
319                    buf.append( "上流ã?ロセスでは、Name 属æ?として、ã?File』を持ち、å?は、Fileオブジェクãƒ?            ).append( CR );
320                    buf.append( "である、Process_FileSearch を使用するのがã?便利ですã?それ以外ã?クラスã‚?           ).append( CR );
321                    buf.append( "使用する場合でもã?Name属æ?と、File オブジェクトを持つ LineModel を受け渡ã�?  ).append( CR );
322                    buf.append( "できれば、使用可能ですã?"                                                                                                            ).append( CR );
323                    buf.append( CR );
324                    buf.append( "-param_XXXX=固定å? を使用して、XSLTにパラメータを設定できますã?"                          ).append( CR );
325                    buf.append( CR );
326                    buf.append( "それ以外では、org.opengion.fukurou.xml.XSLT で、å?力ファイルæƒ??の設定が可能に"           ).append( CR );
327                    buf.append( "なってã�?‚‹為、å?部æƒ??を使用するかどã�?�‹ -useFileInfo を指定できますã?"              ).append( CR );
328                    buf.append( "-useFileInfo=true とセãƒ?ƒˆすると、以下ã??”é?目がå?部çš?�«セãƒ?ƒˆされますã?"           ).append( CR );
329                    buf.append( CR );
330                    buf.append( "入力ファイル(inXMLのフルパス)     : FILEPATH  (ä¾? G:/temp/DOC10/query.jsp)"   ).append( CR );
331                    buf.append( "入力親フォルãƒ?inXMLの親フォルãƒ? : ADDRESS   (ä¾? DOC10)"                                              ).append( CR );
332                    buf.append( "入力ファイル(inXMLのファイルå�?   : FILENAME  (ä¾? query.jsp)"                                 ).append( CR );
333                    buf.append( "入力ファイル(inXMLの更新日ä»? )   : MODIFIED  (ä¾? yyyyMMddHHmmss形å¼?"                ).append( CR );
334                    buf.append( CR );
335                    buf.append( "xsl ファイルでは、xsl:param で宣è¨?�—、xsl:value-of で取り出しますã?"                      ).append( CR );
336                    buf.append( "<xsl:param name=\"ADDRESS\" select=\"\" /> と宣è¨?�—ておき、å¿?¦�なç®?‰€で"         ).append( CR );
337                    buf.append( "<xsl:value-of select=\"$ADDRESS\"     /> とすれば、取得できますã?"                                ).append( CR );
338                    buf.append( CR );
339                    buf.append( "引数æ–?­—å?中に空白を含ã‚??合ã?、ダブルコーãƒ??ション(\"\") で括って下さã�??" ).append( CR );
340                    buf.append( "引数æ–?­—å?の ã€?』ã?前後には、空白は挟めません。å¿?�šã€?key=value の様に"             ).append( CR );
341                    buf.append( "繋げてくださいã€?                                                                                                                              ).append( CR );
342                    buf.append( CR ).append( CR );
343    
344                    buf.append( getArgument().usage() ).append( CR );
345    
346                    return buf.toString();
347            }
348    
349            /**
350             * こã?クラスは、main メソãƒ?ƒ‰から実行できませんã€?
351             *
352             * @param       args    コマンド引数配å?
353             */
354            public static void main( final String[] args ) {
355                    LogWriter.log( new Process_XSLT().usage() );
356            }
357    }