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.db;
017
018 import org.opengion.hayabusa.common.HybsSystem;
019 import org.opengion.fukurou.util.LogWriter;
020 import org.opengion.fukurou.util.StringUtil;
021
022 import java.util.List;
023 import java.util.ArrayList;
024
025 /**
026 * DBTableModelを継承した TableModelのソート機?の実?ラスです?
027 *
028 * ViewFormのヘッ??リンクをクリ?すると、その?につ?再ソートします?
029 * これは、データベ?スではなく?メモリのDBTableModelにソート用のModel?
030 * 用意し、そのModelの行番号のみをソートし、行変換を行います?
031 * ソートを利用するかど?は、シス?パラメータ の、VIEW_USE_TABLE_SORTER 属?で
032 * ?します?(? シス?パラメータ では、false 設?
033 * ヘッ??部に表示するリンクは、command=VIEW&h_sortColumns=XXXXX で、カラ?を指定します?
034 * ※ h_sortColumns 部は、HybsSystemにて定義します?で?のJSPでは使用しな?下さ??
035 *
036 * DBTableModel インターフェースは?データベ?スの検索結果(Resultset)をラ??する
037 * インターフェースとして使用して下さ??
038 *
039 * @og.rev 3.5.4.7 (2004/02/06) 新規登録
040 * @og.group ??ブル管?
041 *
042 * @version 4.0
043 * @author Kazuhiko Hasegawa
044 * @since JDK5.0,
045 */
046 public class DBTableModelSorter extends DBTableModelImpl {
047 private int[] indexes;
048 private int sortingColumn ;
049 private boolean ascending = true;
050 private int lastColumNo = -1;
051 private boolean isNumberType = false; // 3.5.6.3 (2004/07/12)
052
053 /**
054 * DBTableModel を設定し、このオブジェクトを初期化します?
055 *
056 * @param model DBTableModelオブジェク?
057 */
058 public void setModel( final DBTableModel model ) {
059 DBTableModelImpl impl = (DBTableModelImpl)model;
060 dbColumns = impl.dbColumns;
061 names = impl.names;
062 data = impl.data;
063 rowHeader = impl.rowHeader;
064 columnMap = impl.columnMap;
065 overflow = impl.overflow;
066 numberOfColumns = impl.numberOfColumns;
067
068 // 3.5.5.5 (2004/04/23) 整合?キー(オブジェクト?作?時刻)追?
069 consistencyKey = impl.consistencyKey;
070
071 lastColumNo = -1;
072 reallocateIndexes();
073 }
074
075 /**
076 * 行番号イン?クスを?期化します?
077 * 行番号をそのまま??番に設定します?
078 *
079 */
080 private void reallocateIndexes() {
081 int rowCount = super.getRowCount();
082 indexes = new int[rowCount];
083
084 for(int row = 0; row < rowCount; row++) {
085 indexes[row] = row;
086 }
087 }
088
089 /**
090 * 同?ラ?号に対する、行1と行2?値の大小を比?ます?
091 * 比?に、そのカラ?、NUMBERタイプ?場合?、Double に変換後?数字として
092 * 比?ます?それ以外?場合?、文字?の比? row1の値.compareTo(s2) )の
093 * 値を返します?
094 *
095 * row1の値 < row2の値 : ?
096 * row1の値 > row2の値 : 正
097 * row1の値 == row2の値 : 0
098 *
099 * @og.rev 3.5.6.3 (2004/07/12) isNumberType 属?を使用する?
100 *
101 * @param row1 比??の行番号
102 * @param row2 比??の行番号
103 * @param column 比?るカラ?号
104 *
105 * @return 比?果[?0/正]
106 */
107 private int compareRowsByColumn( final int row1, final int row2, final int column ) {
108
109 String s1 = super.getValue(row1, column);
110 String s2 = super.getValue(row2, column);
111
112 if( isNumberType ) {
113 // 3.5.6.3 (2004/07/12) 数字型で ゼロ??時?処?
114 if( s1.length() == 0 || s2.length() == 0 ) {
115 return ( s1.length() - s2.length() );
116 }
117
118 double d1 = StringUtil.parseDouble( s1 );
119 double d2 = StringUtil.parseDouble( s2 );
120
121 // 注意:引き算をすると、桁あふれする可能性があるため?比?る?
122 if(d1 < d2) { return -1; }
123 else if(d1 > d2) { return 1; }
124 else { return 0; }
125 }
126 else {
127 return s1.compareTo(s2);
128 }
129 }
130
131 /**
132 * ???カラ?sortingColumn)に対する、行1と行2?値の大小を比?ます?
133 * 比????、compareRowsByColumn( int,int,int ) を使用します?
134 * ascending フラグ[true:??/false:降?] にしたがって、結果を反転します?
135 *
136 * ascending == true の? ascending == false の?
137 * row1の値 < row2の値 : ? 正
138 * row1の値 > row2の値 : 正 ?
139 * row1の値 == row2の値 : 0 0
140 *
141 * @param row1 比??の行番号
142 * @param row2 比??の行番号
143 *
144 * @return 比?果[?0/正]
145 * @see #compareRowsByColumn( int,int,int )
146 */
147 private int compare( final int row1, final int row2 ) {
148 int result = compareRowsByColumn(row1, row2, sortingColumn);
149
150 if(result != 0) {
151 return ascending ? result : -result;
152 }
153 return 0;
154 }
155
156 /**
157 * ソートする?部??タが不整合を起こして?かチェ?します?
158 * ?行番号と、テーブルオブジェクト?件数を比?ます?
159 *
160 * @og.rev 3.5.6.3 (2004/07/12) チェ?エラー時にアベンドせずに再設定する?
161 */
162 private void checkModel() {
163 if(indexes.length != super.getRowCount()) {
164 String errMsg = "?行番号と、テーブルオブジェクト?件数が不??です? " + HybsSystem.CR
165 + "Index Length=[" + indexes.length + "] , Table Row Count=[" + super.getRowCount() + "]";
166 LogWriter.log( errMsg );
167 reallocateIndexes();
168 }
169 }
170
171 /**
172 * ソート???トップメソ?です?
173 *
174 */
175 private void sort() {
176 checkModel();
177
178 reallocateIndexes();
179 shuttlesort(indexes.clone(), indexes, 0, indexes.length);
180
181 int rowCount = indexes.length;
182
183 List<String[]> newData = new ArrayList<String[]>( rowCount );
184 List<DBRowHeader> newRowHeader = new ArrayList<DBRowHeader>( rowCount );
185
186 for( int row=0; row<rowCount; row++ ) {
187 newData.add( row,data.get( indexes[row] ) );
188 newRowHeader.add( row,rowHeader.get( indexes[row] ) );
189 }
190 data = newData;
191 rowHeader = newRowHeader;
192 }
193
194 /**
195 * シャトルソートを行います?
196 *
197 * @param from ソート?配?
198 * @param to ソート?配?
199 * @param low ?(下?
200 * @param high ?(上?
201 */
202 private void shuttlesort( final int[] from, final int[] to, final int low, final int high ) {
203 if(high - low < 2) {
204 return;
205 }
206 int middle = (low + high) >>> 1; // widely publicized the bug pattern.
207 shuttlesort(to, from, low, middle);
208 shuttlesort(to, from, middle, high);
209
210 int pp = low;
211 int qq = middle;
212
213 if(high - low >= 4 && compare(from[middle-1], from[middle]) <= 0) {
214 for(int i = low; i < high; i++) {
215 to[i] = from[i];
216 }
217 return;
218 }
219
220 for(int i = low; i < high; i++) {
221 if(qq >= high || (pp < middle && compare(from[pp], from[qq]) <= 0)) {
222 to[i] = from[pp++];
223 }
224 else {
225 to[i] = from[qq++];
226 }
227 }
228 }
229
230 /**
231 * カラ?ソート?トップメソ?です?
232 * ?ォルトで、??ートを行います?
233 * ?にソートしたカラ?同??カラ??された場合???と降??
234 * 反転させて、?度ソートを行います?(シャトルソー?
235 *
236 * @param column カラ?号
237 */
238 public void sortByColumn( final int column ) {
239 if( lastColumNo == column ) {
240 ascending = !ascending ;
241 }
242 else {
243 ascending = true;
244 }
245 sortByColumn( column,ascending );
246 }
247
248 /**
249 * カラ?ソート?トップメソ?です?
250 * ascending フラグ[true:??/false:降?]を指定します?
251 *
252 * @og.rev 3.5.6.3 (2004/07/12) isNumberType 属?を設定する?
253 * @og.rev 4.0.0.0 (2005/01/31) getColumnClassName ??BColumから取得する?
254 *
255 * @param column カラ?号
256 * @param ascending ソート?方向[true:??/false:降?]
257 */
258 public void sortByColumn( final int column, final boolean ascending ) {
259 this.ascending = ascending;
260 sortingColumn = column;
261 isNumberType = "NUMBER".equals( getDBColumn(sortingColumn).getClassName() );
262 sort();
263 lastColumNo = column;
264 }
265
266 /**
267 * ソート?方???:true/降?:false)を取得します?
268 *
269 * @return ソート?方?[true:??/false:降?]
270 */
271 public boolean isAscending() {
272 return ascending;
273 }
274 }