    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 static org.opengion.fukurou.system.HybsConst.CR ;                // 6.1.0.0 (2014/12/26)
    019import org.opengion.fukurou.util.StringUtil;
    020import org.opengion.hayabusa.common.HybsSystemException;
    021import org.opengion.hayabusa.db.DBTableModel;
    022
    023import java.sql.Connection;
    024import java.sql.SQLException;
    025import java.util.Map;
    026import java.util.HashMap;
    027import java.util.Arrays;
    028
    029import org.jfree.data.jdbc.JDBCPieDataset;
    030import org.jfree.data.jdbc.JDBCXYDataset;
    031import org.jfree.data.general.Dataset;
    032import org.jfree.data.general.DefaultValueDataset;
    033
    034import org.jfree.data.xy.CategoryTableXYDataset;
    035import org.jfree.data.general.DefaultPieDataset;
    036import org.jfree.data.DefaultKeyedValues;
    037
    038import org.jfree.data.category.CategoryDataset;                 // 6.9.7.0 (2018/05/14)
    039import org.jfree.data.xy.XYDataset;                                             // 6.9.7.0 (2018/05/14)
    040import org.jfree.data.Values;                                                   // 6.9.7.0 (2018/05/14)
    041import org.jfree.data.Value;                                                    // 6.9.7.0 (2018/05/14)
    042
    043/**
    044 * ChartFactory は、Dataset および、Renderer のオブジェクトを構築するファクトリクラスです。
    045 * JFreeChart では、各種オブジェクトの組み合わせで、色々なグラフを作成できます。
    046 * ここでは、簡易的にオブジェクトを構築できるように、一つのキーワードによって、各種作成する
    047 * オブジェクトのキーワードを関連付けておきます。
    048 *
    049 * <table border="1" frame="box" rules="all" >
    050 *   <caption>各種オブジェクトの組み合わせ一覧</caption>
    051 *   <tr><th> チャートタイプ          </th><th> レンデラー(org.jfree.chart.renderer.)    </th><th> Dataset          </th></tr>
    052 *   <tr><td> HybsLine                </td><td> HybsLineRenderer                         </td><td> Category         </td></tr>
    053 *   <tr><td> LineAndShape            </td><td> category.LineAndShapeRenderer            </td><td> Category         </td></tr>
    054 *   <tr><td> Line3D                  </td><td> category.LineRenderer3D                  </td><td> Category         </td></tr>
    055 *   <tr><td> StatisticalLineAndShape </td><td> category.StatisticalLineAndShapeRenderer </td><td> Category         </td></tr>
    056 *   <tr><td> HybsParetoLine          </td><td> HybsLineRenderer                         </td><td> ParetoCategory   </td></tr>
    057 *   <tr><td> HybsBar                 </td><td> HybsBarRenderer                          </td><td> Category         </td></tr>
    058 *   <tr><td> HybsColorBar            </td><td> HybsBarRenderer                          </td><td> Category         </td></tr>
    059 *   <tr><td> Bar                     </td><td> category.BarRenderer                     </td><td> Category         </td></tr>
    060 *   <tr><td> Bar3D                   </td><td> category.BarRenderer3D                   </td><td> Category         </td></tr>
    061 *   <tr><td> HybsColorBar3D          </td><td> HybsBarRenderer3D                        </td><td> Category         </td></tr>
    062 *   <tr><td> Area                    </td><td> category.AreaRenderer                    </td><td> Category         </td></tr>
    063 *   <tr><td> HybsStackedBar          </td><td> HybsStackedBarRenderer                   </td><td> Category         </td></tr>
    064 *   <tr><td> StackedBar              </td><td> category.StackedBarRenderer              </td><td> Category         </td></tr>
    065 *   <tr><td> StackedBar3D            </td><td> category.StackedBarRenderer3D            </td><td> Category         </td></tr>
    066 *   <tr><td> StackedArea             </td><td> category.StackedAreaRenderer             </td><td> Category         </td></tr>
    067 *   <tr><td> GroupedStackedBar       </td><td> category.GroupedStackedBarRenderer       </td><td> Category         </td></tr>
    068 *   <tr><td> LayeredBar              </td><td> category.LayeredBarRenderer              </td><td> Category         </td></tr>
    069 *   <tr><td> CategoryStep            </td><td> category.CategoryStepRenderer            </td><td> Category         </td></tr>
    070 *   <tr><td> Level                   </td><td> category.LevelRenderer                   </td><td> Category         </td></tr>
    071 *   <tr><td> MinMax                  </td><td> category.MinMaxCategoryRenderer          </td><td> Category         </td></tr>
    072 *   <tr><td> WaterfallBar            </td><td> category.WaterfallBarRenderer            </td><td> Category         </td></tr>
    073 *   <tr><td> MultiplePie             </td><td> null                                     </td><td> Category         </td></tr>
    074 *   <tr><td> SpiderWeb               </td><td> null                                     </td><td> Category         </td></tr>
    075 *   <tr><td> Pie                     </td><td> null                                     </td><td> Pie              </td></tr>
    076 *   <tr><td> Pie3D                   </td><td> null                                     </td><td> Pie              </td></tr>
    077 *   <tr><td> Ring                    </td><td> null                                     </td><td> Pie              </td></tr>
    078 *   <tr><td> XYArea                  </td><td> xy.XYAreaRenderer                        </td><td> XY               </td></tr>
    079 *   <tr><td> XYArea2                 </td><td> xy.XYAreaRenderer2                       </td><td> XY               </td></tr>
    080 *   <tr><td> XYBlock                 </td><td> xy.XYBlockRenderer                       </td><td> XY               </td></tr>
    081 *   <tr><td> CyclicXYItem            </td><td> xy.CyclicXYItemRenderer                  </td><td> XY               </td></tr>
    082 *   <tr><td> HighLow                 </td><td> xy.HighLowRenderer                       </td><td> XY               </td></tr>
    083 *   <tr><td> StackedXYArea           </td><td> xy.StackedXYAreaRenderer                 </td><td> XY               </td></tr>
    084 *   <tr><td> StackedXYArea2          </td><td> xy.StackedXYAreaRenderer2                </td><td> XY               </td></tr>
    085 *   <tr><td> StandardXYItem          </td><td> xy.StandardXYItemRenderer                </td><td> XY               </td></tr>
    086 *   <tr><td> XYBubble                </td><td> xy.XYBubbleRenderer                      </td><td> XY               </td></tr>
    087 *   <tr><td> XYDifference            </td><td> xy.XYDifferenceRenderer                  </td><td> XY               </td></tr>
    088 *   <tr><td> XYDot                   </td><td> xy.XYDotRenderer                         </td><td> XY               </td></tr>
    089 *   <tr><td> XYError                 </td><td> xy.XYErrorRenderer                       </td><td> XY               </td></tr>
    090 *   <tr><td> XYLine3D                </td><td> xy.XYLine3DRenderer                      </td><td> XY               </td></tr>
    091 *   <tr><td> XYLineAndShape          </td><td> xy.XYLineAndShapeRenderer                </td><td> XY               </td></tr>
    092 *   <tr><td> XYStepArea              </td><td> xy.XYStepAreaRenderer                    </td><td> XY               </td></tr>
    093 *   <tr><td> XYStep                  </td><td> xy.XYStepRenderer                        </td><td> XY               </td></tr>
    094 *   <tr><td> PolarItem               </td><td> DefaultPolarItemRenderer                 </td><td> XY               </td></tr>
    095 *   <tr><td> Meter                   </td><td> null                                     </td><td> Value            </td></tr>
    096 *   <tr><td> Thermometer             </td><td> null                                     </td><td> Value            </td></tr>
    097 *   <tr><td> Compass                 </td><td> null                                     </td><td> Value            </td></tr>
    098 *   <tr><td> Gantt                   </td><td> category.GanttRenderer                   </td><td> TaskSeries       </td></tr>
    099 *   <tr><td> XYBarV                  </td><td> xy.XYBarRenderer                         </td><td> TimeSeries       </td></tr>
    100 *   <tr><td> ClusteredXYBarV         </td><td> xy.ClusteredXYBarRenderer                </td><td> TimeSeries       </td></tr>
    101 *   <tr><td> YIntervalV              </td><td> xy.YIntervalRenderer                     </td><td> TimeSeries       </td></tr>
    102 *   <tr><td> DeviationV              </td><td> xy.DeviationRenderer                     </td><td> TimeSeries       </td></tr>
    103 *   <tr><td> TimeSeriesLineV         </td><td> xy.StandardXYItemRenderer                </td><td> TimeSeries       </td></tr>
    104 *   <tr><td> TimeSeriesLineH         </td><td> xy.StandardXYItemRenderer                </td><td> TimeSeries       </td></tr>
    105 *   <tr><td> TimeSeriesBarV          </td><td> xy.XYBarRenderer                         </td><td> TimeSeries       </td></tr>
    106 *   <tr><td> TimeSeriesBarH          </td><td> xy.XYBarRenderer                         </td><td> TimeSeries       </td></tr>
    107 *   <tr><td> StackedTimeSeriesLineV  </td><td> xy.StandardXYItemRenderer                </td><td> TimeSeries       </td></tr>
    108 *   <tr><td> StackedTimeSeriesLineH  </td><td> xy.StandardXYItemRenderer                </td><td> TimeSeries       </td></tr>
    109 *   <tr><td> TimeStepV               </td><td> xy.XYStepRenderer                        </td><td> TimeSeries       </td></tr>
    110 *   <tr><td> TimeStepH               </td><td> xy.XYStepRenderer                        </td><td> TimeSeries       </td></tr>
    111 * </table>
    112 *
    113 * @version  0.9.0      2007/06/21
    114 * @author       Kazuhiko Hasegawa
    115 * @since        JDK1.1,
    116 */
    117public final class ChartFactory {
    118
    119        private static final String PLOT_SUB = "org.opengion.hayabusa.io.ChartPlot_" ;
    120
    121        // ChartPlot オブジェクトはマルチスレッドで使用可能なため、キャッシュして使いまわします。
    122
    123        private static ChartPlot plotCAT        ;
    124        private static ChartPlot plotXY         ;
    125        private static ChartPlot plotPIE        ;
    126        private static ChartPlot plotTIM        ;               // 5.6.1.0 (2013/02/01)
    127        private static ChartPlot plotXTIM       ;               // 5.6.1.0 (2013/02/01)
    128
    129        private static final Object LOCK = new Object();                // 6.4.1.1 (2016/01/16) lock → LOCK refactoring
    130
    131        /**
    132         * 引数タイプに応じたレンデラーやデータセットを規定します。
    133         */
    134        /** staticイニシャライザ後、読み取り専用にするので、ConcurrentHashMap を使用しません。 */
    135        private static final Map<String,TypeRenderer> TYPE_RENDERER_MAP = new HashMap<>();
    136
    137        // 4.1.1.0 (2008/02/04) HybsBar 追加
    138        // 5.3.0.0 (2010/12/01) xxxPlot 追加、データ内容修正、コメント部対応
    139        static {
    140                final String[][] data = new String[][] {
    141                        // キーワード                                        xxxRenderer                                                                     xxxDataset                              xxxPlot
    142                    {  "HybsLine"                               , "HybsLineRenderer"                                            , "Category"                    , "Category"    }
    143                  , {  "LineAndShape"                   , "category.LineAndShapeRenderer"                       , "Category"                    , "Category"    }
    144                  , {  "Line3D"                                 , "category.LineRenderer3D"                             , "Category"                    , "Category"    }
    145                  , {  "StatisticalLineAndShape", "category.StatisticalLineAndShapeRenderer", "Category"                        , "Category"    }
    146                  , {  "HybsParetoLine"                 , "HybsLineRenderer"                                            , "ParetoCategory"              , "Category"    }       // 6.0.2.1 (2014/09/26) パレート図
    147
    148                  , {  "HybsBar"                                , "HybsBarRenderer"                                                     , "Category"                    , "Category"    }
    149                  , {  "HybsColorBar"                   , "HybsBarRenderer"                                                     , "Category"                    , "Category"    }       // 6.0.2.1 (2014/09/26) カテゴリカラー
    150                  , {  "Bar"                                    , "category.BarRenderer"                                        , "Category"                    , "Category"    }
    151                  , {  "Bar3D"                                  , "category.BarRenderer3D"                                      , "Category"                    , "Category"    }
    152                  , {  "HybsColorBar3D"                 , "HybsBarRenderer3D"                                           , "Category"                    , "Category"    }       // 6.0.2.2 (2014/10/03) カテゴリカラー
    153                  , {  "Area"                                   , "category.AreaRenderer"                                       , "Category"                    , "Category"    }
    154
    155                  , {  "HybsStackedBar"                 , "HybsStackedBarRenderer"                                      , "Category"                    , "Category"    }
    156                  , {  "StackedBar"                             , "category.StackedBarRenderer"                         , "Category"                    , "Category"    }
    157                  , {  "StackedBar3D"                   , "category.StackedBarRenderer3D"                       , "Category"                    , "Category"    }
    158                  , {  "StackedArea"                    , "category.StackedAreaRenderer"                        , "Category"                    , "Category"    }
    159                  , {  "GroupedStackedBar"              , "category.GroupedStackedBarRenderer"          , "Category"                    , "Category"    }
    160
    161                  , {  "LayeredBar"                             , "category.LayeredBarRenderer"                         , "Category"                    , "Category"    }
    162
    163                  , {  "CategoryStep"                   , "category.CategoryStepRenderer"                       , "Category"                    , "Category"    }
    164                  , {  "Level"                                  , "category.LevelRenderer"                                      , "Category"                    , "Category"    }
    165
    166                  , {  "MinMax"                                 , "category.MinMaxCategoryRenderer"             , "Category"                    , "Category"    }
    167
    168                  , {  "WaterfallBar"                   , "category.WaterfallBarRenderer"                       , "Category"                    , "Category"    }
    169
    170                  , {  "MultiplePie"                    ,  null                                                                         , "Category"                    , "MultiplePie" }
    171                  , {  "SpiderWeb"                              ,  null                                                                         , "Category"                    , "SpiderWeb"   }
    172
    173        //        , {  "BoxAndWhisker"                  , "category.BoxAndWhiskerRenderer"                      , "BoxAndWhisker"               , "Category"    }
    174        //        , {  "IntervalBar"                    , "category.IntervalBarRenderer"                        , "IntervalCategory"    , "Category"    }
    175        //        , {  "StatisticalBar"                 , "category.StatisticalBarRenderer"             , "StatisticalCategory" , "Category"    }
    176        //        , {  "Candlestick"                    , "xy.CandlestickRenderer"                                      , "OHLC"                                , "XY"                  }
    177        //        , {  "StackedXYBarV"                  , "xy.StackedXYBarRenderer"                             , "TableXY"                             , "XY"                  }
    178        //        , {  "WindItem"                               , "xy.WindItemRenderer"                                         , "Wind"                                , "XY"                  }
    179        //        , {  "XYBoxAndWhisker"                , "xy.XYBoxAndWhiskerRenderer"                          , "BoxAndWhiskerXY"     , "XY"                  }
    180        //        , {  "WaferMap"                               , "WaferMapRenderer"                                            , "WaferMap"                    , "WaferMap"    }
    181        //        , {  "Contour"                                ,  null                                                                         , "Contour"                             , "Contour"             }
    182        //        , {  "FastScatter"                    ,  null                                                                         , "float2"                              , "FastScatter" }
    183
    184                  , {  "Pie"                                    ,  null                                                                         , "Pie"                                 , "Pie"                 }
    185                  , {  "Pie3D"                                  ,  null                                                                         , "Pie"                                 , "Pie"                 }
    186                  , {  "Ring"                                   ,  null                                                                         , "Pie"                                 , "Ring"                }
    187
    188                  , {  "XYArea"                                 , "xy.XYAreaRenderer"                                           , "XY"                                  , "XY"                  }
    189                  , {  "XYArea2"                                , "xy.XYAreaRenderer2"                                          , "XY"                                  , "XY"                  }
    190                  , {  "XYBlock"                                , "xy.XYBlockRenderer"                                          , "XY"                                  , "XY"                  }
    191                  , {  "CyclicXYItem"                   , "xy.CyclicXYItemRenderer"                             , "XY"                                  , "XY"                  }
    192                  , {  "HighLow"                                , "xy.HighLowRenderer"                                          , "XY"                                  , "XY"                  }
    193                  , {  "StackedXYArea"                  , "xy.StackedXYAreaRenderer"                            , "XY"                                  , "XY"                  }
    194                  , {  "StackedXYArea2"                 , "xy.StackedXYAreaRenderer2"                           , "XY"                                  , "XY"                  }
    195                  , {  "StandardXYItem"                 , "xy.StandardXYItemRenderer"                           , "XY"                                  , "XY"                  }
    196                  , {  "XYBubble"                               , "xy.XYBubbleRenderer"                                         , "XY"                                  , "XY"                  }
    197                  , {  "XYDifference"                   , "xy.XYDifferenceRenderer"                             , "XY"                                  , "XY"                  }
    198                  , {  "XYDot"                                  , "xy.XYDotRenderer"                                            , "XY"                                  , "XY"                  }
    199                  , {  "XYError"                                , "xy.XYErrorRenderer"                                          , "XY"                                  , "XY"                  }
    200                  , {  "XYLine3D"                               , "xy.XYLine3DRenderer"                                         , "XY"                                  , "XY"                  }
    201                  , {  "XYLineAndShape"                 , "xy.XYLineAndShapeRenderer"                           , "XY"                                  , "XY"                  }
    202                  , {  "XYStepArea"                             , "xy.XYStepAreaRenderer"                                       , "XY"                                  , "XY"                  }
    203                  , {  "XYStep"                                 , "xy.XYStepRenderer"                                           , "XY"                                  , "XY"                  }
    204                  , {  "PolarItem"                              , "DefaultPolarItemRenderer"                            , "XY"                                  , "Polar"               }
    205
    206                  , {  "Meter"                                  ,  null                                                                         , "Value"                               , "Meter"               }
    207                  , {  "Thermometer"                    ,  null                                                                         , "Value"                               , "Thermometer" }
    208                  , {  "Compass"                                ,  null                                                                         , "Value"                               , "Compass"             }
    209
    210                  , {  "Gantt"                                  , "category.GanttRenderer"                                      , "TaskSeries"                  , "Time"                }
    211
    212                  , {  "XYBarV"                                 , "xy.XYBarRenderer"                                            , "TimeSeries"                  , "XYTime"              }
    213                  , {  "ClusteredXYBarV"                , "xy.ClusteredXYBarRenderer"                           , "TimeSeries"                  , "XYTime"              }
    214                  , {  "YIntervalV"                     , "xy.YIntervalRenderer"                                        , "TimeSeries"                  , "XYTime"              }
    215                  , {  "DeviationV"                     , "xy.DeviationRenderer"                                        , "TimeSeries"                  , "XYTime"              }
    216                  , {  "TimeSeriesBarV"                 , "xy.XYBarRenderer"                                            , "TimeSeries"                  , "XYTime"              }       // 5.6.1.0 (2013/02/01) 時間軸を持つチャート
    217                  , {  "TimeSeriesBarH"                 , "xy.XYBarRenderer"                                            , "TimeSeries"                  , "XYTime"              }       // 5.6.1.0 (2013/02/01) 時間軸を持つチャート
    218                  , {  "TimeSeriesLineV"                , "xy.StandardXYItemRenderer"                           , "TimeSeries"                  , "XYTime"              }       // 5.6.1.0 (2013/02/01) 時間軸を持つチャート
    219                  , {  "TimeSeriesLineH"                , "xy.StandardXYItemRenderer"                           , "TimeSeries"                  , "XYTime"              }       // 5.6.1.0 (2013/02/01) 時間軸を持つチャート
    220                  , {  "StackedTimeSeriesLineV" , "xy.StandardXYItemRenderer"                           , "TimeSeries"                  , "XYTime"              }       // 5.6.1.0 (2013/02/01) 時間軸を持つチャート
    221                  , {  "StackedTimeSeriesLineH" , "xy.StandardXYItemRenderer"                           , "TimeSeries"                  , "XYTime"              }       // 5.6.1.0 (2013/02/01) 時間軸を持つチャート
    222                  , {  "TimeStepV"                              , "xy.XYStepRenderer"                                           , "TimeSeries"                  , "XYTime"              }       // 5.9.17.1 (2017/02/10) step追加
    223                  , {  "TimeStepH"                              , "xy.XYStepRenderer"                                           , "TimeSeries"                  , "XYTime"              }       // 5.9.17.1 (2017/02/10) step追加
    224                };
    225
    226                for( int i=0; i<data.length; i++ ) {
    227                        TYPE_RENDERER_MAP.put( data[i][0],new TypeRenderer( data[i][0],data[i][1],data[i][2],data[i][3] ) );
    228                }
    229        }
    230
    231        /**
    232         * デフォルトコンストラクタを private 化しておきます。
    233         *
    234         */
    235        private ChartFactory() {}
    236
    237        /**
    238         * Connection と query 文字列から、Dataset オブジェクトを作成します。
    239         *
    240         * 引数のtypeは、内部定義の TYPE_RENDERER_MAP マップで関連付けられたキーワード
    241         * より、対象とするチャート特性を取得します。(getTypeRenderer)
    242         * その TypeRenderer#getDatasetType() メソッドの値を元に、Dataset クラスは、
    243         * "org.jfree.data.jdbc.JDBC****Dataset" の **** の箇所を特定します。
    244         * 現状は、Category , ParetoCategory , Pie , XY の３種類 ＋ Valueデータセットが選択されます。
    245         *
    246         * @og.rev 3.8.9.2 (2007/07/28) HybsJDBCCategoryDataset 追加
    247         * @og.rev 5.3.0.0 (2010/12/01) その他のDataset 追加
    248         * @og.rev 5.6.1.0 (2013/02/01) 時間軸を持つチャート TimeSeries 追加
    249         * @og.rev 6.0.2.0 (2014/09/19) シリーズのラベル名配列追加
    250         * @og.rev 6.0.2.1 (2014/09/26) パレート図用のDataset ParetoCategory 追加
    251         * @og.rev 6.0.2.2 (2014/10/03) カテゴリのカラー名指定 useCategoryColor 追加
    252         *
    253         * @param       conn    Dataset の取得先のコネクション
    254         * @param       query   取得するクエリー文字列
    255         * @param       type    Dataset オブジェクトの作成元を求めるキーワード
    256         * @param       lbls    シリーズのラベル名配列
    257         * @param       useCateColor    カテゴリのカラー名指定 [false:指定しない/true:指定する]
    258         *
    259         * @return      Datasetオブジェクト
    260         *
    261         * @see     #getTypeRenderer( String )
    262         * @see     #newDataset( DBTableModel ,String ,String[] ,boolean )
    263         * @throws SQLException データベースアクセスエラー
    264         */
    265        public static Dataset newDataset( final Connection conn,final String query,
    266                                                                          final String type,final String[] lbls,final boolean useCateColor )
    267                                                                        throws SQLException {
    268                final Dataset dataset ;
    269
    270                final TypeRenderer rend = getTypeRenderer( type );
    271
    272                final String dsType = rend.getDatasetType();
    273                // 6.0.2.1 (2014/09/26) パレート図用のDataset ParetoCategory 追加
    274                final boolean isPareto = "ParetoCategory".equalsIgnoreCase( dsType );
    275                if( "Category".equalsIgnoreCase( dsType ) || isPareto ) {
    276                        final HybsCategoryDataset hData = new HybsCategoryDataset();
    277                        hData.initParam( lbls,useCateColor,isPareto );
    278                        hData.execute( conn, query );
    279                        dataset = hData ;
    280                }
    281                else if( "XY".equalsIgnoreCase( dsType ) ) {
    282                        dataset = new JDBCXYDataset( conn, query );
    283                }
    284                else if( "Pie".equalsIgnoreCase( dsType ) ) {
    285                        dataset = new JDBCPieDataset( conn, query );
    286                }
    287                else if( "Value".equalsIgnoreCase( dsType ) ) {
    288                        dataset = new DefaultValueDataset();
    289                }
    290                // 5.3.0.0 (2010/12/01) その他のDataset 追加
    291        //      else if( "GanttCategory".equalsIgnoreCase( dsType ) ) {
    292        //              dataset = new HybsJDBCCategoryDataset2( conn, query );          // 代替
    293        //      }
    294        //      else if( "IntervalCategory".equalsIgnoreCase( dsType ) ) {
    295        //              dataset = new HybsJDBCCategoryDataset2( conn, query );          // 代替
    296        //      }
    297        //      else if( "StatisticalCategory".equalsIgnoreCase( dsType ) ) {
    298        //              dataset = new HybsJDBCCategoryDataset2( conn, query );          // 代替
    299        //      }
    300                else if( "TimeSeries".equalsIgnoreCase( dsType ) ) {
    301                        dataset = new HybsTimeSeriesCollection( type  );                                        // 5.6.1.0 (2013/02/01) 時間軸を持つチャート
    302                        ((HybsTimeSeriesCollection)dataset).executeQuery( conn, query );
    303                }
    304                else if( "TaskSeries".equalsIgnoreCase( dsType ) ) {
    305                        dataset = new HybsTaskSeriesCollection();                                                       // 5.6.1.0 (2013/02/01) タスク情報を持つチャート
    306                        ((HybsTaskSeriesCollection)dataset).executeQuery( conn, query );
    307                }
    308                else {
    309                        final String errMsg = "Category,ParetoCategory,Pie,XY,Value,TimeSeries 以外のDataset はサポートしていません。[" + dsType + "]";
    310                        throw new HybsSystemException( errMsg );
    311                }
    312
    313                return dataset ;
    314        }
    315
    316        /**
    317         * DBTableModelオブジェクトから、Dataset オブジェクトを作成します。
    318         *
    319         * 引数のtypeは、内部定義の TYPE_RENDERER_MAP マップで関連付けられたキーワード
    320         * より、対象とするチャート特性を取得します。(getTypeRenderer)
    321         * その TypeRenderer#getDatasetType() メソッドの値を元に、Dataset クラスを作成します。
    322         *
    323         * 現状は、Category , ParetoCategory , Pie , XY の３種類 ＋ Valueデータセットが選択されます。
    324         *
    325         * ※ DBTableModel の row,col と、Dataset の row,col は、逆になっています。
    326         *
    327         * @og.rev 5.3.0.0 (2010/12/01) 新規追加
    328         * @og.rev 6.0.2.0 (2014/09/19) シリーズのラベル名配列追加
    329         * @og.rev 6.0.2.1 (2014/09/26) パレート図用のDataset ParetoCategory 追加
    330         * @og.rev 6.0.2.2 (2014/10/03) カテゴリのカラー名指定 useCategoryColor 追加
    331         *
    332         * @param       table   Dataset の取得先のテーブルモデル
    333         * @param       type    Dataset オブジェクトの作成元を求めるキーワード
    334         * @param       lbls    シリーズのラベル名配列
    335         * @param       useCateColor    カテゴリのカラー名指定 [false:指定しない/true:指定する]
    336         *
    337         * @return      Datasetオブジェクト
    338         *
    339         * @see     #getTypeRenderer( String )
    340         * @see     #newDataset( Connection ,String ,String ,String[] ,boolean )
    341         */
    342        public static Dataset newDataset( final DBTableModel table ,
    343                                                                          final String type,final String[] lbls,final boolean useCateColor ) {
    344                final Dataset dataset ;
    345
    346                final TypeRenderer rend = getTypeRenderer( type );
    347                final int clmNo = table.getColumnCount();
    348                final int rowNo = table.getRowCount();
    349
    350                final String dsType = rend.getDatasetType();
    351                // 6.0.2.1 (2014/09/26) パレート図用のDataset ParetoCategory 追加
    352                final boolean isPareto = "ParetoCategory".equalsIgnoreCase( dsType );
    353                if( "Category".equalsIgnoreCase( dsType ) || isPareto ) {
    354                        // select key,val1,val2,val3 ･･･ from ･･･
    355
    356                        final String[] seri = getSeriesLabels( table,lbls );            // 6.0.2.0 (2014/09/19) シリーズのラベル名配列追加
    357
    358                        final HybsCategoryDataset hData = new HybsCategoryDataset();
    359                        hData.initParam( seri,useCateColor,isPareto );
    360                        hData.execute( table );
    361                        dataset = hData ;
    362
    363                }
    364                else if( "XY".equalsIgnoreCase( dsType ) ) {
    365                        // select valx,valy from ･･･
    366
    367                        final CategoryTableXYDataset xyDataset = new CategoryTableXYDataset() ;
    368                        // 6.0.2.0 (2014/09/19) シリーズのラベル名配列追加
    369                        final String[] seri = getSeriesLabels( table,lbls );            // 6.0.2.0 (2014/09/19) シリーズのラベル名配列追加
    370
    371                        for( int row=0; row<rowNo; row++ ) {
    372                                final String[] vals   = table.getValues( row );
    373                                final double rval = vals[0] == null || vals[0].isEmpty() ? 0.0d : Double.parseDouble( vals[0] );                // 6.4.2.1 (2016/02/05) PMD refactoring. Useless parentheses.
    374                                for( int clm=1; clm<clmNo; clm++ ) {            // ２番目(アドレス=1)からカラムデータを取得
    375                                        final String sval = vals[clm];
    376                                        final double val  = sval == null || sval.isEmpty() ? 0.0d : Double.parseDouble( sval ) ;                // 6.4.2.1 (2016/02/05) PMD refactoring. Useless parentheses.
    377                                        xyDataset.add( rval,val,seri[clm] );
    378                                }
    379                        }
    380
    381                        dataset = xyDataset;
    382                }
    383                else if( "Pie".equalsIgnoreCase( dsType ) ) {
    384                        // select key,val from ･･･
    385
    386                        final DefaultKeyedValues keyVal = new DefaultKeyedValues();
    387                        for( int row=0; row<rowNo; row++ ) {
    388                                final String[] vals   = table.getValues( row );
    389
    390                                final String key  = vals[0];    // KEY項目
    391                                final String sval = vals[1];    // VALUE項目
    392                                final double val = sval == null || sval.isEmpty() ? 0.0d : Double.parseDouble( sval ) ;         // 6.4.2.1 (2016/02/05) PMD refactoring. Useless parentheses.
    393                                keyVal.addValue( key ,val );
    394                        }
    395                        dataset = new DefaultPieDataset( keyVal );
    396                }
    397                else if( "Value".equalsIgnoreCase( dsType ) ) {
    398                        // Value は、オブジェクトを作成するだけ。値は、markValues を ChartDataset.java で設定
    399                        dataset = new DefaultValueDataset();
    400                }
    401                // 5.3.0.0 (2010/12/01) その他のDataset 追加
    402        //      else if( "GanttCategory".equalsIgnoreCase( dsType ) ) {
    403        //              dataset = new TaskSeriesCollection();
    404        //      }
    405        //      else if( "IntervalCategory".equalsIgnoreCase( dsType ) ) {
    406        //              dataset = new DefaultIntervalCategoryDataset( String[] seriesNames, Number[][] starts, Number[][] ends) ;
    407        //      }
    408        //      else if( "StatisticalCategory".equalsIgnoreCase( dsType ) ) {
    409        //              dataset = new DefaultStatisticalCategoryDataset();
    410        //      }
    411        //      else if( "Wind".equalsIgnoreCase( dsType ) ) {
    412        //              dataset = new DefaultWindDataset(java.lang.String[] seriesNames, java.lang.Object[][][] data);
    413        //      }
    414        //      else if( "OHLC".equalsIgnoreCase( dsType ) ) {
    415        //              dataset = new DefaultOHLCDataset(java.lang.Comparable key, OHLCDataItem[] data);
    416        //      }
    417        //      else if( "BoxAndWhiskerXY".equalsIgnoreCase( dsType ) ) {
    418        //              dataset = new org.jfree.data.statistics.DefaultBoxAndWhiskerXYDataset(java.lang.Comparable seriesKey);
    419        //      }
    420        //      else if( "WaferMap".equalsIgnoreCase( dsType ) ) {
    421        //              dataset = new JDBCXYDataset( conn, query );
    422        //      }
    423        //      else if( "float2".equalsIgnoreCase( dsType ) ) {
    424        //              float[][] を返すので、ここでは使えない。
    425        //      }
    426                else {
    427                        final String errMsg = "Category,ParetoCategory,Pie,XY,Value 以外のDataset はサポートしていません。[" + dsType + "]";
    428                        throw new HybsSystemException( errMsg );
    429                }
    430
    431                return dataset ;
    432        }
    433
    434        /**
    435         * Datasetオブジェクトのデータ件数を返します。
    436         *
    437         * org.jfree.data.general.Dataset には、共通に利用できる件数取得のメソッドが定義されていません。
    438         * なので、個々のクラスごとに、取得します。
    439         * ChartFactory に持っているのは、このクラスで、Dataset の実態を作成している関係上、
    440         * 新しいクラスを追加時に、このメソッドの手直しが必要になるからです。
    441         *
    442         * @og.rev 6.9.7.0 (2018/05/14) データ０件の対応。
    443         *
    444         * @param       dataset Datasetオブジェクト
    445         * @return      データ件数
    446         */
    447        public static int getRowCount( final Dataset dataset ) {
    448                if( dataset == null ) {
    449                        return 0;
    450                }
    451                else if( dataset instanceof CategoryDataset ) {
    452                        return ((CategoryDataset)dataset).getRowCount();
    453                }
    454                else if( dataset instanceof XYDataset ) {
    455                        final XYDataset xyData = (XYDataset)dataset;
    456                        int cnt = 0;
    457                        for( int i=0; i<xyData.getSeriesCount(); i++ ) {
    458                                for( int j=0; j<xyData.getItemCount( i ); j++ ) {
    459                                        cnt++ ;
    460                                }
    461                        }
    462
    463                        return cnt;
    464                }
    465                else if( dataset instanceof Values ) {
    466                        return ((Values)dataset).getItemCount();
    467                }
    468                else if( dataset instanceof Value ) {
    469                        return ((Value)dataset).getValue() == null ? 0 : 1 ;
    470                }
    471                else {
    472                        final String errMsg = "Category,ParetoCategory,Pie,XY,Value 以外のDataset はサポートしていません。" + dataset.getClass();
    473                        throw new HybsSystemException( errMsg );
    474                }
    475        }
    476
    477        /**
    478         * シリーズのラベル名配列を作成します。
    479         *
    480         * シリーズのラベル名配列が null でない場合は、その配列から、そうでない場合は、
    481         * DBTableModelオブジェクトから、ラベル名配列を作成します。
    482         *
    483         * シリーズのラベル名配列追加引数は、DBTableModelオブジェクトのカラム数ー１ でなければなりません。
    484         * シリーズのラベルは、以前は、テーブルのカラムそのものでしたが、リソースを経由したラベルに変更します。
    485         * また、ここで返すラベルの配列は、ゼロ番目が、カラム順の１番目になります。
    486         * カラムの０番目は、カテゴリなので、シリーズのラベル名としては使用しません。
    487         * COLOR対応の場合は、最後のカラムが、色コードになり、ラベルとしては使いませんが、
    488         * ここで作成する配列には、含まれます。利用する側で、COLORの場合は、無視するだけです。
    489         *
    490         * @og.rev 6.0.2.0 (2014/09/19) 新規追加
    491         *
    492         * @param       table   Datasetの取得先のテーブルモデル
    493         * @param       lbls    0から始まるシリーズのラベル名配列(可変長引数)
    494         *
    495         * @return      カラム名の配列(0...)(ラベル化されている)
    496         */
    497        private static String[] getSeriesLabels( final DBTableModel table , final String... lbls ) {
    498                final int clmNo = table.getColumnCount();
    499
    500                // 6.0.2.0 (2014/09/19) シリーズのラベル名配列を使うときは、必ずカラム数ー１以上必要
    501                // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
    502                if( lbls != null && lbls.length < clmNo-1 ) {
    503                                final String errMsg = "seriesLabels を使用する場合は、必ず(カラム数ー１)以上にしてください。"
    504                                                        + CR
    505                                                        + " seriesLabels.length=" + lbls.length
    506                                                        + " columnCount=" + clmNo
    507                                                        + CR
    508                                                        + " seriesLabels=" + Arrays.toString( lbls )
    509                                                        + CR ;
    510                        throw new IllegalArgumentException( errMsg );
    511                }
    512
    513                String[] series = new String[clmNo-1];
    514                for( int i=0; i<clmNo-1; i++ ) {
    515                        // 6.1.1.0 (2015/01/17) 可変長引数でもnullは来る。
    516                        // 6.4.1.1 (2016/01/16) PMD refactoring. Avoid if (x != y) ..; else ..;
    517                        series[i] = lbls == null || lbls[i] == null ? table.getColumnLabel(i+1) : lbls[i];
    518                }
    519                return series;
    520        }
    521
    522        /**
    523         * TypeRenderer オブジェクトを作成します。
    524         *
    525         * 引数のtypeは、内部定義の TYPE_RENDERER_MAP マップで関連付けられたキーワード
    526         * より、対象とするチャート特性を取得します。
    527         * typeは、org.jfree.chart.renderer.XXXX.YYYYRenderer のYYYY とほぼ一致します。
    528         * TYPE_RENDERER_MAP マップには、XXXX.YYYYRenderer 部分が定義されています。
    529         * XXXX は、category と xy が定義されており、それ以外のレンデラーは null に
    530         * なっています。Pie 関係は、レンデラーではなく、Plot と対応します。
    531         * ただし、個々に設定情報が異なる為、ChartPlot_Pie クラスで個別対応しています。
    532         *
    533         * @param       type    Rendererオブジェクトの作成元を求めるキーワード
    534         *
    535         * @return      TypeRendererオブジェクト
    536         */
    537        public static TypeRenderer getTypeRenderer( final String type ) {
    538                final TypeRenderer rend = TYPE_RENDERER_MAP.get( type );
    539
    540                if( rend == null ) {
    541                        final String errMsg = "指定のタイプに該当する Renderer はサポートしていません。[" + type + "]"
    542                                        + CR
    543                                        + "Key=" + Arrays.toString( TYPE_RENDERER_MAP.keySet().toArray( new String[TYPE_RENDERER_MAP.size()] ) );
    544                        throw new HybsSystemException( errMsg );
    545                }
    546
    547                return rend ;
    548        }
    549
    550        /**
    551         * ChartPlot オブジェクトを作成します。
    552         *
    553         * ChartPlot オブジェクトは、ChartPlot インターフェースを継承した
    554         * サブクラスで、"org.opengion.hayabusa.io.ChartPlot_**** になります。
    555         * **** には、Category , Pie , XY が指定できます。
    556         *
    557         * @og.rev 4.0.0.0 (2007/11/29) ChartPlot のサブクラスを動的に作成、キャッシュします。
    558         * @og.rev 5.3.0.0 (2010/12/01) xxxPlot対応
    559         * @og.rev 5.6.1.0 (2013/02/01) 時間軸を持つチャート TimeSeries 追加
    560         *
    561         * @param       type    Rendererオブジェクトの作成元を求めるキーワード
    562         *
    563         * @return      ChartPlotオブジェクト
    564         */
    565        public static ChartPlot newChartPlot( final String type ) {
    566
    567                final ChartPlot plot ;
    568
    569                final TypeRenderer rend = TYPE_RENDERER_MAP.get( type );
    570
    571                final String pltType = rend.getPlotType();                      // 5.3.0.0 (2010/12/01) xxxPlot対応
    572                if( "Category".equalsIgnoreCase( pltType ) ) {
    573                        synchronized( LOCK ) {
    574                                if( plotCAT == null ) {
    575                                        plotCAT = (ChartPlot)StringUtil.newInstance( PLOT_SUB + pltType ) ;
    576                                }
    577                        }
    578                        plot = plotCAT;
    579                }
    580                else if( "XY".equalsIgnoreCase( pltType ) ) {
    581                        synchronized( LOCK ) {
    582                                if( plotXY == null ) {
    583                                        plotXY = (ChartPlot)StringUtil.newInstance( PLOT_SUB + pltType ) ;
    584                                }
    585                        }
    586                        plot = plotXY;
    587                }
    588                // 5.6.1.0 (2013/02/01) 時間軸を持つチャート
    589                else if( "Time".equalsIgnoreCase( pltType ) ) {
    590                        synchronized( LOCK ) {
    591                                if( plotTIM == null ) {
    592                                        plotTIM = (ChartPlot)StringUtil.newInstance( PLOT_SUB + pltType ) ;
    593                                }
    594                        }
    595                        plot = plotTIM;
    596                }
    597                // 5.6.1.0 (2013/02/01) 時間軸を持つチャート
    598                else if( "XYTime".equalsIgnoreCase( pltType ) ) {
    599                        synchronized( LOCK ) {
    600                                if( plotXTIM == null ) {
    601                                        plotXTIM = (ChartPlot)StringUtil.newInstance( PLOT_SUB + pltType ) ;
    602                                }
    603                        }
    604                        plot = plotXTIM;
    605                }
    606                else {
    607                        synchronized( LOCK ) {
    608                                if( plotPIE == null ) {
    609                                        plotPIE = (ChartPlot)StringUtil.newInstance( PLOT_SUB + "Pie" ) ;
    610                                }
    611                        }
    612                        plot = plotPIE;
    613                }
    614
    615                return plot ;
    616        }
    617}