View Javadoc

1   /*
2    * $Id: ChartResult.java 817318 2009-09-21 16:55:09Z musachy $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  package org.apache.struts2.dispatcher;
23  
24  import org.apache.struts2.ServletActionContext;
25  import com.opensymphony.xwork2.ActionInvocation;
26  import com.opensymphony.xwork2.util.logging.Logger;
27  import com.opensymphony.xwork2.util.logging.LoggerFactory;
28  import org.jfree.chart.ChartUtilities;
29  import org.jfree.chart.JFreeChart;
30  
31  import java.io.OutputStream;
32  
33  import javax.servlet.http.HttpServletResponse;
34  
35  /***
36   * <!-- START SNIPPET: description -->
37   * <p/>
38   * A custom Result type for chart data. Built on top of
39   * <a href="http://www.jfree.org/jfreechart/" target="_blank">JFreeChart</a>. When executed
40   * this Result will write the given chart as a PNG or JPG to the servlet output stream.
41   * <p/>
42   * <!-- END SNIPPET: description -->
43   * <p/>
44   * <b>This result type takes the following parameters:</b>
45   * <p/>
46   * <!-- START SNIPPET: params -->
47   * <p/>
48   * <ul>
49   * <p/>
50   * <li><b>value</b> - the name of the JFreeChart object on the ValueStack, defaults to 'chart'.</li>
51   * <p/>
52   * <li><b>type</b> - the render type for this chart. Can be jpg (or jpeg) or png. Defaults to png.</li>
53   * <p/>
54   * <li><b>width (required)</b> - the width (in pixels) of the rendered chart.</li>
55   * <p/>
56   * <li><b>height (required)</b> - the height (in pixels) of the rendered chart.</li>
57   * <p/>
58   * </ul>
59   * <!-- END SNIPPET: params -->
60   * <p/>
61   * <b>Example:</b>
62   * <p/>
63   * <pre><!-- START SNIPPET: example -->
64   * public class ExampleChartAction extends ActionSupport {
65   *
66   *	    private JFreeChart chart;
67   *
68   *	    public String execute() throws Exception {
69   *		    // chart creation logic...
70   *		    XYSeries dataSeries = new XYSeries(new Integer(1)); // pass a key for this serie
71   *		    for (int i = 0; i <= 100; i++) {
72   *			    dataSeries.add(i, RandomUtils.nextInt());
73   *		    }
74   *		    XYSeriesCollection xyDataset = new XYSeriesCollection(dataSeries);
75   *
76   *		    ValueAxis xAxis = new NumberAxis("Raw Marks");
77   *		    ValueAxis yAxis = new NumberAxis("Moderated Marks");
78   *
79   *		    // set my chart variable
80   *		    chart =
81   *			    new JFreeChart( "Moderation Function", JFreeChart.DEFAULT_TITLE_FONT,
82   *				    new XYPlot( xyDataset, xAxis, yAxis, new StandardXYItemRenderer(StandardXYItemRenderer.LINES)),
83   *				    false);
84   *		    chart.setBackgroundPaint(java.awt.Color.white);
85   *
86   *		    return SUCCESS;
87   *	    }
88   * 
89   *      // this method will get called if we specify &lt;param name="value"&gt;chart&lt;/param&gt;
90   *	    public JFreeChart getChart() {
91   *		    return chart;
92   *	    }
93   *  }
94   *
95   * &lt;result name="success" type="chart"&gt;
96   *   &lt;param name="value"&gt;chart&lt;/param&gt;
97   *   &lt;param name="type"&gt;png&lt;/param&gt;
98   *   &lt;param name="width"&gt;640&lt;/param&gt;
99   *   &lt;param name="height"&gt;480&lt;/param&gt;
100  * &lt;/result&gt;
101  * <!-- END SNIPPET: example --></pre>
102  */
103 public class ChartResult extends StrutsResultSupport {
104 
105     private final static Logger LOG = LoggerFactory.getLogger(ChartResult.class);
106 
107     private static final long serialVersionUID = -6484761870055986612L;
108     private static final String DEFAULT_TYPE = "png";
109     private static final String DEFAULT_VALUE = "chart";
110 
111     private JFreeChart chart; // the JFreeChart to render
112     private boolean chartSet;
113     String height, width;
114     String type = DEFAULT_TYPE; // supported are jpg, jpeg or png, defaults to png
115     String value = DEFAULT_VALUE; // defaults to 'chart'
116 
117     // CONSTRUCTORS ----------------------------
118 
119     public ChartResult() {
120         super();
121     }
122 
123     public ChartResult(JFreeChart chart, String height, String width) {
124         this.chart = chart;
125         this.height = height;
126         this.width = width;
127     }
128 
129     // ACCESSORS ----------------------------
130 
131     public String getHeight() {
132         return height;
133     }
134 
135     public void setHeight(String height) {
136         this.height = height;
137     }
138 
139     public String getWidth() {
140         return width;
141     }
142 
143     public void setWidth(String width) {
144         this.width = width;
145     }
146 
147     public String getType() {
148         return type;
149     }
150 
151     public void setType(String type) {
152         this.type = type;
153     }
154 
155     public String getValue() {
156         return value;
157     }
158 
159     public void setValue(String value) {
160         this.value = value;
161     }
162 
163     public JFreeChart getChart() {
164         return chart;
165     }
166 
167     public void setChart(JFreeChart chart) {
168         this.chartSet = true;
169         this.chart = chart;
170     }
171 
172     // OTHER METHODS -----------------------
173 
174     // Required by com.opensymphony.xwork2.Result
175 
176     /***
177      * Executes the result. Writes the given chart as a PNG or JPG to the servlet output stream.
178      *
179      * @param invocation an encapsulation of the action execution state.
180      * @throws Exception if an error occurs when creating or writing the chart to the servlet output stream.
181      */
182     public void doExecute(String finalLocation, ActionInvocation invocation) throws Exception {
183 
184         initializeProperties(invocation);
185         
186         if (!chartSet) // if our chart hasn't been set (by the testcase), we'll look it up in the value stack
187             chart = (JFreeChart) invocation.getStack().findValue(value, JFreeChart.class);
188         if (chart == null) // we need to have a chart object - if not, blow up
189             throw new NullPointerException("No JFreeChart object found on the stack with name " + value);
190         // make sure we have some value for the width and height
191         if (height == null)
192             throw new NullPointerException("No height parameter was given.");
193         if (width == null)
194             throw new NullPointerException("No width parameter was given.");
195 
196         // get a reference to the servlet output stream to write our chart image to
197         HttpServletResponse response = ServletActionContext.getResponse();
198         OutputStream os = response.getOutputStream();
199         try {
200             // check the type to see what kind of output we have to produce
201             if ("png".equalsIgnoreCase(type)) {
202                 response.setContentType("image/png");
203                 ChartUtilities.writeChartAsPNG(os, chart, getIntValueFromString(width), getIntValueFromString(height));
204             }
205             else if ("jpg".equalsIgnoreCase(type) || "jpeg".equalsIgnoreCase(type)) {
206                 response.setContentType("image/jpg");
207                 ChartUtilities.writeChartAsJPEG(os, chart, getIntValueFromString(width), getIntValueFromString(height));
208             }
209             else
210                 throw new IllegalArgumentException(type + " is not a supported render type (only JPG and PNG are).");
211         } finally {
212             if (os != null) os.flush();
213         }
214     }
215 
216     /***
217      * Sets up result properties, parsing etc.
218      *
219      * @param invocation Current invocation.
220      * @throws Exception on initialization error.
221      */
222     private void initializeProperties(ActionInvocation invocation) throws Exception {
223 
224         if (height != null) {
225             height = conditionalParse(height, invocation);
226         }
227 
228         if (width != null) {
229             width = conditionalParse(width, invocation);
230         }
231 
232         if (type != null) {
233             type = conditionalParse(type, invocation);
234         }
235         
236         if ( type == null) {
237             type = DEFAULT_TYPE;
238         }
239     }
240 
241     private Integer getIntValueFromString(String value) {
242         try {
243             return Integer.parseInt(value);
244         } catch (Exception e) {
245             LOG.error("Specified value for width or height is not of type Integer...", e);
246             return null;
247         }
248     }
249 
250 }