0001: /*
0002: * (C) Copyright 2000 - 2003 Nabh Information Systems, Inc.
0003: *
0004: * This program is free software; you can redistribute it and/or
0005: * modify it under the terms of the GNU General Public License
0006: * as published by the Free Software Foundation; either version 2
0007: * of the License, or (at your option) any later version.
0008: *
0009: * This program is distributed in the hope that it will be useful,
0010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
0012: * GNU General Public License for more details.
0013: *
0014: * You should have received a copy of the GNU General Public License
0015: * along with this program; if not, write to the Free Software
0016: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
0017: *
0018: */
0019:
0020: package com.nabhinc.portlet.chart;
0021:
0022: import java.io.*;
0023: import java.net.MalformedURLException;
0024: import java.net.URL;
0025: import java.util.*;
0026:
0027: import java.awt.Color;
0028: import java.awt.Font;
0029: import java.awt.Image;
0030: import java.awt.Toolkit;
0031:
0032: import javax.portlet.PortletConfig;
0033: import javax.portlet.PortletException;
0034: import javax.portlet.PortletSession;
0035: import javax.portlet.RenderRequest;
0036: import javax.portlet.RenderResponse;
0037: import javax.portlet.UnavailableException;
0038: import javax.portlet.WindowState;
0039:
0040: import org.jfree.chart.ChartFactory;
0041: import org.jfree.chart.ChartUtilities;
0042: import org.jfree.chart.JFreeChart;
0043: import org.jfree.chart.plot.Pie3DPlot;
0044: import org.jfree.chart.plot.PiePlot;
0045: import org.jfree.chart.plot.Plot;
0046: import org.jfree.chart.plot.VerticalCategoryPlot;
0047: import org.jfree.data.CategoryDataset;
0048: import org.jfree.data.PieDataset;
0049: import org.jfree.data.HighLowDataset;
0050: import org.jfree.data.XYDataset;
0051:
0052: import com.nabhinc.portlet.base.BasePortlet;
0053: import com.nabhinc.util.StringUtil;
0054:
0055: /**
0056: *
0057: *
0058: * @author Padmanabh Dabke
0059: * (c) 2002 Nabh Information Systems, Inc. All Rights Reserved.
0060: */
0061: public class ChartPortlet extends BasePortlet {
0062:
0063: private static int cpCounter = 0;
0064:
0065: public static final String[] CHART_TYPES = { "area", "area-xy",
0066: "horizontal-bar", "horizontal-bar-3d", "line", "pie",
0067: "scatter", "stacked-horizontal-bar",
0068: "stacked-vertical-bar", "stacked-vertical-bar-3d",
0069: "timeseries", "vertical-bar", "vertical-bar-3d", "line-xy",
0070: "candlestick", "high-low-close", "gantt", "wind", "signal",
0071: "vertical-xy-bar", "pie3d" };
0072:
0073: public static final List CHART_TYPE_LIST = Arrays
0074: .asList(CHART_TYPES);
0075:
0076: public static final String PORTLET_WIDTH_ATTRIB = "portletWidthAttribute";
0077:
0078: /**
0079: * Parameter name for the dataset class used for creating the specific type
0080: * of the chart. In the future, the dataset class will be map to the specified
0081: * chart's type, so that it does not need to be specified explicitly. For now,
0082: * <code>dataSourceClass</code> is required.
0083: */
0084: public static final String DATA_SOURCE_CLASS = "dataSourceClass";
0085:
0086: /**
0087: * Parameter name for chart's type. If <code>chartType</code> is not
0088: * defined, the default <code>line</code> type will be used.
0089: */
0090: public static final String CHART_TYPE = "chartType";
0091:
0092: //public static final String REFRESH_PERIOD = "refreshPeriod";
0093:
0094: /**
0095: * Parameter name for chart's aspect ratio. The <code>chartAspectRatio</code>'s
0096: * value defines the ratio of the height to the width of the chart. Optional
0097: */
0098: public static final String CHART_ASPECT_RATIO = "chartAspectRatio";
0099:
0100: /**
0101: * Parameter name for chart's title. <code>chartTitle</code> is optional.
0102: */
0103: public static final String CHART_TITLE = "chartTitle";
0104:
0105: /**
0106: * Parameter name for X axis title. <code>xAxisTitle</code> is optional.
0107: */
0108: public static final String X_AXIS_TITLE = "xAxisTitle";
0109:
0110: /**
0111: * Parameter name for Y axis title. <code>yAxisTitle</code> is optional.
0112: */
0113: public static final String Y_AXIS_TITLE = "yAxisTitle";
0114:
0115: /**
0116: * Parameter name for showing legend. <code>showLegend</code> is optional.
0117: */
0118: public static final String SHOW_LEGEND = "showLegend";
0119:
0120: /**
0121: * Parameter name for chart's width. <code>normalChartWidth</code> is optional.
0122: */
0123: public static final String NORMAL_CHART_WIDTH = "normalChartWidth";
0124:
0125: /**
0126: * Parameter name for chart's height. <code>normalChartHeight</code> is optional.
0127: */
0128: public static final String NORMAL_CHART_HEIGHT = "normalChartHeight";
0129:
0130: /**
0131: * Parameter name for chart's width. <code>maximizedChartWidth</code> is optional.
0132: */
0133: public static final String MAXIMIZED_CHART_WIDTH = "maximizedChartWidth";
0134:
0135: /**
0136: * Parameter name for chart's height. <code>maximizedChartHeight</code> is optional.
0137: */
0138: public static final String MAXIMIZED_CHART_HEIGHT = "maximizedChartHeight";
0139:
0140: /**
0141: * Parameter name for pie chart's shape. <code>pieChartShape</code> is optional
0142: * and specific to the <code>pie</code> or <code>pie3D</code> chart types.
0143: */
0144: public static final String PIE_CHART_SHAPE = "pieChartShape";
0145:
0146: /**
0147: * Parameter name for pie chart's label type. <code>pieLabelType</code> is
0148: * optional and specific to the <code>pie</code> or <code>pie3D</code> chart types.
0149: */
0150: public static final String PIE_LABEL_TYPE = "pieLabelType";
0151:
0152: /**
0153: * Parameter name for pie3D's depth factor. <code>pieDepthFactor</code> is
0154: * optional and specific to <code>pie3D</code> chart type only.
0155: */
0156: public static final String PIE_DEPTH_FACTOR = "pieDepthFactor";
0157:
0158: /**
0159: * Parameter name for pie's gap. <code>pieGap</code> is optional and
0160: * specific to <code>pie</code> and <code>pie3d</code> chart types.
0161: */
0162: public static final String PIE_GAP = "pieGap";
0163:
0164: //public static final String CHARTS = "charts";
0165:
0166: /**
0167: * Parameter name for font type. <code>fontType</code> is optional and
0168: * if specified will take affect of chart's title,
0169: * x and y axis title, and legend's label.
0170: */
0171: public static final String FONT_TYPE = "fontType";
0172:
0173: /**
0174: * Parameter name for font size. <code>fontSize</code> is optional and
0175: * if specified will take affect of chart's title,
0176: * x and y axis title, and legend's label.
0177: */
0178: public static final String FONT_SIZE = "fontSize";
0179:
0180: /**
0181: * Parameter name for chart's colors. The value of this parameter name
0182: * can be the static color constant defined in class java.awt.Color or
0183: * hexadecimal number, prefixed by <code>#</code>. Each color name or
0184: * hex number is separated by a comma (",").
0185: */
0186: public static final String CHART_COLORS = "chartColors";
0187:
0188: /**
0189: * Parameter name for chart's background color. The value of this parameter name
0190: * can be the static color constant defined in class java.awt.Color or
0191: * hexadecimal number, prefixed by <code>#</code>.
0192: */
0193: public static final String CHART_BG_COLOR = "chartBgColor";
0194:
0195: /**
0196: * Parameter name for showing chart's border. The value of <code>showBorder</code>
0197: * is either <code>true</code> or <code>false</code>. The border's color can be set
0198: * using <code>borderColor</code> parameter.
0199: */
0200: public static final String SHOW_BORDER = "showBorder";
0201:
0202: /**
0203: * Parameter name for chart's border color. The value of this parameter name
0204: * can be the static color constant defined in class java.awt.Color or
0205: * hexadecimal number, prefixed by <code>#</code>. This parameter only works
0206: * if <code>showBorder</code>'s value is <code>true</code>.
0207: */
0208: public static final String BORDER_COLOR = "borderColor";
0209:
0210: /**
0211: * Parameter name for chart's background image URL. <code>bgImageURL</code>
0212: * is optional.
0213: */
0214: public static final String BG_IMAGE_URL = "bgImageURL";
0215:
0216: /**
0217: * Parameter name for chart's background image (relative) path.
0218: * <code>bgImagePath</code>'s value defines the relative (to the context)path of
0219: * the image file.
0220: */
0221: public static final String BG_IMAGE_PATH = "bgImagePath";
0222:
0223: /**
0224: * Parameter name for chart's background alpha.
0225: */
0226: public static final String BG_ALPHA = "bgAlpha";
0227:
0228: /**
0229: * Parameter name for chart's background image alpha.
0230: */
0231: public static final String BG_IMAGE_ALPHA = "bgImageAlpha";
0232:
0233: /**
0234: * Parameter name for the chart's foreground alpha.
0235: */
0236: public static final String FG_ALPHA = "fgAlpha";
0237:
0238: /**
0239: * Name for chart's image type. <code>imageType</code> is optional.
0240: */
0241: public static final String IMAGE_TYPE = "imageType";
0242:
0243: /**
0244: * <code>circular</code> is one of the possible values for
0245: * <code>pieChartShape</code>.
0246: */
0247: public static final String CIRCULAR_SHAPE = "circular";
0248:
0249: /**
0250: * <code>oval</code> is one of the possible value for <code>pieChartShape</code>.
0251: */
0252: public static final String OVAL_SHAPE = "oval";
0253:
0254: /**
0255: * One of the supported value for <code>imageType</code> parameter.
0256: * <code>image/PNG</code> is the default image type.
0257: */
0258: public static final String PNG_IMAGE_TYPE = "image/PNG";
0259:
0260: /**
0261: * One of the supported value for <code>imageType</code> parameter.
0262: * <code>image/JPG</code> is for JPG type of chart image.
0263: */
0264: public static final String JPG_IMAGE_TYPE = "image/JPG";
0265:
0266: /**
0267: * <code>percent</code> is one of possible values for <code>pieLabelType</code>.
0268: */
0269: public static final String PERCENT_LABEL_TYPE = "percent";
0270:
0271: /**
0272: * <code>name</code> is one of possible values for <code>pieLabelType</code>.
0273: */
0274: public static final String NAME_LABEL_TYPE = "name";
0275:
0276: /**
0277: * <code>value</code> is one of possible values for <code>pieLabelType</code>.
0278: */
0279: public static final String VALUE_LABEL_TYPE = "value";
0280:
0281: /**
0282: * <code>name-value</code> is one of possible values for <code>pieLabelType</code>.
0283: */
0284: public static final String NAME_VALUE_LABEL_TYPE = "name-value";
0285:
0286: /**
0287: * <code>name-percent</code> is one of possible values for <code>pieLabelType</code>.
0288: */
0289: public static final String NAME_PERCENT_LABEL_TYPE = "name-percent";
0290:
0291: /**
0292: * <code>value-percent</code> is one of possible values for <code>pieLabelType</code>.
0293: */
0294: public static final String VALUE_PERCENT_LABEL_TYPE = "value-percent";
0295:
0296: /**
0297: * <code>none</code> is one of <code>pieLabelType</code>'s value.
0298: */
0299: public static final String NO_LABEL_TYPE = "none";
0300:
0301: public static final int DEFAULT_MAXIMIZED_WINDOW_WIDTH = 700;
0302: public static final int DEFAULT_MAXIMIZED_WINDOW_HEIGHT = 700;
0303: public static final int DEFAULT_NORMAL_WINDOW_WIDTH = 200;
0304: public static final int DEFAULT_NORMAL_WINDOW_HEIGHT = 200;
0305:
0306: private String cpWidthAttribute = "com.nabhinc.portal.portlet_width";
0307: private int cpID = getUniqueID();
0308: private boolean cpShowLegend = true;
0309: private Image cpBackgroundImage = null;
0310: private float cpBackgroundImageAlpha = 0;
0311: private float cpBackgroundAlpha = 0;
0312: private float cpForegroundAlpha = 0;
0313: private int cpPieLabelType = PiePlot.PERCENT_LABELS;
0314:
0315: /**
0316: * Applies only to Pie 3D chart
0317: */
0318: private double cpPieDepthFactor = 0;
0319: private double cpPieGap = 0.3;
0320:
0321: /**
0322: * Pie chart's type. Default is "circular".
0323: */
0324: private String cpPieChartShape = CIRCULAR_SHAPE;
0325:
0326: /**
0327: * Cached chart creation error.
0328: */
0329: private String cpError = null;
0330:
0331: /**
0332: * Aspect ratio for the graph
0333: */
0334: private float cpAspectRatio = -1;
0335:
0336: /**
0337: * Data source class name.
0338: */
0339: private String cpDSClass = null;
0340:
0341: /**
0342: * Chart datasource. Supported datasource is <code>xml</code> and
0343: * <code>jdbc/<datasource-name></code>
0344: */
0345: private ChartDataSource cpDataSource = null;
0346:
0347: /**
0348: * Should there be a border around the chart
0349: */
0350: private boolean cpShowBorder = false;
0351:
0352: /**
0353: * Border color if specified explicitly
0354: */
0355: private Color cpBorderColor = null;
0356:
0357: /**
0358: * Background color if specified explicitly
0359: */
0360: private Color cpBackgroundColor = null;
0361:
0362: /**
0363: * Chart colors
0364: */
0365: private Color[] cpChartColors = null;
0366:
0367: /**
0368: * Chart type selected
0369: */
0370: private int cpChartType = ChartTypeConstant.LINE;//CHART_TYPE_LINE;
0371:
0372: /**
0373: * Font for axis title and legend item.
0374: * Default is SansSerif with font size 11 pt.
0375: */
0376: private Font cpContentFont = new Font("SansSerif", Font.PLAIN, 11);
0377:
0378: /**
0379: * IMG tag returned when the content is first requested.
0380: */
0381: private String cpImageURL = null;
0382:
0383: /**
0384: * IMG tag returned when the content is first requested.
0385: */
0386: private String cpImagePath = null;
0387:
0388: /**
0389: * Chart's image type. Default is PNG.
0390: */
0391: private String cpImageType = "image/png";
0392:
0393: /**
0394: * Chart title.
0395: */
0396: private String cpTitle = null;
0397:
0398: /**
0399: * Chart width in normal window state
0400: */
0401: private int cpNormalWidth = -1;
0402:
0403: /**
0404: * Chart height in normal window state
0405: */
0406: private int cpNormalHeight = -1;
0407:
0408: /**
0409: * Chart width in maximized window state
0410: */
0411: private int cpMaximizedWidth = -1;
0412:
0413: /**
0414: * Chart height in maximized window state
0415: */
0416: private int cpMaximizedHeight = -1;
0417:
0418: /**
0419: * X axis labels
0420: */
0421: private String[] cpXLabels = null;
0422:
0423: /**
0424: * X axis title
0425: */
0426: private String cpXTitle = null;
0427:
0428: /**
0429: * Y axis labels
0430: */
0431: private String[] cpYLabels = null;
0432:
0433: /**
0434: * Y axis title
0435: */
0436: private String cpYTitle = null;
0437:
0438: //private String cpDataSetClassname = null;
0439:
0440: /**
0441: * Do nothing constructor.
0442: */
0443: public ChartPortlet() {
0444: }
0445:
0446: private static synchronized int getUniqueID() {
0447: return cpCounter++;
0448: }
0449:
0450: /**
0451: * Set chart properties common to all chart areas.
0452: */
0453:
0454: /**
0455: * Initializes the chart portlet. The following XML elements are expected:
0456: * <p>
0457: * <UL>
0458: * <LI>
0459: * URL of the RSS / RDF file
0460: * </LI>
0461: * <LI>
0462: * refresh (Optional) - Refresh period used to fetch newer version of the
0463: * RSS file specified in minutes. Defaults is 24 hours.
0464: * </LI>
0465: * <LI>
0466: * max-items (Optional) - Maximum number of headlines to display. Default
0467: * is 15.
0468: * </LI>
0469: * </UL>
0470: */
0471: public void init(PortletConfig config) throws PortletException {
0472: super .init(config);
0473:
0474: cpDSClass = config.getInitParameter(DATA_SOURCE_CLASS);
0475: if (cpDSClass == null) {
0476: throw new UnavailableException(
0477: "Failed to find required chart class configuration element: "
0478: + DATA_SOURCE_CLASS);
0479: }
0480:
0481: try {
0482: cpDataSource = (ChartDataSource) Class.forName(cpDSClass)
0483: .newInstance();
0484: cpDataSource.init(config);
0485: } catch (PortletException pe) {
0486: throw pe;
0487: } catch (Exception ex) {
0488: throw new PortletException(
0489: "Failed to initialize chart data source.", ex);
0490: }
0491:
0492: retrieveInitParameters(config);
0493:
0494: }
0495:
0496: public void doView(RenderRequest request, RenderResponse response)
0497: throws PortletException, IOException {
0498:
0499: int width = DEFAULT_NORMAL_WINDOW_WIDTH;
0500: int height = DEFAULT_NORMAL_WINDOW_HEIGHT;
0501:
0502: if (request.getWindowState().equals(WindowState.MAXIMIZED)) {
0503: width = DEFAULT_MAXIMIZED_WINDOW_WIDTH;
0504: height = DEFAULT_MAXIMIZED_WINDOW_HEIGHT;
0505: if (cpMaximizedHeight > 0 && cpMaximizedWidth > 0) {
0506: width = cpMaximizedWidth;
0507: height = cpMaximizedHeight;
0508: } else {
0509: if (cpAspectRatio > 0) {
0510: // Check if we can get portlet width via request attribute
0511: String pWidth = (String) request
0512: .getAttribute(cpWidthAttribute);
0513: if (pWidth != null) {
0514: try {
0515: width = Integer.parseInt(pWidth);
0516: } catch (Exception ex) {
0517: // Ignore since the width may be specified as a percent
0518: }
0519: }
0520: height = (int) (cpAspectRatio * width);
0521: }
0522: }
0523: } else {
0524: if (cpNormalHeight > 0 && cpNormalWidth > 0) {
0525: width = cpNormalWidth;
0526: height = cpNormalHeight;
0527: } else {
0528: if (cpAspectRatio > 0) {
0529: // Check if we can get portlet width via request attribute
0530: String pWidth = (String) request
0531: .getAttribute(cpWidthAttribute);
0532: if (pWidth != null) {
0533: try {
0534: width = Integer.parseInt(pWidth);
0535: } catch (Exception ex) {
0536: // Ignore since the width may be specified as a percent
0537: }
0538: }
0539: height = (int) (cpAspectRatio * width);
0540: }
0541: }
0542:
0543: }
0544:
0545: String wState = request.getWindowState().toString();
0546: String id = "chart_" + wState + cpID;
0547:
0548: // Refresh chart data
0549: cpDataSource.retrieveChartData();
0550: request.getPortletSession().setAttribute(id,
0551: generateChart(request, width, height),
0552: PortletSession.APPLICATION_SCOPE);
0553: /*
0554: response.getWriter().write(
0555: "<IMG align=\"center\" src=\""+ contextPath + "/charts?chartid=" + id + "\"/>");
0556: */
0557: request.setAttribute("chartID", id);
0558: super .doView(request, response);
0559: }
0560:
0561: private Object[] generateChart(RenderRequest req, int width,
0562: int height) throws UnavailableException, IOException,
0563: PortletException {
0564: // create the chart...
0565:
0566: JFreeChart chart = null;
0567: Plot plot = null;
0568:
0569: switch (cpChartType) {
0570: case ChartTypeConstant.PIE_3D:
0571: chart = ChartFactory.createPie3DChart(cpTitle, this
0572: .getPieDataset(), cpShowLegend, false, false);
0573: Pie3DPlot pie3DPlot = (Pie3DPlot) chart.getPlot();
0574: if (cpPieDepthFactor != 0)
0575: pie3DPlot.setDepthFactor(cpPieDepthFactor);
0576: pie3DPlot.setStartAngle(270);
0577: pie3DPlot.setDirection(PiePlot.CLOCKWISE);
0578: pie3DPlot.setSeriesLabelFont(cpContentFont);
0579: pie3DPlot.setSectionLabelFont(cpContentFont);
0580: pie3DPlot.setInteriorGap(cpPieGap);
0581: pie3DPlot.setSectionLabelType(cpPieLabelType);
0582:
0583: if (CIRCULAR_SHAPE.equals(cpPieChartShape)) {
0584: pie3DPlot.setCircular(true);
0585: } else {
0586: pie3DPlot.setCircular(false);
0587: }
0588:
0589: plot = pie3DPlot;
0590: break;
0591: case ChartTypeConstant.PIE:
0592: chart = ChartFactory.createPieChart(cpTitle, this
0593: .getPieDataset(), cpShowLegend, false, false);
0594: PiePlot piePlot = (PiePlot) chart.getPlot();
0595: piePlot.setStartAngle(270);
0596: piePlot.setDirection(PiePlot.CLOCKWISE);
0597: piePlot.setSeriesLabelFont(cpContentFont);
0598: piePlot.setSectionLabelFont(cpContentFont);
0599: piePlot.setInteriorGap(cpPieGap /*5.0*/);
0600: piePlot.setSectionLabelType(cpPieLabelType);
0601:
0602: if (CIRCULAR_SHAPE.equals(cpPieChartShape)) {
0603: piePlot.setCircular(true);
0604: } else {
0605: piePlot.setCircular(false);
0606: }
0607:
0608: plot = piePlot;
0609: break;
0610:
0611: case ChartTypeConstant.LINE:
0612: chart = ChartFactory.createLineChart(cpTitle, cpXTitle,
0613: cpYTitle, this .getCategoryDataset(), cpShowLegend,
0614: false, false);
0615:
0616: VerticalCategoryPlot vertPlot = (VerticalCategoryPlot) chart
0617: .getPlot();
0618:
0619: if (cpChartColors != null) {
0620: for (int i = 0; i < getCategoryDataset().getRowCount(); i++) {
0621: chart.getCategoryPlot().getRenderer()
0622: .setSeriesPaint(
0623: i,
0624: cpChartColors[i
0625: % cpChartColors.length]);
0626: }
0627: }
0628:
0629: /*
0630: if (cpChartColors != null) {
0631: for (int i = 0; i < getCategoryDataset().getColumnKeys().size(); i++) {
0632: vertPlot.getRenderer().setSeriesPaint(
0633: i, cpChartColors[i % cpChartColors.length]);
0634: }
0635: }
0636: */
0637: break;
0638:
0639: case ChartTypeConstant.HORIZONTAL_BAR:
0640: chart = ChartFactory.createHorizontalBarChart(cpTitle,
0641: cpXTitle, cpYTitle, this .getCategoryDataset(),
0642: cpShowLegend, false, false);
0643:
0644: if (cpChartColors != null) {
0645: for (int i = 0; i < getCategoryDataset().getRowCount(); i++) {
0646: chart.getCategoryPlot().getRenderer()
0647: .setSeriesPaint(
0648: i,
0649: cpChartColors[i
0650: % cpChartColors.length]);
0651: }
0652: }
0653:
0654: break;
0655:
0656: case ChartTypeConstant.HORIZONTAL_BAR_3D:
0657: chart = ChartFactory.createHorizontalBarChart3D(cpTitle,
0658: cpXTitle, cpYTitle, this .getCategoryDataset(),
0659: cpShowLegend, false, false);
0660:
0661: if (cpChartColors != null) {
0662: for (int i = 0; i < getCategoryDataset().getRowCount(); i++) {
0663: chart.getCategoryPlot().getRenderer()
0664: .setSeriesPaint(
0665: i,
0666: cpChartColors[i
0667: % cpChartColors.length]);
0668: }
0669: }
0670:
0671: break;
0672:
0673: case ChartTypeConstant.VERTICAL_BAR:
0674: chart = ChartFactory.createVerticalBarChart(cpTitle,
0675: cpXTitle, cpYTitle, this .getCategoryDataset(),
0676: cpShowLegend, false, false);
0677:
0678: if (cpChartColors != null) {
0679: for (int i = 0; i < getCategoryDataset().getRowCount(); i++) {
0680: chart.getCategoryPlot().getRenderer()
0681: .setSeriesPaint(
0682: i,
0683: cpChartColors[i
0684: % cpChartColors.length]);
0685: }
0686: }
0687:
0688: break;
0689:
0690: case ChartTypeConstant.VERTICAL_BAR_3D:
0691: chart = ChartFactory.createVerticalBarChart3D(cpTitle,
0692: cpXTitle, cpYTitle, this .getCategoryDataset(),
0693: cpShowLegend, false, false);
0694:
0695: if (cpChartColors != null) {
0696: for (int i = 0; i < getCategoryDataset().getRowCount(); i++) {
0697: chart.getCategoryPlot().getRenderer()
0698: .setSeriesPaint(
0699: i,
0700: cpChartColors[i
0701: % cpChartColors.length]);
0702: }
0703: }
0704: break;
0705:
0706: case ChartTypeConstant.STACKED_HORIZONTAL_BAR:
0707: chart = ChartFactory.createStackedHorizontalBarChart(
0708: cpTitle, cpXTitle, cpYTitle, this
0709: .getCategoryDataset(), cpShowLegend, false,
0710: false);
0711:
0712: if (cpChartColors != null) {
0713: for (int i = 0; i < getCategoryDataset().getRowCount(); i++) {
0714: chart.getCategoryPlot().getRenderer()
0715: .setSeriesPaint(
0716: i,
0717: cpChartColors[i
0718: % cpChartColors.length]);
0719: }
0720: }
0721:
0722: break;
0723:
0724: case ChartTypeConstant.STACKED_VERTICAL_BAR:
0725: chart = ChartFactory.createStackedVerticalBarChart(cpTitle,
0726: cpXTitle, cpYTitle, this .getCategoryDataset(),
0727: cpShowLegend, false, false);
0728:
0729: break;
0730:
0731: case ChartTypeConstant.LINE_XY:
0732: chart = ChartFactory.createLineXYChart(cpTitle, cpXTitle,
0733: cpYTitle, this .getXYDataset(), cpShowLegend, false,
0734: false);
0735: break;
0736:
0737: case ChartTypeConstant.SCATTER:
0738:
0739: chart = ChartFactory.createScatterPlot(cpTitle, cpXTitle,
0740: cpYTitle, this .getXYDataset(), cpShowLegend, false,
0741: false);
0742: break;
0743:
0744: case ChartTypeConstant.CANDLESTICK:
0745: chart = ChartFactory.createCandlestickChart(cpTitle,
0746: cpXTitle, cpYTitle, this .getHighLowDataset(),
0747: cpShowLegend);
0748:
0749: break;
0750:
0751: }
0752:
0753: // Set properties common to all charts if specified
0754: plot = chart.getPlot();
0755:
0756: if (cpBackgroundImage != null) {
0757: //plot.setBackgroundImage(cpBackgroundImage);
0758: chart.setBackgroundImage(cpBackgroundImage);
0759: if (cpBackgroundImageAlpha != 0) {
0760: chart.setBackgroundImageAlpha(cpBackgroundImageAlpha);
0761:
0762: }
0763: }
0764:
0765: if (cpBackgroundColor != null) {
0766: plot.setBackgroundPaint(cpBackgroundColor);
0767: }
0768:
0769: if (cpBackgroundAlpha != 0)
0770: plot.setBackgroundAlpha(cpBackgroundAlpha);
0771:
0772: if (cpForegroundAlpha != 0)
0773: plot.setForegroundAlpha(cpForegroundAlpha);
0774:
0775: // plot.setNoDataMessageFont(contentFont);
0776:
0777: if (cpShowBorder) {
0778: plot.setOutlinePaint(this .cpBackgroundColor);
0779:
0780: } else {
0781: plot.setOutlinePaint(null);
0782:
0783: }
0784:
0785: ByteArrayOutputStream out = new ByteArrayOutputStream();
0786:
0787: if (cpImageType.endsWith("JPG")) {
0788: ChartUtilities.writeChartAsJPEG(out, chart, width, height);
0789:
0790: } else {
0791: ChartUtilities.writeChartAsPNG(out, chart, width, height);
0792: }
0793:
0794: out.flush();
0795: Object[] cachedValue = new Object[2];
0796: cachedValue[0] = cpImageType;
0797: cachedValue[1] = out.toByteArray();
0798: //System.out.println("Chart image size = " + ((byte[]) cachedValue[1]).length);
0799: out.close();
0800: return cachedValue;
0801:
0802: }
0803:
0804: public static final int getChartTypeConstant(String type)
0805: throws PortletException {
0806: int index = CHART_TYPE_LIST.indexOf(type.toLowerCase());
0807: if (index < 0)
0808: throw new PortletException("Invalid chart type: " + type
0809: + ".");
0810: else
0811: return index;
0812:
0813: }
0814:
0815: private void retrieveInitParameters(PortletConfig config)
0816: throws PortletException {
0817: String temp = null;
0818:
0819: // Set name of the attribute that provides preferred chart
0820: // width
0821: temp = config.getInitParameter(PORTLET_WIDTH_ATTRIB);
0822: if (temp != null) {
0823: cpWidthAttribute = temp;
0824: }
0825:
0826: // Check and set the chart type if specified
0827: temp = config.getInitParameter(CHART_TYPE);
0828: if (temp != null) {
0829: cpChartType = getChartTypeConstant(temp);
0830: }
0831:
0832: temp = config.getInitParameter(CHART_ASPECT_RATIO);
0833: if (temp != null) {
0834: cpAspectRatio = Float.parseFloat(temp);
0835: }
0836:
0837: // Set chart title if specified
0838: cpTitle = config.getInitParameter(CHART_TITLE);
0839:
0840: // Set x axis label
0841: cpXTitle = config.getInitParameter(X_AXIS_TITLE);
0842:
0843: // Set Y axis label
0844: cpYTitle = config.getInitParameter(Y_AXIS_TITLE);
0845:
0846: temp = config.getInitParameter(SHOW_LEGEND);
0847: if (temp != null) {
0848: if ("false".equals(temp)) {
0849: cpShowLegend = false;
0850: } else {//default is true
0851: cpShowLegend = true;
0852: }
0853: }
0854:
0855: // Set normal width
0856: temp = config.getInitParameter(NORMAL_CHART_WIDTH);
0857: if (temp != null) {
0858: try {
0859: cpNormalWidth = Integer.parseInt(temp);
0860: } catch (Exception ex) {
0861: throw new PortletException(
0862: "Invalid normal chart width: " + temp + ".", ex);
0863: }
0864: }
0865:
0866: // Set normal height
0867: temp = config.getInitParameter(NORMAL_CHART_HEIGHT);
0868: if (temp != null) {
0869: try {
0870: cpNormalHeight = Integer.parseInt(temp);
0871: } catch (Exception ex) {
0872: throw new PortletException(
0873: "Invalid normal chart height: " + temp + ".",
0874: ex);
0875: }
0876: }
0877:
0878: // Set maximized width
0879: temp = config.getInitParameter(MAXIMIZED_CHART_WIDTH);
0880: if (temp != null) {
0881: try {
0882: cpMaximizedWidth = Integer.parseInt(temp);
0883: } catch (Exception ex) {
0884: throw new PortletException(
0885: "Invalid maximized chart width: " + temp + ".",
0886: ex);
0887: }
0888: }
0889:
0890: // Set normal height
0891: temp = config.getInitParameter(MAXIMIZED_CHART_HEIGHT);
0892: if (temp != null) {
0893: try {
0894: cpMaximizedHeight = Integer.parseInt(temp);
0895: } catch (Exception ex) {
0896: throw new PortletException(
0897: "Invalid maximized chart height: " + temp + ".",
0898: ex);
0899: }
0900: }
0901:
0902: // Configuration parameters applicable to pie charts
0903: temp = config.getInitParameter(PIE_CHART_SHAPE);
0904: if (temp != null) {
0905: if (CIRCULAR_SHAPE.equals(temp.trim())
0906: || OVAL_SHAPE.equals(temp.trim())) {
0907: cpPieChartShape = temp;
0908: } else {
0909: throw new PortletException("Invalid pie chart shape: "
0910: + temp + ".");
0911: }
0912: }
0913:
0914: temp = config.getInitParameter(PIE_DEPTH_FACTOR);
0915: if (temp != null) {
0916: try {
0917: cpPieDepthFactor = Double.parseDouble(temp);
0918: } catch (Exception ex) {
0919: throw new PortletException("Invalid pie chart depth: "
0920: + temp + ".");
0921: }
0922: }
0923:
0924: temp = config.getInitParameter(PIE_GAP);
0925: if (temp != null) {
0926: try {
0927: cpPieGap = Double.parseDouble(temp);
0928: } catch (Exception ex) {
0929: throw new PortletException("Invalid pie chart gap: "
0930: + temp + ".");
0931: }
0932: }
0933:
0934: temp = config.getInitParameter(PIE_LABEL_TYPE);
0935: if (temp != null) {
0936: temp = temp.trim();
0937: if (temp.equals(PERCENT_LABEL_TYPE)) {
0938: cpPieLabelType = PiePlot.PERCENT_LABELS;
0939: } else if (temp.equals(NO_LABEL_TYPE)) {
0940: cpPieLabelType = PiePlot.NO_LABELS;
0941: } else if (temp.equals(NAME_LABEL_TYPE)) {
0942: cpPieLabelType = PiePlot.NAME_LABELS;
0943: } else if (temp.equals(VALUE_LABEL_TYPE)) {
0944: cpPieLabelType = PiePlot.VALUE_LABELS;
0945: } else if (temp.equals(NAME_VALUE_LABEL_TYPE)) {
0946: cpPieLabelType = PiePlot.NAME_AND_VALUE_LABELS;
0947: } else if (temp.equals(NAME_PERCENT_LABEL_TYPE)) {
0948: cpPieLabelType = PiePlot.NAME_AND_PERCENT_LABELS;
0949: } else if (temp.equals(VALUE_PERCENT_LABEL_TYPE)) {
0950: cpPieLabelType = PiePlot.VALUE_AND_PERCENT_LABELS;
0951: } else {
0952: throw new PortletException("Invalid pie label type: "
0953: + temp + ".");
0954: }
0955:
0956: }
0957:
0958: String fontType = config.getInitParameter(FONT_TYPE);
0959:
0960: String fontSize = config.getInitParameter(FONT_SIZE);
0961:
0962: if (fontType != null) {
0963: int size = 0;
0964: if (fontSize != null) {
0965: try {
0966: size = Integer.parseInt(fontSize);
0967: } catch (Exception ex) {
0968: throw new PortletException("Invalid font size: "
0969: + fontSize + ".", ex);
0970: }
0971:
0972: }
0973: cpContentFont = new Font(fontType, Font.PLAIN, size);
0974:
0975: } else if (fontSize != null) {
0976: int size = 0;
0977: try {
0978: size = Integer.parseInt(fontSize);
0979: } catch (Exception ex) {
0980: throw new PortletException("Invalid font size: "
0981: + fontSize + ".", ex);
0982: }
0983: cpContentFont = new Font(cpContentFont.getFontName(),
0984: Font.PLAIN, size);
0985: }
0986:
0987: // Set chart colors
0988: temp = config.getInitParameter(CHART_COLORS);
0989: if (temp != null) {
0990: setChartColors(temp);
0991: }
0992:
0993: // Set chart background color
0994: temp = config.getInitParameter(CHART_BG_COLOR);
0995: if (temp != null) {
0996: setBackgroundColor(temp);
0997: }
0998:
0999: temp = config.getInitParameter(SHOW_BORDER);
1000: if (temp != null) {
1001: if ("true".equals(temp.trim().toLowerCase())) {
1002: cpShowBorder = true;
1003: } else {
1004: cpShowBorder = false;
1005: }
1006: }
1007:
1008: // Border color
1009: temp = config.getInitParameter(BORDER_COLOR);
1010: if (temp != null) {
1011: cpBorderColor = Color.decode(temp);
1012: }
1013:
1014: temp = config.getInitParameter(BG_IMAGE_URL);
1015: if (temp != null) {
1016:
1017: try {
1018: cpImageURL = temp;
1019: cpBackgroundImage = Toolkit.getDefaultToolkit()
1020: .createImage(new URL(temp));
1021: } catch (MalformedURLException ex) {
1022: throw new PortletException(
1023: "Invalid chart background image URL: " + temp
1024: + ".");
1025: }
1026: } else {
1027: // Check if an image file has been specified
1028: temp = config.getInitParameter(BG_IMAGE_PATH);
1029: if (temp != null) {
1030: cpImagePath = temp;
1031: String imagePath = getRealPath(
1032: this .getPortletContext(), temp);
1033: cpBackgroundImage = Toolkit.getDefaultToolkit()
1034: .createImage(imagePath);
1035: }
1036: }
1037:
1038: temp = config.getInitParameter(BG_IMAGE_ALPHA);
1039: if (temp != null) {
1040: try {
1041: cpBackgroundImageAlpha = Float.parseFloat(temp);
1042: } catch (Exception ex) {
1043: throw new PortletException(
1044: "Invalid background image alpha: " + temp + ".");
1045: }
1046: }
1047:
1048: temp = config.getInitParameter(BG_ALPHA);
1049: if (temp != null) {
1050: try {
1051: cpBackgroundAlpha = Float.parseFloat(temp);
1052: } catch (Exception ex) {
1053: throw new PortletException(
1054: "Invalid chart image alpha: " + temp + ".");
1055: }
1056: }
1057:
1058: temp = config.getInitParameter(FG_ALPHA);
1059: if (temp != null) {
1060: try {
1061: cpForegroundAlpha = Float.parseFloat(temp);
1062: } catch (Exception ex) {
1063: throw new PortletException("Invalid foreground alpha: "
1064: + temp + ".");
1065: }
1066: }
1067:
1068: temp = config.getInitParameter(IMAGE_TYPE);
1069:
1070: if (temp != null) {
1071: temp = temp.toUpperCase();
1072: if ((temp.equals("JPEG")) || (temp.equals("JPG"))) {
1073: cpImageType = JPG_IMAGE_TYPE;
1074: } else if (temp.equals("PNG")) {
1075: cpImageType = PNG_IMAGE_TYPE;
1076: } else {
1077: throw new PortletException("Invalid chart image type: "
1078: + temp + ".");
1079: }
1080: }
1081:
1082: }
1083:
1084: private PieDataset getPieDataset() throws UnavailableException {
1085: try {
1086: return (PieDataset) cpDataSource;
1087:
1088: } catch (Exception ex) {
1089: error("doView", "Unable to find class: " + cpDSClass + ".");
1090: throw new UnavailableException("Unable to find class: "
1091: + cpDSClass);
1092:
1093: }
1094: }
1095:
1096: private CategoryDataset getCategoryDataset()
1097: throws UnavailableException {
1098: try {
1099: return (CategoryDataset) cpDataSource;
1100:
1101: } catch (Exception ex) {
1102: error("doView", "Unable to find class: " + cpDSClass + ".");
1103: throw new UnavailableException("Unable to find class: "
1104: + cpDSClass);
1105:
1106: }
1107: }
1108:
1109: private XYDataset getXYDataset() throws UnavailableException {
1110: try {
1111: return (XYDataset) cpDataSource;
1112:
1113: } catch (Exception ex) {
1114: error("doView", "Unable to find class: " + cpDSClass + ".");
1115: throw new UnavailableException("Unable to find class: "
1116: + cpDSClass);
1117:
1118: }
1119: }
1120:
1121: private HighLowDataset getHighLowDataset()
1122: throws UnavailableException, PortletException {
1123: try {
1124: return (HighLowDataset) cpDataSource;
1125:
1126: } catch (Exception ex) {
1127: error("doView", "Unable to find class: " + cpDSClass + ".");
1128: throw new UnavailableException("Unable to find class: "
1129: + cpDSClass);
1130:
1131: }
1132:
1133: }
1134:
1135: public void setChartColors(String chartColor) {
1136: String[] temp2 = StringUtil.split(chartColor, ",");
1137: cpChartColors = new Color[temp2.length];
1138:
1139: for (int i = 0; i < temp2.length; i++) {
1140: try {
1141: if (temp2[i].startsWith("#")) {
1142: cpChartColors[i] = Color.decode("0x"
1143: + temp2[i].substring(1));
1144: } else {
1145: cpChartColors[i] = (Color) Color.class.getField(
1146: temp2[i]).get(null);
1147: }
1148: } catch (Exception ex) {
1149: //reset the chart colors. Use default colors.
1150: cpChartColors = null;
1151: error("doView", temp2[i]
1152: + " is an invalid chart color.");
1153: break;
1154: }
1155: }
1156:
1157: }
1158:
1159: public void setBackgroundColor(String bgColor) {
1160: try {
1161: if (bgColor.startsWith("#")) {
1162: cpBackgroundColor = Color.decode("0x"
1163: + bgColor.substring(1));
1164: } else {
1165: cpBackgroundColor = (Color) Color.class.getField(
1166: bgColor).get(null);
1167: }
1168: } catch (Exception ex) {
1169: //reset the chart colors. Use default colors.
1170: cpBackgroundColor = null;
1171: error("doView", bgColor
1172: + " is an invalid background color.");
1173: }
1174:
1175: }
1176:
1177: }
|