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