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.html; 017 018import org.opengion.fukurou.util.StringUtil ; 019 020import java.util.Map; 021import java.util.HashMap; 022import java.util.List; 023import java.util.ArrayList; 024import java.util.Arrays; 025 026/** 027 * String[] 型キーにカラム列の連想記憶を用いた、クロス集計データを管理するクラスです。 028 * 029 * クロス集計では、カラム列が、データとして与えられる為、このクラス内部で、 030 * 一旦カラム列の連想記憶(Map)データを作成し、実際の行データ登録時にデータを 031 * 設定しています。 032 * 取り出すときは、一気に取り出すことを考慮して、配列(ArrayList)データに 033 * 共有しているオブジェクトを取り出します。 034 * 035 * この実装は同期化されません。 036 * 037 * @og.rev 3.5.4.0 (2003/11/25) 新規作成 038 * @og.group 画面表示 039 * 040 * @version 4.0 041 * @author Kazuhiko Hasegawa 042 * @since JDK5.0, 043 */ 044public final class CrossMap { 045 private final Map<String,String[]> row = new HashMap<String,String[]>() ; 046 private final Map<String,Integer> clm = new HashMap<String,Integer>() ; 047 private final List<String[]> list = new ArrayList<String[]>(); 048 private final int headCount; 049 private final int sumCount; 050 private final int totalCols; 051 052 /** 053 * カラム部(クロス集計部)を与えて新しく作成するコンストラクター 054 * 055 * クロス集計を行うカラム部のみセットします。 056 * 行のクロス集計部のヘッダーキーは、引数の配列の順番で、設定されます。 057 * この行のヘッダー部となるデータは、addData 時にセットします。 058 * 059 * @param clmData クロス集計部のカラム名配列 060 * @param headCount HEADカラムの数 061 * @param sumCount 合計カラムの数 062 */ 063 public CrossMap( final String[] clmData, final int headCount, final int sumCount ) { 064 if( headCount <= 0 ) { 065 String errMsg = "headCount は、ROWカラムを含むため、最低1以上必要です。"; 066 throw new IllegalArgumentException( errMsg ); 067 } 068 069 this.headCount = headCount; 070 this.sumCount = sumCount; 071 int clmNum = clmData.length; 072 totalCols = headCount + clmNum * sumCount; 073 for( int i=0; i<clmNum; i++ ) { 074 clm.put( clmData[i],Integer.valueOf( i ) ); 075 } 076 } 077 078 /** 079 * クロス集計の元となる検索結果の行データを登録します。 080 * 081 * クロス集計を行うカラム部のみ,セットします。 082 * 行のヘッダー部となるデータは、rowKeys と headCount で指定します。 083 * 行のクロス集計部のヘッダーキーは、clmKey で指定し、内部で、列カラムとして 084 * 割り当てられます。割り当て順(カラム順)は、コンストラクタでの clmData の 085 * 配列の順番です。 086 * 087 * @param rowKeys 行データの配列( 0〜headCount の値が行のキーとなります。) 088 */ 089 public void add( final String[] rowKeys ) { 090 if( rowKeys.length < headCount + 1 + sumCount) { 091 String errMsg = "指定の rowKeys の個数が不正です。 rowKeys には、clmKey と data が必要です。" 092 + " rowKeys=" + StringUtil.array2csv( rowKeys ) ; // 5.1.8.0 (2010/07/01) errMsg 修正 093 throw new ArrayIndexOutOfBoundsException( errMsg ); 094 } 095 096 // 3.5.6.6 (2004/08/23) 修正 097 String clmKey = rowKeys[headCount]; // カラム列のクロス集計部のキー(ヘッダー) 098 String[] data = new String[sumCount]; // クロス集計表の値 099 for( int i=0; i<sumCount; i++ ) { 100 data[i] = rowKeys[headCount+1+i]; 101 } 102 103 String rowKey ; 104 // 3.5.6.6 (2004/08/23) 修正 105 if( headCount == 1 ) { rowKey = rowKeys[0]; } 106 else { 107 StringBuilder rKey = new StringBuilder(); 108 for( int i=0; i<headCount; i++ ) { 109 rKey.append( rowKeys[i] ); 110 rKey.append( "_" ); 111 } 112 rowKey = rKey.toString(); 113 } 114 String[] clmData = row.get( rowKey ); 115 if( clmData == null ) { 116 // 行データ+クロス行データ 117 clmData = new String[totalCols]; 118 Arrays.fill( clmData,"" ); 119 for( int i=0; i<headCount; i++ ) { 120 clmData[i] = rowKeys[i]; 121 } 122 list.add( clmData ); // 生成順にArrayList にセーブします。 123 } 124 125 for( int i=0; i<sumCount; i++ ) { 126 int no = headCount + (clm.get( clmKey )).intValue()*sumCount+i; // 列番号 127 clmData[no] = data[i]; 128 } 129 row.put( rowKey,clmData ); // ArrayList と同じオブジェクトを検索用のMapにもセットする。 130 } 131 132 /** 133 * クロス集計結果の指定行の列データを返します。 134 * 135 * @param row 指定の行番号( 0 .. getSize()-1 ) 136 * 137 * @return 列データ配列 138 */ 139 public String[] get( final int row ) { 140 return list.get( row ); 141 } 142 143 /** 144 * クロス集計結果の行数を返します。 145 * 146 * @return 行数を返します。 147 */ 148 public int getSize() { 149 return list.size(); 150 } 151}