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