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 java.sql.Connection; 019// import java.sql.Date; 020import java.sql.ResultSet; 021import java.sql.ResultSetMetaData; 022import java.sql.SQLException; 023import java.sql.Statement; 024// import java.sql.Types; 025// import java.util.Locale; 026 027import org.opengion.fukurou.util.Closer; 028import org.opengion.fukurou.util.LogWriter; 029 030import org.jfree.data.time.TimeSeriesCollection; 031import org.jfree.data.time.TimeSeries; 032import org.jfree.data.time.RegularTimePeriod; 033// import org.jfree.data.time.Year; // Year (int year) 034// import org.jfree.data.time.Month; // Month (int month, int year) 035// import org.jfree.data.time.Day; // Day (int day, int month, int year) 036// import org.jfree.data.time.Hour; // Hour (int hour, int day, int month, int year) 037// import org.jfree.data.time.Minute; // Minute(int minute, int hour, int day, int month, int year) 038import org.jfree.data.time.Second; // Second(int second, int minute, int hour, int day, int month, int year) 039 040/** 041 * HybsTimeSeriesCollection は、org.jfree.data.time.TimeSeriesCollection を継承したサブクラスで、 042 * オブジェクト作成とともに JDBC接続して、TimeSeries データを作成し、セットします。 043 * TimeSeriesCollection は、XYDataset のサブクラスです。 044 * 045 * TimeSeriesLineV、TimeSeriesBarV、StackedTimeSeriesLineV の場合は縦持です。 046 * 1.select series,x(時間),y(値) from XX order by series,x(時間) の縦持ちで、series のキーブレイク処理 047 * TimeSeriesLineH、TimeSeriesBarH、StackedTimeSeriesLineH の場合は横持です。 048 * 2.select x(時間),y1(値),y2(値),・・・ from XX order by x(時間) の横持 049 * series のキーブレイク処理されます。 050 * 051 * Stacked**** は、各シリーズのy(値)を、次々に加算します。各時間で実績数をセットし、最終時刻に 052 * どれだけ出来上がったかを表示するのに便利です。 053 * 054 * @og.rev 5.6.1.0 (2013/02/01) 新規作成 055 * 056 * @version 0.9.0 2001/05/05 057 * @author Kazuhiko Hasegawa 058 * @since JDK1.1, 059 */ 060public class HybsTimeSeriesCollection extends TimeSeriesCollection { 061 private static final long serialVersionUID = 561020130201L ; 062 063 private final boolean vhFlag ; // select文で series を縦持V(true)か横持H(false)かを指定。 064 private final boolean isStacked ; // データの加算処理を行うかどうか? true:行う/false:行わない 065 066 /** 067 * チャートタイプを引数にとる、コンストラクター 068 * 069 * TimeSeriesLineV、TimeSeriesBarV、StackedTimeSeriesLineV の場合は縦持です。 070 * 1.select series,x(時間),y(値) from XX order by series,x(時間) の縦持ちで、series のキーブレイク処理 071 * TimeSeriesLineH、TimeSeriesBarH、StackedTimeSeriesLineH の場合は横持です。 072 * 2.select x(時間),y1(値),y2(値),・・・ from XX order by x(時間) の横持 073 * series のキーブレイク処理されます。 074 * 075 * Stacked**** は、各シリーズのy(値)を、次々に加算します。各時間で実績数をセットし、最終時刻に 076 * どれだけ出来上がったかを表示するのに便利です。 077 * 078 * @param type チャートタイプ 079 */ 080 public HybsTimeSeriesCollection( final String type ) { 081 super(); 082 vhFlag = ( type.endsWith( "V" ) ) ; // V:縦持 = true / H:横持 = false 083 isStacked = ( type.startsWith( "Stacked" ) ) ; // Stacked:積み上げ = true 084 } 085 086 /** 087 * HybsTimeSeriesCollection オブジェクトの内部に、DB検索結果のデータを設定します。 088 * 089 * このメソッドは、series の 縦持/横持を、コンストラクターで判定しています。 090 * TimeSeriesLineV、TimeSeriesBarV、StackedTimeSeriesLineV の場合は縦持です。 091 * 1.select series,x(時間),y(値) from XX order by series,x(時間) の縦持ちで、series のキーブレイク処理 092 * TimeSeriesLineH、TimeSeriesBarH、StackedTimeSeriesLineH の場合は横持です。 093 * 2.select x(時間),y1(値),y2(値),・・・ from XX order by x(時間) の横持 094 * series のキーブレイク処理されます。 095 * 096 * @param con the connection. 097 * @param query the query. 098 * @throws SQLException データベース実行エラーが発生した場合 099 * 100 */ 101 public void executeQuery( final Connection con, final String query ) throws SQLException { 102 if( vhFlag ) { innerQueryV( con,query ); } 103 else { innerQueryH( con,query ); } 104 } 105 106 /** 107 * HybsTimeSeriesCollection オブジェクトの内部に、DB検索結果のデータを設定します(縦持)。 108 * このメソッドが呼ばれるのは、TimeSeriesLineV、TimeSeriesBarV、StackedTimeSeriesLineV の場合です。 109 * 110 * このメソッドは、series の 縦持を想定しています。 111 * 1.select series,x(時間),y(値) from XX order by series,x(時間) の縦持ちで、series のキーブレイク処理 112 * series のキーブレイク処理されます。 113 * 114 * @param con the connection. 115 * @param query the query. 116 * 117 */ 118 private void innerQueryV( final Connection con, final String query ) throws SQLException { 119 120 Statement statement = null; 121 ResultSet resultSet = null; 122 try { 123 statement = con.createStatement(); 124 resultSet = statement.executeQuery(query); 125 ResultSetMetaData metaData = resultSet.getMetaData(); 126 127 int columnCount = metaData.getColumnCount(); 128 129 if(columnCount < 3) { 130 String errMsg = "HybsTimeSeriesCollection.innerQueryV() : 実行できません。\n" 131 + "select series,x(時間),y(値) は、最低必要です。それ以降は無視します。" 132 + " SQL=" + query ; 133 throw new SQLException( errMsg ); 134 } 135 136 String bkSeries = null; // キーブレイクのための過去のSeries 137 double bkyn = 0.0; 138 139 TimeSeries timeSeries = null; 140 while (resultSet.next()) { 141 // first column contains the row key... 142 String seriVal = resultSet.getString(1); // 縦持ちの場合は、データの値がシリーズ名になる。 143 if( seriVal != null && !seriVal.equals( bkSeries ) ) { 144 if( timeSeries != null ) { addSeries( timeSeries ); } // キーブレイクでセット 145 timeSeries = new TimeSeries( seriVal ); 146 bkSeries = seriVal ; 147 bkyn = 0.0; 148 } 149 150 String dateVal = resultSet.getString(2); // x(時間) 151 RegularTimePeriod timep = getTimePeriod( dateVal ); 152 153 double yn = resultSet.getDouble(3); // y(値) 154 bkyn = ( isStacked ) ? bkyn + yn : yn ; // isStacked = true の場合は、加算していく 155 156 timeSeries.add( timep, bkyn ); 157 } 158 if( timeSeries != null ) { addSeries( timeSeries ); } // キーブレイクでセット 159 } 160 finally { 161 Closer.resultClose( resultSet ) ; 162 Closer.stmtClose( statement ) ; 163 } 164 } 165 166 /** 167 * HybsTimeSeriesCollection オブジェクトの内部に、DB検索結果のデータを設定します(横持)。 168 * このメソッドが呼ばれるのは、TimeSeriesLineH、TimeSeriesBarH、StackedTimeSeriesLineH の場合です。 169 * 170 * このメソッドは、series の 横持を想定しています。 171 * 2.select x(時間),y1(値),y2(値),・・・ from XX order by x(時間) の横持 172 * で、y1, y2 ・・・ が series として処理されます。 173 * series のラベルは、y1, y2 ・・・のカラム名になります。 174 * 175 * @param con the connection. 176 * @param query the query. 177 */ 178 private void innerQueryH( final Connection con, final String query ) throws SQLException { 179 180 Statement statement = null; 181 ResultSet resultSet = null; 182 try { 183 statement = con.createStatement(); 184 resultSet = statement.executeQuery(query); 185 ResultSetMetaData metaData = resultSet.getMetaData(); 186 187 int columnCount = metaData.getColumnCount(); 188 189 if(columnCount < 2) { 190 String errMsg = "HybsTimeSeriesCollection.innerQueryH() : 実行できません。\n" 191 + "select x(時間),y1(値),y2(値) , ・・・・ は、最低必要です。" 192 + " SQL=" + query ; 193 throw new SQLException( errMsg ); 194 } 195 196 // 各シリーズに対するカラムタイプを先に求めておく 197 int seriSu = columnCount-1; // カラム数-1( x(時間) ) 198 TimeSeries[] timeSeries = new TimeSeries[seriSu]; 199 double[] bkyn = new double[seriSu]; 200 for( int j=0; j<seriSu; j++ ) { 201 timeSeries[j] = new TimeSeries( metaData.getColumnLabel(j+2) ); // 横持の場合は、カラム名をシリーズ名にする。 202 bkyn[j] = 0.0; 203 } 204 205 while (resultSet.next()) { 206 // first column contains the row key... 207 String dateVal = resultSet.getString(1); // x(時間) 208 RegularTimePeriod timep = getTimePeriod( dateVal ); 209 210 for( int j=0; j<seriSu; j++ ) { 211 double yn = resultSet.getDouble(j+2); 212 bkyn[j] = ( isStacked ) ? bkyn[j] + yn : yn ; // isStacked = true の場合は、加算していく 213 timeSeries[j].add( timep, bkyn[j] ); 214 } 215 } 216 217 for( int j=0; j<seriSu; j++ ) { 218 addSeries( timeSeries[j] ); 219 } 220 } 221 finally { 222 Closer.resultClose( resultSet ) ; 223 Closer.stmtClose( statement ) ; 224 } 225 } 226 227 /** 228 * 日付文字列 から、RegularTimePeriodオブジェクト を生成します。 229 * 230 * このメソッドでは、日付文字列 として、"yyyyMMdd" 形式と "yyyyMMddhhmmss" 形式のみ認めています。 231 * 1.8文字以上ある場合、yyyyMMdd 部分を切り出して、年月日情報を作成します。 232 * 2.14文字以上ある場合、残りの、hhmmss 部分を切り出して、時分秒情報を作成します。 233 * 3.それ以外の場合は、"20100101000000" として、処理します。 234 * 235 * @param dateVal 日付文字列(yyyyMMddhhmmss 形式) 236 * 237 * @return RegularTimePeriodオブジェクト(Secondオブジェクト) 238 */ 239 private RegularTimePeriod getTimePeriod( final String dateVal ) { 240 int second=0, minute=0, hour=0, day=1, month=1, year=2010 ; 241 if( dateVal != null ) { 242 if( dateVal.length() >= 8 ) { 243 year = Integer.parseInt( dateVal.substring( 0,4 ) ); 244 month = Integer.parseInt( dateVal.substring( 4,6 ) ); 245 day = Integer.parseInt( dateVal.substring( 6,8 ) ); 246 } 247 if( dateVal.length() >= 14 ) { 248 hour = Integer.parseInt( dateVal.substring( 8,10 ) ); 249 minute = Integer.parseInt( dateVal.substring( 10,12 ) ); 250 second = Integer.parseInt( dateVal.substring( 12,14 ) ); 251 } 252 } 253 254 return new Second( second,minute,hour,day,month,year ) ; 255 } 256 257// private Number getNumber( final Object objVal , final int columnType ) { 258// Number value = null; 259// 260// switch (columnType) { 261// case Types.TINYINT: 262// case Types.SMALLINT: 263// case Types.INTEGER: 264// case Types.BIGINT: 265// case Types.FLOAT: 266// case Types.DOUBLE: 267// case Types.DECIMAL: 268// case Types.NUMERIC: 269// case Types.REAL: { 270// value = (Number)objVal; 271// break; 272// } 273// case Types.DATE: 274// case Types.TIME: 275// case Types.TIMESTAMP: { 276// Date date = (Date) objVal; 277// value = Long.valueOf(date.getTime()); 278// break; 279// } 280// case Types.CHAR: 281// case Types.VARCHAR: 282// case Types.LONGVARCHAR: { 283// String string = (String)objVal; 284// try { 285// value = Double.valueOf(string); 286// } 287// catch (NumberFormatException ex) { 288// // LogWriter.log( ex ); 289// // suppress (value defaults to null) 290// } 291// break; 292// } 293// default: 294// // not a value, can't use it (defaults to null) 295// break; 296// } 297// return value; 298// } 299}