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.report; 017 018import org.opengion.hayabusa.common.HybsSystem; 019import org.opengion.hayabusa.common.HybsSystemException; 020import org.opengion.fukurou.util.Closer ; 021 022import org.apache.poi.poifs.filesystem.POIFSFileSystem; 023import org.apache.poi.hssf.usermodel.HSSFWorkbook; 024import org.apache.poi.hssf.usermodel.HSSFSheet; 025import org.apache.poi.hssf.usermodel.HSSFRow; 026import org.apache.poi.hssf.usermodel.HSSFCell; 027import org.apache.poi.hssf.usermodel.HSSFRichTextString; 028 029import java.io.FileInputStream; 030import java.io.FileOutputStream; 031import java.io.IOException; 032 033import java.util.regex.Pattern; 034import java.util.regex.Matcher; 035 036/** 037 * DBTableReport インターフェース を実装したネイティブEXCEL形式で出力するクラスです。 038 * AbstractDBTableReport を継承していますので,writeReport() のみオーバーライドして, 039 * 固定長文字ファイルの出力機能を実現しています。 040 * 041 * @og.group 帳票システム 042 * 043 * @version 4.0 044 * @author Kazuhiko Hasegawa 045 * @since JDK5.0, 046 */ 047public class DBTableReport_Excel extends AbstractDBTableReport { 048 049 private static final String EXCEL_FILE_EXT = ".xls"; 050 private static final Pattern PATTERN_KEY = 051 Pattern.compile("\\{@((\\w+?)(?:_(\\d+?))?)\\}", Pattern.MULTILINE); 052 053 // POIの解析した式の中に変な属性が付けられて、これを取り除く(patternExcludeInFormula) 054 private static final Pattern PATTERN_EXIN = 055 Pattern.compile("ATTR\\(semiVolatile\\)", Pattern.MULTILINE); 056 057 private HSSFWorkbook wb = null; 058 059 /** 060 * DBTableModel から データを作成して,PrintWriter に書き出します。 061 * 062 */ 063 @Override 064 public void writeReport() { 065 setHeaderFooter(); 066 initReader(); 067 initWriter(); 068 changeSheet(); 069 close(); 070 } 071 072 /** 073 * POIFSFileSystem を、初期化します。 074 * これは、雛型ファイルの終端まで読取り、処理した場合、もう一度 075 * 初めから読み込みなおす処理を行います。 076 * 基本的に、書き込みも初期化する必要があります。 077 * 078 * メモリ上に読み込んで、繰り返し利用するかどうかは、実装依存です。 079 * 080 */ 081 @Override 082 protected void initReader() { 083 if( null != wb ) { wb = null; } 084 085 FileInputStream istream = null; 086 try { 087 istream = new FileInputStream(templateFile); 088 POIFSFileSystem fs = new POIFSFileSystem(istream); 089 wb = new HSSFWorkbook(fs); 090 } 091 catch( IOException ex ) { 092 String errMsg = "ファイル名がオープン出来ませんでした。" 093 + HybsSystem.CR 094 + " File:" + templateFile; 095 throw new HybsSystemException( errMsg,ex ); // 3.5.5.4 (2004/04/15) 引数の並び順変更 096 } 097 finally { 098 Closer.ioClose( istream ); // 4.0.0 (2006/01/31) close 処理時の IOException を無視 099 } 100 } 101 102 /** 103 * FileOutputStream を、初期化します。 104 * これは、雛型ファイルを終端まで読取り、処理した場合、出力ファイル名を 105 * 変えて、別ファイルとして出力する為のものです。 106 * 基本的に、読取も初期化する必要があります。 107 * 108 * 現在の所、POIはメモリ上にExcelファイルを作成する為、作成したファイルの書く込むを 109 * ファイル閉じる時点に伸ばされます。 110 * 111 */ 112 @Override 113 protected void initWriter() { 114 // ここでは処理を行いません。 115 } 116 117 /** 118 * リーダー、ライターの終了処理を行います。 119 * このメソッドが呼ばれたタイミングで、実際にファイル出力を行います。 120 * 121 */ 122 protected void close() { 123 124 String filename = htmlDir + HybsSystem.FS + htmlFileKey + EXCEL_FILE_EXT ; 125 126 FileOutputStream fileOut = null; 127 try { 128 // Write the output to a file 129 fileOut = new FileOutputStream(filename); 130 wb.write(fileOut); 131 } 132 catch( IOException ex ) { 133 wb = null; 134 String errMsg = "ファイル名がオープン出来ませんでした。" 135 + HybsSystem.CR 136 + " File:" + filename; 137 throw new HybsSystemException( errMsg,ex ); // 3.5.5.4 (2004/04/15) 引数の並び順変更 138 } 139 finally { 140 Closer.ioClose( fileOut ); // 4.0.0 (2006/01/31) close 処理時の IOException を無視 141 } 142 } 143 144 /** 145 * Excelの雛型をコピーして、そのシートに帳票データを埋め込みます。 146 * いろいろな属性がある所に、適切に対応していく予定。 147 * 各サブクラスで実装してください。 148 * 149 * @og.rev 4.3.4.0 (2008/12/01) POI3.2対応 150 * 151 */ 152 protected void changeSheet() { 153 HSSFSheet patternSheet = wb.getSheetAt(0); 154 while(!rowOver) { 155 HSSFSheet sheet2 = wb.cloneSheet(0); 156 // HSSFRow oRow2; 157 int nFirstRow = sheet2.getFirstRowNum(); 158 int nLastRow = sheet2.getLastRowNum(); 159 // int nTotalRows = patternSheet.getPhysicalNumberOfRows(); 160 for( int nIndexRow = nFirstRow; nIndexRow <= nLastRow; nIndexRow++) { 161 HSSFRow oRow = patternSheet.getRow(nIndexRow); 162 if( null != oRow ) { 163 // int nTotalCells = oRow.getPhysicalNumberOfCells(); 164 // 4.3.4.0 (2008/12/01) POI3.2対応。shortをintにする。 165 // short nFirstCell = oRow.getFirstCellNum(); 166 // short nLastCell = oRow.getLastCellNum(); 167 int nFirstCell = oRow.getFirstCellNum(); 168 int nLastCell = oRow.getLastCellNum(); 169 for( int nIndexCell = nFirstCell; nIndexCell <= nLastCell; nIndexCell++) { 170 HSSFCell oCell = oRow.getCell(nIndexCell); 171 if( null != oCell ) { changeCell(oCell);} 172 } 173 } 174 } 175 } 176 } 177 178 /** 179 * セル情報を変更します。 180 * 181 * @og.rev 4.3.4.0 (2008/12/01) POI3.2対応 182 * 183 * @param oCell HSSFCellオブジェクト 184 */ 185 protected void changeCell(final HSSFCell oCell) { 186 String strText; 187 HSSFRichTextString richText; 188 int nCellType = oCell.getCellType(); 189 switch(nCellType) { 190 case HSSFCell.CELL_TYPE_FORMULA: 191 strText = changeData(changeFormulaAttr(oCell.getCellFormula())); 192 if( null != strText ) { 193 // oCell.setCellType(HSSFCell.CELL_TYPE_FORMULA); 194 // oCell.setEncoding(HSSFCell.ENCODING_UTF_16); 195 oCell.setCellFormula(strText); 196 } 197 break; 198 case HSSFCell.CELL_TYPE_STRING: 199 // POI3.0 strText = changeData(oCell.getStringCellValue()); 200 richText = oCell.getRichStringCellValue(); 201 strText = changeData(richText.getString()); 202 if( null != strText ) { 203 // oCell.setCellType(HSSFCell.CELL_TYPE_STRING); 204 // POI3.0 oCell.setEncoding(HSSFCell.ENCODING_UTF_16); 205 // POI3.2 oCell.setCellValue( strText ); // POI3.0 Deprecation 206 oCell.setCellValue( new HSSFRichTextString(strText) ); 207 } 208 break; 209 // case HSSFCell.CELL_TYPE_NUMERIC: 210 // break; 211 // case HSSFCell.CELL_TYPE_BOOLEAN: 212 // break; 213 // case HSSFCell.CELL_TYPE_ERROR: 214 // break; 215 default : 216 break; 217 } 218 } 219 220 /** 221 * POIで解釈したExcel式の中の変な属性を加工して、出力します。 222 * いろいろな属性がある所に、適切に対応していく予定。 223 * 各サブクラスで実装してください。 224 * 225 * @param inLine 入力文字列 226 * 227 * @return 出力文字列 228 */ 229 protected String changeFormulaAttr( final String inLine ) { 230 // rowOver で、かつ ページブレークかページエンドカットの場合、処理終了。 231 Matcher matcher = PATTERN_EXIN.matcher(inLine); 232 return matcher.find() ? matcher.replaceAll("") : inLine; 233 } 234 235 /** 236 * 入力文字列 を加工して、出力します。 237 * データをテーブルモデルより読み取り、値をセットします。 238 * 各サブクラスで実装してください。 239 * 240 * @param inLine 入力文字列 241 * 242 * @return 出力文字列. 文字列の変換は要らない場合、nullを返します 243 */ 244 @Override 245 protected String changeData( final String inLine ) { 246 boolean bFind = false; 247 248 // rowOver で、かつ ページブレークかページエンドカットの場合、処理終了。 249 Matcher matcher = PATTERN_KEY.matcher(inLine); 250 StringBuffer sb = new StringBuffer(); // Matcher.appendTail( StringBuffer ) の為 251 252 while (matcher.find()) { 253 matcher.appendReplacement(sb, getValue(matcher.group( 1 ))); 254 bFind = true; 255 } 256 257 if( bFind ) { 258 matcher.appendTail(sb); 259 return sb.toString(); 260 } 261 else { 262 return null; 263 } 264 } 265 266 /** 267 * 入力文字列 を読み取って、出力します。 268 * tr タグを目印に、1行(trタグ間)ずつ取り出します。 269 * 読み取りを終了する場合は、null を返します。 270 * 各サブクラスで実装してください。 271 * ※ このクラスでは実装されていません。 272 * 273 * @return 出力文字列 274 */ 275 @Override 276 protected String readLine() { 277 throw new UnsupportedOperationException(); 278 } 279 280 /** 281 * 入力文字列 を読み取って、出力します。 282 * 各サブクラスで実装してください。 283 * ※ このクラスでは実装されていません。 284 * 285 * @param line 入力文字列 286 */ 287 @Override 288 protected void println( final String line ) { 289 throw new UnsupportedOperationException(); 290 } 291}