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.hayabusa.report;
017
018 import org.opengion.hayabusa.common.HybsSystemException;
019
020 import java.util.Map;
021 import java.util.HashMap;
022 import java.util.List;
023 import java.util.ArrayList;
024 import java.util.Iterator ;
025 import java.util.NoSuchElementException;
026 import java.util.Arrays ;
027
028 /**
029 * 【EXCEL取込】雛形EXCELシートã? {@カラãƒ? 解析データを管ç�??収集する 雛形レイアウト管ç�?‚¯ラスですã?
030 * POIのHSSFListener などでã€?››形æƒ??を収é›?�—、HSSFSheet などでã€?››形æƒ??のアドレス(行å?)から
031 * å¿?¦�なæƒ??を取得し、このオブジェクトに設定しておきますã?
032 * EXCELシート毎に、INSERTæ–?�¨、対応する文字å?配å?を取りå?しますã?
033 *
034 * @og.rev 3.8.0.0 (2005/06/07) 新規追åŠ?
035 * @og.group 帳票シスãƒ?ƒ
036 *
037 * @version 4.0
038 * @author Kazuhiko Hasegawa
039 * @since JDK5.0,
040 */
041 public class ExcelLayout {
042
043 private final Map<String,String> headMap = new HashMap<String,String>(); // シート単位ã?ヘッãƒ??キーをæ?納しますã?
044 private final Map<String,String> bodyMap = new HashMap<String,String>(); // シート単位ã?ボディーキーをæ?納しますã?
045 private final Map<Integer,Map<String,String>> dataMap = new HashMap<Integer,Map<String,String>>(); // シート単位ã?ãƒ??タをæ?納するMapをæ?納しますã?(キーは、GEEDNO)
046
047 private final List<ExcelLayoutData>[] model ; // シート毎にExcelLayoutDataがæ?納されますã?
048
049 private String loopClm = null; // 繰返å¿??カラãƒ?なければnull))
050 private ExcelLayoutDataIterator iterator = null; // ExcelLayoutData を返す、Iterator
051
052 /**
053 * コンストラクター
054 *
055 * 雛形のæœ?¤§シート数を設定しますã?
056 * ここではã€??番で管ç�?�—てã�?‚‹為、その雛形シート番号がå?ç�?¯¾象外であってもã?
057 * 雛形EXCEL上に存在するシート数を設定するå¿?¦�がありますã?
058 * 具体的には、HSSFListener#processRecord( Record )で、BoundSheetRecord.sid の
059 * イベントã?数を数えて設定しますã?
060 *
061 * @param sheetSize æœ?¤§シート数
062 */
063 @SuppressWarnings(value={"unchecked","rawtypes"})
064 public ExcelLayout( final int sheetSize ) {
065 model = new ArrayList[sheetSize];
066 for( int i=0; i<sheetSize; i++ ) {
067 model[i] = new ArrayList<ExcelLayoutData>();
068 }
069 }
070
071 /**
072 * 雛形EXCELの {@カラãƒ? 解析情報を設定しますã?
073 *
074 * 雛形EXCELは、HSSFListener を使用して、イベントé§?‹•で取得しますã?そã?場合ã?
075 * {@カラãƒ?を含ã‚?‚»ルを見つける都度、このメソãƒ?ƒ‰を呼び出して、{@カラãƒ?の
076 * 位置(行å?番号)を設定しますã?
077 * ãƒ??タEXCELからãƒ??タを読み出すå?合ã?、ここで登録したカラãƒ??行å?より、読み込みますã?
078 * 具体的には、HSSFListener#processRecord( Record )で、SSTRecord.sid の æƒ??をキープしておきã€?
079 * LabelSSTRecord.sid 毎に、{@カラãƒ?を含ã‚?�‹チェãƒ?‚¯しã?含ã‚??合に、このメソãƒ?ƒ‰に
080 * 解析情報を設定しますã?
081 *
082 * @param sheetNo シート番号
083 * @param key 処ç�?‚«ラãƒ?
084 * @param rowNo 行番号
085 * @param colNo 列番号
086 */
087 public void addModel( final int sheetNo, final String key, final int rowNo, final short colNo ) {
088 model[sheetNo].add( new ExcelLayoutData( key,rowNo,colNo ) );
089 }
090
091 /**
092 * 雛形EXCELの {@カラãƒ? 解析情報(ExcelLayoutData)をé?列で取得しますã?
093 *
094 * 雛形EXCELは、イベントå?ç�?�§取り込ã‚?‚º、すべての処ç�?�Œ終äº?�—てから、このメソãƒ?ƒ‰で
095 * 処ç�?µ�果を取りå?すå¿?¦�がありますã?
096 * 解析情報は、ExcelLayoutData オブジェクトにシート単位に保管されてã�?�¾すã?
097 * こã? ExcelLayoutData オブジェクãƒ?ひとつに、{@カラãƒ? ひとつ、つまりã?
098 * ある特定ã?行å?番号を持ってã�?�¾すã?
099 * ãƒ??タEXCELを読取る場合ã?こã? ExcelLayoutData配å?から、行å?æƒ??を取りå?しã?
100 * addData メソãƒ?ƒ‰で、キーæƒ??と関連付けて登録する為に、使用しますã?
101 *
102 * @param sheetNo シート番号
103 * @param loopClm 繰返å¿??カラãƒ?なければ通常の?‘対?‘å?ç�?
104 *
105 * @return ExcelLayoutData配å?
106 */
107 public Iterator<ExcelLayoutData> getLayoutDataIterator( final int sheetNo, final String loopClm ) {
108 this.loopClm = loopClm ;
109 ExcelLayoutData[] datas = model[sheetNo].toArray( new ExcelLayoutData[model[sheetNo].size()] );
110 iterator = new ExcelLayoutDataIterator( datas,loopClm );
111 return iterator ;
112 }
113
114 /**
115 * 解析情報(clm,edbn)と関連付けて、データEXCELの値を設定しますã?
116 *
117 * ãƒ??タEXCELはã€?››形EXCELの解析情報をå?に、行å?番号から設定å?を取りå?しますã?
118 * そã?設定å?は、取りだした ExcelLayoutData の clm,edbn と関連付けて、このメソãƒ?ƒ‰で登録しますã?
119 * こã?処ç�??、シート毎に、å?期化して使ã�?¿?¦�がありますã?
120 * 初期化メソãƒ?ƒ‰する場合ã?、dataClear() を呼び出してくださいã€?
121 *
122 * @param clm カラãƒ?��
123 * @param edbn 枝番
124 * @param value ãƒ??タ値
125 */
126 public void addData( final String clm, final int edbn, final String value ) {
127 if( loopClm != null && loopClm.equals( clm ) && edbn >= 0 && ( value == null || value.length() == 0 ) ) {
128 iterator.setEnd();
129 Integer edbnObj = Integer.valueOf( edbn );
130 dataMap.remove( edbnObj ); // 枝番単位ã?Mapを削除
131 return ;
132 }
133
134 Integer edbnObj = Integer.valueOf( edbn );
135 Map<String,String> map = dataMap.get( edbnObj ); // 枝番単位ã?Mapを取å¾?
136 if( map == null ) { map = new HashMap<String,String>(); }
137 map.put( clm,value ); // 枝番に含まれるキーと値をセãƒ?ƒˆ
138 dataMap.put( edbnObj,map ); // そã?Mapを枝番に登録
139
140 if( edbn < 0 ) {
141 headMap.put( clm,null );
142 }
143 else {
144 bodyMap.put( clm,null );
145 }
146 }
147
148 /**
149 * ãƒ??タEXCELの設定情報をå?期化しますã?
150 *
151 * ãƒ??タEXCELとã€?››形EXCELの解析情報を関連付けるå?ç�??、シート毎に行うå¿?¦�がありますã?
152 * 処ç�?µ‚äº?™‚(シートå?り替え時)こã?メソãƒ?ƒ‰を呼び出して、å?期化しておくå¿?¦�がありまã�?
153 *
154 */
155 public void dataClear() {
156 dataMap.clear();
157 headMap.clear();
158 bodyMap.clear();
159 }
160
161 /**
162 * ヘッãƒ??æƒ??のINSERT用Queryæ–?—å?を取得しますã?
163 *
164 * シート単位に、データEXCELより、INSERT用のQueryæ–?—å?を作æ?しますã?
165 * こã?、Query は、シート単位に登録したキーæƒ??のæœ?¤§数(使用されてã�?‚‹すべてのキー)ã‚?
166 * å…?�«、PreparedStatement で処ç�?�§きる形の INSERTæ–?‚’作æ?しますã?
167 * シート単位に呼び出すå¿?¦�がありますã?
168 *
169 * @param table ヘッãƒ??æƒ??を登録するãƒ??タベã?スå�?HEADERDBID)
170 *
171 * @return ヘッãƒ??æƒ??のINSERT用Queryæ–?—å?
172 */
173 public String getHeaderInsertQuery( final String table ) {
174 if( table == null || table.length() == 0 || headMap.isEmpty() ) { return null; }
175 return makeQuery( table,headMap );
176 }
177
178 /**
179 * ボディ(明細)æƒ??のINSERT用Queryæ–?—å?を取得しますã?
180 *
181 * シート単位に、データEXCELより、INSERT用のQueryæ–?—å?を作æ?しますã?
182 * こã?、Query は、シート単位に登録したキーæƒ??のæœ?¤§数(使用されてã�?‚‹すべてのキー)ã‚?
183 * å…?�«、PreparedStatement で処ç�?�§きる形の INSERTæ–?‚’作æ?しますã?
184 * シート単位に呼び出すå¿?¦�がありますã?
185 *
186 * @param table ボディ(明細)æƒ??を登録するãƒ??タベã?スå�?BODYDBID)
187 *
188 * @return ボディ(明細)æƒ??のINSERT用Queryæ–?—å?
189 */
190 public String getBodyInsertQuery( final String table ) {
191 if( table == null || table.length() == 0 || bodyMap.isEmpty() ) { return null; }
192 return makeQuery( table,bodyMap );
193 }
194
195 /**
196 * ヘッãƒ??æƒ??のINSERT用Queryに対応するã?ãƒ??タ配å?を取得しますã?
197 *
198 * getHeaderInsertQuery( String ) で取りã�?�—ã�?PreparedStatement に設定するå?配å?ですã?
199 * シート単位に呼び出すå¿?¦�がありますã?
200 *
201 * @param systemId シスãƒ?ƒ ID(SYSTEM_ID)
202 * @param ykno 要求番号(YKNO)
203 * @param sheetNo 登録するãƒ??タEXCELのシート番号(SHEETNO)
204 *
205 * @return ãƒ??タ配å?
206 */
207 public String[] getHeaderInsertData( final String systemId,final int ykno,final int sheetNo ) {
208 String[] keys = headMap.keySet().toArray( new String[headMap.size()] );
209 if( keys == null || keys.length == 0 ) { return new String[0]; }
210
211 Integer edbnObj = Integer.valueOf( -1 ); // ヘッãƒ??
212 Map<String,String> map = dataMap.get( edbnObj );
213 if( map == null ) { return new String[0]; }
214
215 String[] rtnData = new String[keys.length+4];
216
217 rtnData[0] = systemId;
218 rtnData[1] = String.valueOf( ykno );
219 rtnData[2] = String.valueOf( sheetNo );
220 rtnData[3] = String.valueOf( -1 ); // 枝番
221
222 for( int i=0; i<keys.length; i++ ) {
223 rtnData[i+4] = map.get( keys[i] );
224 }
225
226 return rtnData;
227 }
228
229 /**
230 * ボディ(明細)æƒ??のINSERT用Queryに対応するã?ãƒ??タ配å?のリスãƒ?String[] のList)を取得しますã?
231 *
232 * getHeaderInsertQuery( String ) で取りã�?�—ã�?PreparedStatement に設定するå?配å?ですã?
233 * シート単位に呼び出すå¿?¦�がありますã?
234 *
235 * @param systemId シスãƒ?ƒ ID(SYSTEM_ID)
236 * @param ykno 要求番号(YKNO)
237 * @param sheetNo 登録するãƒ??タEXCELのシート番号(SHEETNO)
238 *
239 * @return ãƒ??タ配å?のリスãƒ?
240 */
241 public List<String[]> getBodyInsertData( final String systemId,final int ykno,final int sheetNo ) {
242 String[] keys = bodyMap.keySet().toArray( new String[bodyMap.size()] );
243 if( keys == null || keys.length == 0 ) { return null; }
244
245 List<String[]> rtnList = new ArrayList<String[]>();
246
247 Integer[] edbnObjs = dataMap.keySet().toArray( new Integer[dataMap.size()] );
248 for( int i=0; i<edbnObjs.length; i++ ) {
249 int edbn = edbnObjs[i].intValue();
250 if( edbn < 0 ) { continue; } // ヘッãƒ??の場合ã?、読み直ã�?
251
252 String[] rtnData = new String[keys.length+4]; // 毎回、新規に作æ?するã€?
253 rtnData[0] = systemId;
254 rtnData[1] = String.valueOf( ykno );
255 rtnData[2] = String.valueOf( sheetNo );
256 rtnData[3] = String.valueOf( edbn ); // 枝番
257
258 Map<String,String> map = dataMap.get( edbnObjs[i] );
259 for( int j=0; j<keys.length; j++ ) {
260 rtnData[j+4] = map.get( keys[j] );
261 }
262 rtnList.add( rtnData );
263 }
264
265 return rtnList;
266 }
267
268 /**
269 * å†?ƒ¨æƒ??Mapより、INSERT用Queryæ–?—å?を取得しますã?
270 *
271 * シート単位に、データEXCELより、INSERT用のQueryæ–?—å?を作æ?しますã?
272 * こã?、Query は、シート単位に登録したキーæƒ??のæœ?¤§数(使用されてã�?‚‹すべてのキー)ã‚?
273 * å…?�«、PreparedStatement で処ç�?�§きる形の INSERTæ–?‚’作æ?しますã?
274 * シート単位に呼び出すå¿?¦�がありますã?
275 *
276 * @param table ãƒ??ブルå�?
277 * @param map ボディ(明細)æƒ??を登録するå†?ƒ¨æƒ??Map
278 *
279 * @return INSERT用Queryæ–?—å?
280 */
281 private String makeQuery( final String table,final Map<String,String> map ) {
282 String[] keys = map.keySet().toArray( new String[map.size()] );
283
284 if( keys == null || keys.length == 0 ) { return null; }
285
286 StringBuilder buf1 = new StringBuilder( 200 );
287 buf1.append( "INSERT INTO " ).append( table ).append( " ( " );
288 buf1.append( "GESYSTEM_ID,GEYKNO,GESHEETNO,GEEDNO" );
289
290 StringBuilder buf2 = new StringBuilder( 200 );
291 buf2.append( " ) VALUES (" );
292 buf2.append( "?,?,?,?" );
293
294 for( int i=0; i<keys.length; i++ ) {
295 buf1.append( "," ).append( keys[i] );
296 buf2.append( ",?" );
297 }
298 buf2.append( ")" );
299
300 buf1.append( buf2 );
301
302 return buf1.toString();
303 }
304 }
305
306 /**
307 * ExcelLayoutData (雛形解析結果)のシート毎ã?Iteratorを返しますã?
308 * ExcelLayout では、データEXCELは、シート毎に解析しますã?
309 * 通常はã€?››形とãƒ??タは?‘対?‘ã?関係でã€?››形より多いãƒ??タは、読み取りませんしã?
310 * 少なã�?ƒ‡ータは、NULL値でãƒ??タ登録しますã?
311 * ここで、繰返å¿??カラãƒ?LOOPCLM)を指定することで、指定ã?カラãƒ?�Œå¿??であることを利用してã€?
312 * ãƒ??タが少なã�??合ã?、そこまでで処ç�?‚’中止して、データが多い場合ã?、仮想çš?�«カラãƒ?�Œ
313 * 存在すると仮定してã€?››形に存在しなã�?®?‰€のãƒ??タを読み取れるよã�?�«、Iterator を返しますã?
314 * ãƒ??タがオーバã?する場合ã?、仮想çš?�«カラãƒ??存在するアドレスを求めるå¿?¦�があるためã€?
315 * æœ?½?カラãƒ?0 と カラãƒ?1 がå¿?¦�ですã?さらに、各カラãƒ??、行方向に並んでおりã€?
316 * 列方向ã?、同ä¸?�§あるとã�?�†前提で、読み取るべき行å?番号を作æ?しますã?
317 *
318 * @og.rev 3.8.0.0 (2005/06/07) 新規追åŠ?
319 * @og.group 帳票シスãƒ?ƒ
320 *
321 * @version 4.0
322 * @author Kazuhiko Hasegawa
323 * @since JDK5.0,
324 */
325 class ExcelLayoutDataIterator implements Iterator<ExcelLayoutData> {
326 private final ExcelLayoutData[] layoutDatas ;
327 private final String loopClm ;
328 private int incSize = 1; // 行番号の増加数(段çµ?�ªどの場合ã?ã€?¼‘以上となã‚?
329 private int count = 0; // 現在処ç�?¸の行番号
330 private int edbnCnt = 0; // 処ç�?¸の枝番に相当するカウントå?
331 private int stAdrs = -1; // 繰返し処ç�?‚’行う開始アドレス
332 private int edAdrs = -1; // 繰返し処ç�?‚’行う終äº?‚¢ドレス
333
334 /**
335 * ExcelLayoutData の配å?を受け取って、å?期情報を設定しますã?
336 *
337 * 繰返å¿??カラãƒ?LOOPCLM)がnullでなã�??合ã?枝番が0ã?カラãƒ?‚’繰り返しますã?
338 * 繰り返す場合ã?行番号と枝番を指定して、既存ã?ExcelLayoutDataオブジェクトを作æ?しã?
339 * 仮想çš?�«繰返しますã?
340 *
341 * @param datas ExcelLayoutData[] ExcelLayoutData の配å?
342 * @param lpClm 繰返å¿??カラãƒ?LOOPCLM)
343 */
344 public ExcelLayoutDataIterator( final ExcelLayoutData[] datas,final String lpClm ) {
345 layoutDatas = datas;
346 loopClm = lpClm;
347
348 int size = layoutDatas.length; // 配å?のæœ?¤§値
349
350 Arrays.sort( layoutDatas ); // 枝番é ?�«ソートされますã?
351 // loopClm を使ã�??合ã?、枝番 -1(ヘッãƒ?とã€?¼�ã?ãƒ??タのみを使用する。枝番?‘ã?、増加数の取得ã?みに用ã�?‚‹ã€?
352 if( loopClm != null ) {
353 int zeroRow = -1;
354 for( int i=0; i<size; i++ ) {
355 // System.out.println( "count=" + i + ":" + layoutDatas[i] );
356 int edbn = layoutDatas[i].getEdbn();
357 if( stAdrs < 0 && edbn == 0 ) { stAdrs = i; } // 初ã?枝番0アドレス?�開å§?含ã‚?
358 if( edAdrs < 0 && edbn == 1 ) { edAdrs = i; } // 初ã?枝番1アドレス?�終äº?含まなã�?
359 if( loopClm.equals( layoutDatas[i].getClm() ) ) {
360 if( edbn == 0 ) {
361 zeroRow = layoutDatas[i].getRowNo(); // loopClm の枝番0 の行番号
362 }
363 else if( edbn == 1 ) {
364 incSize = layoutDatas[i].getRowNo() - zeroRow; // 増加数=枝番1-枝番0
365 break;
366 }
367 }
368 }
369 // 繰返がある場å�?枝番ã�?以ä¸?でloopClmが見つからなã�??合ã?エラー
370 if( zeroRow < 0 && stAdrs >= 0 ) {
371 String errMsg = "繰返å¿??カラãƒ?�Œシート中に存在しませんã€?" + loopClm + "]";
372 throw new HybsSystemException( errMsg );
373 }
374 }
375 if( stAdrs < 0 ) { stAdrs = 0; } // 開å§?含ã‚?
376 if( edAdrs < 0 ) { edAdrs = size; } // 終äº?含まなã�?
377 // System.out.println( "stAdrs=" + stAdrs + " , edAdrs=" + edAdrs );
378 }
379
380 /**
381 * 繰り返し処ç�?�§さらに要ç´?�Œある場合に true を返しますã?
382 * つまりã?next が例外をスローしなã�?�§要ç´?‚’返す場合に true を返しますã?
383 *
384 * @return 反復子がさらに要ç´?‚’持つ場合ã? true
385 */
386 public boolean hasNext() {
387 if( loopClm != null && count == edAdrs ) {
388 count = stAdrs;
389 edbnCnt++;
390 }
391 // System.out.print( "count=[" + count + "]:" );
392 return ( count < edAdrs );
393 }
394
395 /**
396 * 繰り返し処ç�?�§次の要ç´?‚’返しますã?
397 *
398 * @return Object 繰り返し処ç�?�§次の要ç´?
399 * @throws NoSuchElementException 繰り返し処ç�?�§それ以上要ç´?�Œなã�??å�?
400 */
401 public ExcelLayoutData next() throws NoSuchElementException {
402 if( layoutDatas == null || layoutDatas.length == count ) {
403 String errMsg = "行番号がレイアウトデータをオーバã?しましたã€? +
404 " 行番号=[" + count + "]" ;
405 throw new NoSuchElementException( errMsg );
406 }
407
408 ExcelLayoutData data = layoutDatas[count++];
409
410 if( edbnCnt > 0 ) { // 繰返å¿??é ?›®機è?が働ã�?�¦ã�?‚‹ケース
411 int rowNo = data.getRowNo() + edbnCnt * incSize ;
412 data = data.copy( rowNo,edbnCnt );
413 // System.out.println( "row,edbn=[" + rowNo + "," + edbnCnt + "]:" + data );
414 }
415
416 return data;
417 }
418
419 /**
420 * こã?メソãƒ?ƒ‰は、このクラスからは使用できませんã€?
421 * ※ こã?クラスでは実è£?�•れてã�?�¾せんã€?
422 * こã?メソãƒ?ƒ‰では、å¿?�š、UnsupportedOperationException がã?throw されますã?
423 */
424 public void remove() {
425 String errMsg = "こã?メソãƒ?ƒ‰は、このクラスからは使用できませんã€?;
426 throw new UnsupportedOperationException( errMsg );
427 }
428
429 /**
430 * 繰返し処ç�?‚’終äº?�•せますã?
431 *
432 */
433 public void setEnd() {
434 edAdrs = -1;
435 }
436 }