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