1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 <param name="value">chart</param>
90 * public JFreeChart getChart() {
91 * return chart;
92 * }
93 * }
94 *
95 * <result name="success" type="chart">
96 * <param name="value">chart</param>
97 * <param name="type">png</param>
98 * <param name="width">640</param>
99 * <param name="height">480</param>
100 * </result>
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;
112 private boolean chartSet;
113 String height, width;
114 String type = DEFAULT_TYPE;
115 String value = DEFAULT_VALUE;
116
117
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
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
173
174
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)
187 chart = (JFreeChart) invocation.getStack().findValue(value, JFreeChart.class);
188 if (chart == null)
189 throw new NullPointerException("No JFreeChart object found on the stack with name " + value);
190
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
197 HttpServletResponse response = ServletActionContext.getResponse();
198 OutputStream os = response.getOutputStream();
199 try {
200
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 }