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