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.plugin.report; 017 018import java.io.BufferedWriter; 019import java.io.File; 020import java.io.FileNotFoundException; 021import java.io.FileOutputStream; 022import java.io.OutputStreamWriter; 023import java.io.UnsupportedEncodingException; 024import org.opengion.hayabusa.common.HybsSystemException; 025import org.opengion.hayabusa.common.HybsSystem; 026import org.opengion.hayabusa.report.AbstractCSVPrintPointService; 027import org.opengion.fukurou.util.StringUtil; 028 029/** 030 * ユニリタ「Report & Form Warehouse」に対応したCSV形式でデータを作成します。 031 * 032 * CSVはシステムリソースRFW_CSV_OUTPUTDIRで指定した場所に[LISTID]_[GRPID]_[YKNO].csvで出力されます。 033 * 又、RFWはNASに出力する場合はJOB単位にNASサーバを指定する必要があるため、出力先ディレクトリの先頭文字が「\\」 034 * となっていた際には「_NASサーバ名」を出力先ディレクトリとします。 035 * 特殊な動作として、デーモングループに"BIG"の文字が入っている場合はCSV出力先ディレクトリ末尾に"_BIG"を付加します。 036 * 2つのフォルダは予め作成しておきます。 037 * 038 * PDF等の最終的な出力先、つまりCSVのコントロールヘッダのRDSetOutputFileNameはGE50で指定します。 039 * (Defaultのプラグインと出力が異なるので注意が必要です) 040 * 041 * データに関しては、全てダブルクウォートで囲って出力されます。 042 * ダブルクウォートそのものは二重化でエスケープします。 043 * ヘッダ、フッタが存在する場合、ボディ、ヘッダ、フッタの順番に連結して出力し、カラム名はヘッダはH_、フッタはF_を先頭に追加します。 044 * 045 * 区分Excelの場合にどの文字列でヘッダーを出すかはシステムリソースRFW_EXCEL_TYPEで決めます。 046 * 指定なしの場合はXLSとなります。 047 * 区分Excel(XLSX)の場合はXLSX固定です。 048 * 049 * なお、デーモングループ名の先頭文字が*の場合には最後に約7秒待ってから終了します。 050 * (プリンタによっては並列処理に対応していない場合があるため、Excel帳票と同等まで発行速度を落とす) 051 * 052 * @og.group 帳票システム 053 * 054 * @version 5.9.0.0 055 * @author Masakazu Takahashi 056 * @since JDK6.0, 057 */ 058public class CSVPrintPointService_RFW extends AbstractCSVPrintPointService { 059 060 private static final String CR = System.getProperty("line.separator"); 061 private final StringBuilder strCSV = new StringBuilder(); // CSVはこれに吐く 062 063 private static final String csvEncode = HybsSystem.sys("REPORT_CSV_TEXT_ENCODE"); 064 065 private static final String RFW_CSV_OUTPUTDIR = HybsSystem.sys("RFW_CSV_OUTPUTDIR"); 066 067 private static final String RFW_EXCEL_TYPE = StringUtil.nval( HybsSystem.sys("RFW_EXCEL_TYPE"), "XLS" ) ; 068 069 /** 070 * 発行処理 071 * ファイル出力 072 * 073 * @og.rev 5.9.2.2 ファイル名に標準OrderBy同様にGRPIDを付ける。デーモングループに「BIG」が入っている場合は出力先変更 074 * @og.rev 5.9.6.2 (2016/03/11) RFWのNAS対応 075 * @og.rev 5.9.17.3 (2017/02/24) デーモングループの先頭文字が*の場合は最後に7秒スリープする 076 * 077 * @return 結果 [true:正常/false:異常] 078 */ 079 @Override 080 public boolean execute(){ 081 System.out.print( "CSV create ... " ); 082 BufferedWriter bw = null; 083 boolean flg = false; 084 085 try { 086 // 5.9.6.2 (2016/03/11) RFWのNAS出力対応に伴う修正 087 // outdirが\\から開始される場合に、次の\もしくは/までの文字列を出力フォルダに付け足す 088 // 5.9.6.3 (2016/03/18) かつ、outdirからはサーバ名は削除する 089 String nasName = ""; 090 if( outdir != null && outdir.startsWith( "\\\\" ) ){ 091 int spl = outdir.indexOf( "\\", 2 ); 092 int spl2 = outdir.indexOf( "/", 2 ); 093 spl = spl<0 ? outdir.length() : spl; 094 spl2 = spl2<0 ? outdir.length() : spl2; 095 spl = spl < spl2 ? spl : spl2; 096 nasName = "_" + outdir.substring( 2, spl ); 097 outdir = outdir.substring(spl+1); // 5.9.6.3 098 } 099 100 makeheader(); 101 makebody(); 102 103 104// bw = getWriter( RFW_CSV_OUTPUTDIR + File.separator + listid + "_" + ykno + ".csv" ,false,csvEncode); 105 106 // 汎用化も考えたが、予期せぬ出力があると困るのでBIG決め打ち。フォルダ存在しない場合はエラー 107 if( dmngrp != null && dmngrp.indexOf( "BIG" ) >= 0 ){ // 5.9.2.2 108// bw = getWriter( RFW_CSV_OUTPUTDIR + "_BIG" + File.separator + listid + "_" + grpid + "_" + ykno + ".csv" ,false,csvEncode); 109 bw = getWriter( RFW_CSV_OUTPUTDIR + nasName + "_BIG" + File.separator + listid + "_" + grpid + "_" + ykno + ".csv" ,false,csvEncode); // 5.9.6.2 110 } 111 else{ 112// bw = getWriter( RFW_CSV_OUTPUTDIR + File.separator + listid + "_" + grpid + "_" + ykno + ".csv" ,false,csvEncode); 113// bw = getWriter( RFW_CSV_OUTPUTDIR + File.separator + listid + "_" + grpid + "_" + ykno + ".csv" ,false,csvEncode); 114 bw = getWriter( RFW_CSV_OUTPUTDIR + nasName + File.separator + listid + "_" + grpid + "_" + ykno + ".csv" ,false,csvEncode); // 5.9.6.2 115 } 116 bw.write( strCSV.toString() ); 117 bw.flush(); 118 bw.close(); 119 120 flg = true; 121 122// if( prgfile != null && prgfile.length() > 0){ 123// makeShellCommand(); 124// flg = programRun(); 125// } 126 127 // 5.9.17.3 (2017/02/24) 先頭が*のデーモングループの場合は約7秒スリープさせる=このスレッドでの連続処理をわざと遅延させる 128 // 特殊対応なので決め打ち 129 if( dmngrp != null && dmngrp.indexOf( "*" ) == 0 ){ 130 Thread.sleep(7000); 131 } 132 133 } 134 catch ( Throwable ex ) { 135 errMsg.append( "CSV Print Request Execution Error. " ).append( CR ); 136 errMsg.append( "==============================" ).append( CR ); 137 errMsg.append( "SYSTEM_ID=[" ).append( systemId ).append( "] , " ); 138 errMsg.append( "YKNO=[" ).append( ykno ).append( "] , " ); 139 errMsg.append( ex.toString() ); 140 errMsg.append( CR ); 141// throw new RuntimeException( errMsg.toString() ); 142 throw new RuntimeException( errMsg.toString(), ex ); 143 } 144 return flg; 145 } 146 147 /** 148 * ヘッダの出力 149 * 150 * @og.rev 5.9.1.2 (2015/10/23) RDSetOutputPrinterの値をIDに変更 151 * @og.rev 5.9.3.0 (2015/12/04) option追加 152 * @og.rev 5.9.3.2 (2015/12/21) XLSX対応 153 * @og.rev 5.9.4.2 (2016/01/13) XLSXは区分に持たせるようにする 154 * @og.rev 5.9.6.0 (2016/03/01) 拡張子対応 155 */ 156 private void makeheader(){ 157 //ヘッダデータを出力する場合はここで指定する。 158 strCSV.append( "<rdstart>" ).append( CR ); 159 160 strCSV.append( "RDSetForm=\"" ).append(modelname).append("\"").append( CR ); 161 162 //5.9.3.1 (2015/12/16) 163 strCSV.append( "RDSetUserName=\"" ).append(systemId).append("\"").append( CR ); 164 strCSV.append( "RDSetComputer=\"" ).append( listid + "_" + grpid + "_" + ykno ).append("\"").append( CR ); 165 strCSV.append( "RDSetDocName=\"" ).append(listid).append("\"").append( CR ); 166 167 String suffix = ""; // 5.9.6.0 168 169 // 5.9.6.0 拡張子を自動で付ける対応を入れておく 170 // PDFの場合 171 if( FGRUN_PDF.equals( fgrun ) ){ 172 if( outdir != null && outdir.indexOf(".") < 0 ){ 173 suffix = ".pdf"; 174 } 175 176 strCSV.append( "RDSetOutputMode=PDF" ).append( CR ); 177// strCSV.append( "RDSetOutputFileName=\"" ).append( outdir ).append("\"").append( CR ); 178 strCSV.append( "RDSetOutputFileName=\"" ).append( outdir ).append( suffix ).append("\"").append( CR ); 179 } 180 // Excel(XLS) 181 else if( FGRUN_EXCEL.equals(fgrun) ){ 182 if( outdir != null && outdir.indexOf(".") < 0 ){ 183 suffix = ".xls"; 184 } 185// strCSV.append( "RDSetOutputMode=XLS" ).append( CR ); 186// if( option != null && option.indexOf("RDSetOutputMode") < 0 ){ 187 strCSV.append( "RDSetOutputMode=" + RFW_EXCEL_TYPE ).append( CR ); 188// } 189// strCSV.append( "RDSetOutputFileName=\"" ).append( outdir ).append("\"").append( CR ); 190 strCSV.append( "RDSetOutputFileName=\"" ).append( outdir ).append( suffix ).append("\"").append( CR ); 191 } 192 // Excel(XLSX) 5.9.4.2 (2016/01/13) 193 else if( FGRUN_EXCEL2.equals(fgrun) ){ 194 if( outdir != null && outdir.indexOf(".") < 0 ){ 195 suffix = ".xlsx"; 196 } 197 strCSV.append( "RDSetOutputMode=XLSX" ).append( CR ); 198// strCSV.append( "RDSetOutputFileName=\"" ).append( outdir ).append("\"").append( CR ); 199 strCSV.append( "RDSetOutputFileName=\"" ).append( outdir ).append( suffix ).append("\"").append( CR ); 200 } 201 // 印刷 202 else{ 203 strCSV.append( "RDSetOutputMode=SPOOL" ).append( CR ); 204 //strCSV.append( "RDSetOutputPrinter=\"" ).append(prtName).append( "\"" ).append( CR ); 205 // プリンタ名ではなく、プリンタIDを出力するように変更 206 strCSV.append( "RDSetOutputPrinter=\"" ).append(prtid).append( "\"" ).append( CR ); 207 } 208 209 if( option != null && option.length() > 0 ){ 210 strCSV.append( option ).append( CR ); // 5.9.3.0 (2015/12/04) 211 } 212 213 strCSV.append( "<rdend>" ).append( CR ); 214 215 //1行目にカラム名を出力します。クウォートで囲わない。 216 // メインテーブルはNULLではない 217 for( int clmNo=0; clmNo<table.getColumnCount(); clmNo++ ) { 218 // 先頭以外はカンマを付ける 219 if( clmNo > 0 ){ strCSV.append( "," ); } 220 strCSV.append( table.getColumnName( clmNo )); 221 } 222 if( tableH != null){ 223 for( int clmNo=0; clmNo<tableH.getColumnCount(); clmNo++ ) { 224 strCSV.append( "," ); 225 strCSV.append("H_").append( tableH.getColumnName( clmNo )); 226 } 227 } 228 if( tableF != null){ 229 for( int clmNo=0; clmNo<tableF.getColumnCount(); clmNo++ ) { 230 strCSV.append( "," ); 231 strCSV.append("F_").append( tableF.getColumnName( clmNo )); 232 } 233 } 234 strCSV.append( CR ); 235 } 236 237 238 239 /** 240 * 本体の出力を行います 241 * HTMLエスケープされている場合は戻します 242 * 243 * @og.rev 5.9.8.2 (2016/05/16) EOR対応 244 */ 245 private void makebody(){ 246 247 for( int rowNo=0; rowNo<table.getRowCount(); rowNo++ ) { 248 // カラム単位の処理 249 for( int clmNo=0; clmNo<table.getColumnCount(); clmNo++ ) { 250 // 先頭以外はカンマを付ける 251 if( clmNo > 0 ){ strCSV.append( "," ); } 252 // 原則全てダブルクウォートで囲う 253 // 5.9.8.2 (2016/05/16) 但し、先頭カラムが制御コードである//EOR//の場合のみ囲わない 254 if( clmNo == 0 && "//EOR//".equals( table.getValue( rowNo, clmNo )) ){ 255 strCSV.append( table.getValue( rowNo, clmNo ) ); 256 } 257 else{ 258 strCSV.append("\"").append( StringUtil.replace( StringUtil.getReplaceEscape( table.getValue( rowNo, clmNo )) ,"\"","\"\"" ) ).append("\""); 259 } 260 } 261 262 //ヘッダ、フッタは毎行に必ず付加します。 263 //例え複数行あったとしても先頭行のみ有効です 264 //ヘッダ 265 if( tableH != null){ 266 int rowNoH=0; 267 for( int clmNo=0; clmNo<tableH.getColumnCount(); clmNo++ ) { 268 // 必ずカンマを付ける 269 strCSV.append( "," ); 270 // 全てダブルクウォートで囲う 271 strCSV.append("\"").append( StringUtil.replace( StringUtil.getReplaceEscape( tableH.getValue( rowNoH, clmNo )) ,"\"","\"\"" ) ).append("\""); 272 } 273 } 274 275 //フッタ 276 if( tableF != null ){ 277 int rowNoF=0; 278 for( int clmNo=0; clmNo<tableF.getColumnCount(); clmNo++ ) { 279 // 必ずカンマを付ける 280 strCSV.append( "," ); 281 // 全てダブルクウォートで囲う 282 strCSV.append("\"").append( StringUtil.replace( StringUtil.getReplaceEscape( tableF.getValue( rowNoF, clmNo )) ,"\"","\"\"" ) ).append("\""); 283 } 284 } 285 286 strCSV.append( CR ); 287 } 288 } 289 290 291 /** 292 * ファイル書き込み用のライターを返します。 293 * 294 * @param fileName ファイル名 295 * @param append アベンドするか 296 * @param encode エンコード 297 * 298 * @return ライター 299 */ 300 private BufferedWriter getWriter( final String fileName, final boolean append, final String encode) { 301 File file = new File ( fileName ); 302 BufferedWriter bw; 303 304 try { 305 bw = new BufferedWriter( new OutputStreamWriter( new FileOutputStream( file, append ), encode ) ); 306 } 307 catch ( UnsupportedEncodingException ex ) { 308 errMsg.append( "[ERROR] Input File is written by Unsupported Encoding" ); 309 throw new HybsSystemException( ex ); 310 } 311 catch ( FileNotFoundException ex ) { 312 errMsg.append( "[ERROR] File not Found" ); 313 throw new HybsSystemException( ex ); 314 } 315 return bw; 316 } 317 318}