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 /** 058 * Creates a new dataset with the given database connection, and executes 059 * the supplied query to populate the dataset. 060 * 061 * @param connection the connection. 062 * @param query the query. 063 * 064 * @throws SQLException if there is a problem executing the query. 065 */ 066 public HybsJDBCCategoryDataset2( final Connection connection, final String query ) throws SQLException { 067 super( connection ); 068 innerQuery( connection,query ); 069 } 070 071 /** 072 * Populates the dataset by executing the supplied query against the 073 * existing database connection. If no connection exists then no action 074 * is taken. 075 * 076 * The results from the query are extracted and cached locally, thus 077 * applying an upper limit on how many rows can be retrieved successfully. 078 * 079 * @og.rev 4.0.0.0 (2007/11/28) new Long(long) ⇒ Long.valueOf(long) 変更 080 * @og.rev 4.0.0.0 (2007/11/28) resultSet,statement を Closer でclose する。 081 * @og.rev 4.0.0.0 (2007/11/28) Range 求めで nullポインタを参照外しの修正 082 * @og.rev 4.0.0.0 (2007/11/30) public な executeQuery メソッドを private 化します。 083 * 084 * @param con the connection. 085 * @param query the query. 086 * 087 * @throws SQLException if there is a problem executing the query. 088 */ 089 @Override 090 public void executeQuery( final Connection con, final String query ) throws SQLException { 091 innerQuery( con,query ); 092 } 093 094 /** 095 * Populates the dataset by executing the supplied query against the 096 * existing database connection. If no connection exists then no action 097 * is taken. 098 * 099 * The results from the query are extracted and cached locally, thus 100 * applying an upper limit on how many rows can be retrieved successfully. 101 * 102 * @og.rev 4.0.0.0 (2007/11/28) new Long(long) ⇒ Long.valueOf(long) 変更 103 * @og.rev 4.0.0.0 (2007/11/28) resultSet,statement を Closer でclose する。 104 * @og.rev 4.0.0.0 (2007/11/28) Range 求めで nullポインタを参照外しの修正 105 * @og.rev 5.6.2.1 (2013/03/08) Types.DATE と Types.TIMESTAMP で処理を分けます。 106 * 107 * @param con the connection. 108 * @param query the query. 109 * 110 * @throws SQLException if there is a problem executing the query. 111 */ 112 private void innerQuery( final Connection con, final String query ) throws SQLException { 113 114 Statement statement = null; 115 ResultSet resultSet = null; 116 try { 117 statement = con.createStatement(); 118 resultSet = statement.executeQuery(query); 119 ResultSetMetaData metaData = resultSet.getMetaData(); 120 121 // Range を予め求めておきます。 122 double minimum = Double.POSITIVE_INFINITY; 123 double maximum = Double.NEGATIVE_INFINITY; 124 125 int columnCount = metaData.getColumnCount(); 126 if(columnCount < 2) { 127 String errMsg = "JDBCCategoryDataset.executeQuery() : insufficient columns " 128 + "returned from the database. \n" 129 + " SQL=" + query ; 130 throw new SQLException( errMsg ); 131 } 132 133 List<Number[]> rowList = new ArrayList<Number[]>(); 134 while (resultSet.next()) { 135 Number[] clmList = new Number[columnCount-1]; 136 // first column contains the row key... 137 // Comparable rowKey = resultSet.getString(1); 138 String rowKey = resultSet.getString(1); // 4.3.3.6 (2008/11/15) Generics警告対応 139 for( int column=2; column<=columnCount; column++ ) { 140 141 // Comparable columnKey = metaData.getColumnName(column); 142 String columnKey = metaData.getColumnName(column); // 4.3.3.6 (2008/11/15) Generics警告対応 143 int columnType = metaData.getColumnType(column); 144 145 Number value = null; 146 switch (columnType) { 147 case Types.TINYINT: 148 case Types.SMALLINT: 149 case Types.INTEGER: 150 case Types.BIGINT: 151 case Types.FLOAT: 152 case Types.DOUBLE: 153 case Types.DECIMAL: 154 case Types.NUMERIC: 155 case Types.REAL: { 156 value = (Number)resultSet.getObject(column); 157 break; 158 } 159 case Types.DATE: 160 case Types.TIME: { 161 Date date = (Date) resultSet.getObject(column); 162 value = Long.valueOf(date.getTime()); 163 break; 164 } 165 // 5.6.2.1 (2013/03/08) Types.DATE と Types.TIMESTAMP で処理を分けます。 166 case Types.TIMESTAMP: { 167 Timestamp time = (Timestamp) resultSet.getObject(column); 168 value = Long.valueOf(time.getTime()); 169 break; 170 } 171 case Types.CHAR: 172 case Types.VARCHAR: 173 case Types.LONGVARCHAR: { 174 String string = (String)resultSet.getObject(column); 175 try { 176 value = Double.valueOf(string); 177 } 178 catch (NumberFormatException ex) { 179 LogWriter.log( ex ); 180 // suppress (value defaults to null) 181 } 182 break; 183 } 184 default: 185 // not a value, can't use it (defaults to null) 186 break; 187 } 188 clmList[column-2] = value; 189 setValue(value, columnKey, rowKey); 190 191 // Range 求め 192 if( value != null ) { // 4.0.0.0 (2007/11/28) 193 double dbl = value.doubleValue(); 194 if( dbl < minimum ) { minimum = dbl; } 195 if( maximum < dbl ) { maximum = dbl; } 196 } 197 } 198 rowList.add( clmList ); 199 } 200 numdata = rowList.toArray( new Number[columnCount-1][rowList.size()] ); 201 202 range = new Range( minimum, maximum ); 203 } 204 finally { 205 Closer.resultClose( resultSet ); 206 Closer.stmtClose( statement ); 207 } 208 } 209 210 /** 211 * 指定された行列から、数字オブジェクトを取得します。 212 * 213 * @param row 行番号 214 * @param column カラム番号(列番号) 215 * 216 * @return 指定の行列の値 217 */ 218 @Override 219 public Number getValue( final int row, final int column ) { 220 // 注意:行列の順序が逆です。 221 return numdata[column][row]; 222 } 223 224 /** 225 * レンジオブジェクトを取得します。(独自メソッド) 226 * 227 * @return レンジオブジェクト 228 */ 229 public Range getRange() { 230 return range; 231 } 232 233 /** 234 * この文字列と指定されたオブジェクトを比較します。 235 * 236 * 親クラスで、equals メソッドが実装されているため、警告がでます。 237 * 238 * @og.rev 5.1.8.0 (2010/07/01) findbug対応 239 * @og.rev 5.1.9.0 (2010/08/01) findbug対応 240 * 241 * @param object 比較するオブジェクト 242 * 243 * @return Objectが等しい場合は true、そうでない場合は false 244 */ 245 @Override 246 public boolean equals( final Object object ) { 247 if( super.equals( object ) ) { 248 return hsCode == ((HybsJDBCCategoryDataset2)object).hsCode; 249 } 250 return false; 251 } 252 253 /** 254 * このオブジェクトのハッシュコードを取得します。 255 * 256 * @og.rev 5.1.8.0 (2010/07/01) findbug対応 257 * @og.rev 5.1.9.0 (2010/08/01) findbug対応 258 * 259 * @return ハッシュコード 260 */ 261 @Override 262 public int hashCode() { return hsCode ; } 263}