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