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