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.io; 017 018import org.opengion.fukurou.util.Closer ; 019import org.opengion.fukurou.util.LogWriter; 020 021import java.sql.Connection; 022import java.sql.Date; 023import java.sql.Timestamp; 024import java.sql.ResultSet; 025import java.sql.ResultSetMetaData; 026import java.sql.SQLException; 027import java.sql.Statement; 028import java.sql.Types; 029 030import java.util.List; 031import java.util.ArrayList; 032 033import org.jfree.data.jdbc.JDBCCategoryDataset; 034import org.jfree.data.Range; 035 036/** 037 * HybsJDBCCategoryDataset は、org.jfree.data.jdbc.JDBCCategoryDataset を継承したサブクラスで、 038 * executeQuery(Connection , String ) をオーバーライドしています。 039 * これは、元のソースのデータベース検索結果を内部で持っておき、getValue(int row, int column) 040 * メソッドで直接値を返します。 041 * series の横持ち(標準と同じ) 対応です。 042 * 参考:JFreeChart : a free chart library for the Java(tm) platform(jfreechart-1.0.6) 043 * 044 * @og.rev 3.8.9.2 (2007/07/28) 新規作成 045 * 046 * @version 0.9.0 2001/05/05 047 * @author Kazuhiko Hasegawa 048 * @since JDK1.1, 049 */ 050public class HybsJDBCCategoryDataset2 extends JDBCCategoryDataset { 051 private static final long serialVersionUID = 562120130308L ; 052 053 private Number[][] numdata = null; 054 private Range range = null; 055 private final int hsCode = Long.valueOf( System.nanoTime() ).hashCode() ; // 5.1.9.0 (2010/08/01) equals,hashCode 056 057 // 4.3.5.0 (2009/02/01) 各オブジェクトを特定するためのユニークな番号 058// private final int uniqNo = Double.valueOf( Math.random() ).hashCode() ; // 5.1.8.0 (2010/07/01) 廃止 059 060 /** 061 * Creates a new dataset with the given database connection, and executes 062 * the supplied query to populate the dataset. 063 * 064 * @param connection the connection. 065 * @param query the query. 066 * 067 * @throws SQLException if there is a problem executing the query. 068 */ 069 public HybsJDBCCategoryDataset2( final Connection connection, final String query ) throws SQLException { 070 super( connection ); 071 innerQuery( connection,query ); 072 } 073 074 /** 075 * Populates the dataset by executing the supplied query against the 076 * existing database connection. If no connection exists then no action 077 * is taken. 078 * 079 * The results from the query are extracted and cached locally, thus 080 * applying an upper limit on how many rows can be retrieved successfully. 081 * 082 * @og.rev 4.0.0.0 (2007/11/28) new Long(long) ⇒ Long.valueOf(long) 変更 083 * @og.rev 4.0.0.0 (2007/11/28) resultSet,statement を Closer でclose する。 084 * @og.rev 4.0.0.0 (2007/11/28) Range 求めで nullポインタを参照外しの修正 085 * @og.rev 4.0.0.0 (2007/11/30) public な executeQuery メソッドを private 化します。 086 * 087 * @param con the connection. 088 * @param query the query. 089 * 090 * @throws SQLException if there is a problem executing the query. 091 */ 092 @Override 093 public void executeQuery( final Connection con, final String query ) throws SQLException { 094 innerQuery( con,query ); 095 } 096 097 /** 098 * Populates the dataset by executing the supplied query against the 099 * existing database connection. If no connection exists then no action 100 * is taken. 101 * 102 * The results from the query are extracted and cached locally, thus 103 * applying an upper limit on how many rows can be retrieved successfully. 104 * 105 * @og.rev 4.0.0.0 (2007/11/28) new Long(long) ⇒ Long.valueOf(long) 変更 106 * @og.rev 4.0.0.0 (2007/11/28) resultSet,statement を Closer でclose する。 107 * @og.rev 4.0.0.0 (2007/11/28) Range 求めで nullポインタを参照外しの修正 108 * @og.rev 5.6.2.1 (2013/03/08) Types.DATE と Types.TIMESTAMP で処理を分けます。 109 * 110 * @param con the connection. 111 * @param query the query. 112 * 113 * @throws SQLException if there is a problem executing the query. 114 */ 115 private void innerQuery( final Connection con, final String query ) throws SQLException { 116 117 Statement statement = null; 118 ResultSet resultSet = null; 119 try { 120 statement = con.createStatement(); 121 resultSet = statement.executeQuery(query); 122 ResultSetMetaData metaData = resultSet.getMetaData(); 123 124 // Range を予め求めておきます。 125 double minimum = Double.POSITIVE_INFINITY; 126 double maximum = Double.NEGATIVE_INFINITY; 127 128 int columnCount = metaData.getColumnCount(); 129 if(columnCount < 2) { 130 String errMsg = "JDBCCategoryDataset.executeQuery() : insufficient columns " 131 + "returned from the database. \n" 132 + " SQL=" + query ; 133 throw new SQLException( errMsg ); 134 } 135 136 List<Number[]> rowList = new ArrayList<Number[]>(); 137 while (resultSet.next()) { 138 Number[] clmList = new Number[columnCount-1]; 139 // first column contains the row key... 140 // Comparable rowKey = resultSet.getString(1); 141 String rowKey = resultSet.getString(1); // 4.3.3.6 (2008/11/15) Generics警告対応 142 for( int column=2; column<=columnCount; column++ ) { 143 144 // Comparable columnKey = metaData.getColumnName(column); 145 String columnKey = metaData.getColumnName(column); // 4.3.3.6 (2008/11/15) Generics警告対応 146 int columnType = metaData.getColumnType(column); 147 148 Number value = null; 149 switch (columnType) { 150 case Types.TINYINT: 151 case Types.SMALLINT: 152 case Types.INTEGER: 153 case Types.BIGINT: 154 case Types.FLOAT: 155 case Types.DOUBLE: 156 case Types.DECIMAL: 157 case Types.NUMERIC: 158 case Types.REAL: { 159 value = (Number)resultSet.getObject(column); 160 break; 161 } 162 case Types.DATE: 163 case Types.TIME: { 164 Date date = (Date) resultSet.getObject(column); 165 value = Long.valueOf(date.getTime()); 166 break; 167 } 168 // 5.6.2.1 (2013/03/08) Types.DATE と Types.TIMESTAMP で処理を分けます。 169 case Types.TIMESTAMP: { 170 Timestamp time = (Timestamp) resultSet.getObject(column); 171 value = Long.valueOf(time.getTime()); 172 break; 173 } 174 case Types.CHAR: 175 case Types.VARCHAR: 176 case Types.LONGVARCHAR: { 177 String string = (String)resultSet.getObject(column); 178 try { 179 value = Double.valueOf(string); 180 } 181 catch (NumberFormatException ex) { 182 LogWriter.log( ex ); 183 // suppress (value defaults to null) 184 } 185 break; 186 } 187 default: 188 // not a value, can't use it (defaults to null) 189 break; 190 } 191 clmList[column-2] = value; 192 setValue(value, columnKey, rowKey); 193 194 // Range 求め 195 if( value != null ) { // 4.0.0.0 (2007/11/28) 196 double dbl = value.doubleValue(); 197 if( dbl < minimum ) { minimum = dbl; } 198 if( maximum < dbl ) { maximum = dbl; } 199 } 200 } 201 rowList.add( clmList ); 202 } 203 numdata = rowList.toArray( new Number[columnCount-1][rowList.size()] ); 204 205 range = new Range( minimum, maximum ); 206 } 207 finally { 208 Closer.resultClose( resultSet ); 209 Closer.stmtClose( statement ); 210 } 211 } 212 213 /** 214 * 指定された行列から、数字オブジェクトを取得します。 215 * 216 * @param row 行番号 217 * @param column カラム番号(列番号) 218 * 219 * @return 指定の行列の値 220 */ 221 @Override 222 public Number getValue( final int row, final int column ) { 223 // 注意:行列の順序が逆です。 224 return numdata[column][row]; 225 } 226 227 /** 228 * レンジオブジェクトを取得します。(独自メソッド) 229 * 230 * @return レンジオブジェクト 231 */ 232 public Range getRange() { 233 return range; 234 } 235 236 /** 237 * この文字列と指定されたオブジェクトを比較します。 238 * 239 * 親クラスで、equals メソッドが実装されているため、警告がでます。 240 * 241 * @og.rev 5.1.8.0 (2010/07/01) findbug対応 242 * @og.rev 5.1.9.0 (2010/08/01) findbug対応 243 * 244 * @param object 比較するオブジェクト 245 * 246 * @return Objectが等しい場合は true、そうでない場合は false 247 */ 248 @Override 249 public boolean equals( final Object object ) { 250// return super.equals( object ); 251 if( super.equals( object ) ) { 252 return hsCode == ((HybsJDBCCategoryDataset2)object).hsCode; 253 } 254 return false; 255 } 256 257 /** 258 * このオブジェクトのハッシュコードを取得します。 259 * 260 * @og.rev 5.1.8.0 (2010/07/01) findbug対応 261 * @og.rev 5.1.9.0 (2010/08/01) findbug対応 262 * 263 * @return ハッシュコード 264 */ 265// public int hashCode() { return super.hashCode() ; } 266 @Override 267 public int hashCode() { return hsCode ; } 268 269 /** 270 * このオブジェクトと指定されたオブジェクトを比較します。 271 * 272 * @og.rev 4.0.0.0 (2007/11/28) 新規追加 273 * @og.rev 4.3.5.0 (2009/02/01) 同一オブジェクトかどうかの判定方法変更 274 * @og.rev 5.1.8.0 (2010/07/01) 廃止 275 * 276 * @param anObject Object 比較されるオブジェクト 277 * 278 * @return 指定されたオブジェクトが等しい場合は true、そうでない場合は false 279 */ 280// public boolean equals( final Object anObject ) { 281// // if( anObject instanceof HybsJDBCCategoryDataset2 ) { 282// // HybsJDBCCategoryDataset2 other = (HybsJDBCCategoryDataset2)anObject ; 283// // return ( uniqNo == other.uniqNo ) ; 284// // } 285// // return false ; 286// 287// if( super.equals( anObject ) ) { 288// HybsJDBCCategoryDataset2 other = ((HybsJDBCCategoryDataset2)anObject); 289// if( numdata != null && numdata == other.numdata && 290// range != null && range.equals( other.range ) ) { 291// return true; 292// } 293// } 294// return false; 295// } 296 297 /** 298 * このオブジェクトのハッシュコードを返します。 299 * 300 * @og.rev 4.0.0.0 (2007/11/28) 新規追加 301 * @og.rev 4.3.5.0 (2009/02/01) ハッシュの求め方を変更 302 * @og.rev 5.1.8.0 (2010/07/01) 廃止 303 * 304 * @return このオブジェクトのハッシュコード値 305 */ 306// public int hashCode() { 307// // return uniqNo; 308// return super.hashCode() + 309// ((numdata == null) ? 0 : numdata.hashCode()) + 310// ((range == null) ? 0 : range.hashCode()) ; 311// } 312}