1133 |
18 Jun 09 |
martin |
1 |
/** |
1133 |
18 Jun 09 |
martin |
$Id$ |
1133 |
18 Jun 09 |
martin |
3 |
|
1133 |
18 Jun 09 |
martin |
Copyright (C) 2009 Martin Svensson |
1133 |
18 Jun 09 |
martin |
5 |
|
1133 |
18 Jun 09 |
martin |
This file is part of BASE - BioArray Software Environment. |
1133 |
18 Jun 09 |
martin |
Available at http://base.thep.lu.se/ |
1133 |
18 Jun 09 |
martin |
8 |
|
1133 |
18 Jun 09 |
martin |
BASE is free software; you can redistribute it and/or |
1133 |
18 Jun 09 |
martin |
modify it under the terms of the GNU General Public License |
1133 |
18 Jun 09 |
martin |
as published by the Free Software Foundation; either version 3 |
1133 |
18 Jun 09 |
martin |
of the License, or (at your option) any later version. |
1133 |
18 Jun 09 |
martin |
13 |
|
1133 |
18 Jun 09 |
martin |
BASE is distributed in the hope that it will be useful, |
1133 |
18 Jun 09 |
martin |
but WITHOUT ANY WARRANTY; without even the implied warranty of |
1133 |
18 Jun 09 |
martin |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1133 |
18 Jun 09 |
martin |
GNU General Public License for more details. |
1133 |
18 Jun 09 |
martin |
18 |
|
1133 |
18 Jun 09 |
martin |
You should have received a copy of the GNU General Public License |
1133 |
18 Jun 09 |
martin |
along with BASE. If not, see <http://www.gnu.org/licenses/>. |
1133 |
18 Jun 09 |
martin |
21 |
*/ |
1133 |
18 Jun 09 |
martin |
22 |
|
1133 |
18 Jun 09 |
martin |
23 |
package net.sf.basedb.illumina.servlet; |
1133 |
18 Jun 09 |
martin |
24 |
|
1133 |
18 Jun 09 |
martin |
25 |
import net.sf.basedb.core.Application; |
1133 |
18 Jun 09 |
martin |
26 |
import net.sf.basedb.core.BioAssay; |
1133 |
18 Jun 09 |
martin |
27 |
import net.sf.basedb.core.BioAssaySet; |
1133 |
18 Jun 09 |
martin |
28 |
import net.sf.basedb.core.DbControl; |
1133 |
18 Jun 09 |
martin |
29 |
import net.sf.basedb.core.DynamicResultIterator; |
1133 |
18 Jun 09 |
martin |
30 |
import net.sf.basedb.core.DynamicSpotQuery; |
1133 |
18 Jun 09 |
martin |
31 |
import net.sf.basedb.core.ItemQuery; |
1133 |
18 Jun 09 |
martin |
32 |
import net.sf.basedb.core.SessionControl; |
1135 |
23 Jun 09 |
martin |
33 |
import net.sf.basedb.core.query.Dynamic; |
1135 |
23 Jun 09 |
martin |
34 |
import net.sf.basedb.core.query.Expression; |
1135 |
23 Jun 09 |
martin |
35 |
import net.sf.basedb.core.query.Expressions; |
1135 |
23 Jun 09 |
martin |
36 |
import net.sf.basedb.core.query.JoinType; |
1133 |
18 Jun 09 |
martin |
37 |
import net.sf.basedb.core.query.Restriction; |
1133 |
18 Jun 09 |
martin |
38 |
import net.sf.basedb.core.query.Restrictions; |
1133 |
18 Jun 09 |
martin |
39 |
import net.sf.basedb.core.query.Selects; |
1133 |
18 Jun 09 |
martin |
40 |
import net.sf.basedb.core.query.SqlResult; |
1133 |
18 Jun 09 |
martin |
41 |
import net.sf.basedb.util.FileUtil; |
1133 |
18 Jun 09 |
martin |
42 |
import net.sf.basedb.util.StaticCache; |
1133 |
18 Jun 09 |
martin |
43 |
import net.sf.basedb.util.Values; |
1133 |
18 Jun 09 |
martin |
44 |
|
1133 |
18 Jun 09 |
martin |
45 |
import java.awt.Color; |
1133 |
18 Jun 09 |
martin |
46 |
import java.awt.Font; |
1133 |
18 Jun 09 |
martin |
47 |
import java.awt.Graphics2D; |
1133 |
18 Jun 09 |
martin |
48 |
import java.awt.font.FontRenderContext; |
1133 |
18 Jun 09 |
martin |
49 |
import java.awt.geom.Rectangle2D; |
1133 |
18 Jun 09 |
martin |
50 |
import java.awt.image.BufferedImage; |
1133 |
18 Jun 09 |
martin |
51 |
import java.awt.image.RenderedImage; |
1133 |
18 Jun 09 |
martin |
52 |
import java.io.IOException; |
1133 |
18 Jun 09 |
martin |
53 |
import java.io.InputStream; |
1133 |
18 Jun 09 |
martin |
54 |
import java.io.OutputStream; |
1133 |
18 Jun 09 |
martin |
55 |
import java.util.ArrayList; |
1133 |
18 Jun 09 |
martin |
56 |
import java.util.List; |
1133 |
18 Jun 09 |
martin |
57 |
|
1133 |
18 Jun 09 |
martin |
58 |
import javax.imageio.ImageIO; |
1133 |
18 Jun 09 |
martin |
59 |
import javax.servlet.ServletConfig; |
1133 |
18 Jun 09 |
martin |
60 |
import javax.servlet.ServletException; |
1133 |
18 Jun 09 |
martin |
61 |
import javax.servlet.http.HttpServlet; |
1133 |
18 Jun 09 |
martin |
62 |
import javax.servlet.http.HttpServletRequest; |
1133 |
18 Jun 09 |
martin |
63 |
import javax.servlet.http.HttpServletResponse; |
1133 |
18 Jun 09 |
martin |
64 |
|
1133 |
18 Jun 09 |
martin |
65 |
import org.apache.commons.io.output.TeeOutputStream; |
1133 |
18 Jun 09 |
martin |
66 |
import org.jfree.chart.JFreeChart; |
1135 |
23 Jun 09 |
martin |
67 |
import org.jfree.chart.axis.CategoryAxis; |
1135 |
23 Jun 09 |
martin |
68 |
import org.jfree.chart.axis.CategoryLabelPositions; |
1133 |
18 Jun 09 |
martin |
69 |
import org.jfree.chart.axis.NumberAxis; |
1133 |
18 Jun 09 |
martin |
70 |
import org.jfree.chart.labels.StandardCategoryToolTipGenerator; |
1133 |
18 Jun 09 |
martin |
71 |
import org.jfree.chart.plot.CategoryPlot; |
1133 |
18 Jun 09 |
martin |
72 |
import org.jfree.chart.renderer.category.CategoryItemRenderer; |
1133 |
18 Jun 09 |
martin |
73 |
import org.jfree.chart.renderer.category.LineAndShapeRenderer; |
1133 |
18 Jun 09 |
martin |
74 |
import org.jfree.chart.title.TextTitle; |
1133 |
18 Jun 09 |
martin |
75 |
import org.jfree.data.category.DefaultCategoryDataset; |
1133 |
18 Jun 09 |
martin |
76 |
import org.jfree.data.statistics.Statistics; |
1133 |
18 Jun 09 |
martin |
77 |
|
1133 |
18 Jun 09 |
martin |
78 |
/** |
1141 |
24 Jun 09 |
martin |
This servlet can plot the controls summary for a Illumina bioassay set. |
1141 |
24 Jun 09 |
martin |
The generated plot contains one dataset for perfectmatch report and |
1141 |
24 Jun 09 |
martin |
one dataset for housekeeping report. |
1141 |
24 Jun 09 |
martin |
It uses the JFreePlot package to generate the plots. |
1141 |
24 Jun 09 |
martin |
This servlet accepts the following parameters: |
1141 |
24 Jun 09 |
martin |
84 |
|
1141 |
24 Jun 09 |
martin |
<table border="1" cellspacing="0" cellpadding="2"> |
1141 |
24 Jun 09 |
martin |
<tr> |
1141 |
24 Jun 09 |
martin |
<th>Parameter</th> |
1141 |
24 Jun 09 |
martin |
<th>Required</th> |
1141 |
24 Jun 09 |
martin |
<th>Default value</th> |
1141 |
24 Jun 09 |
martin |
<th>Description</th> |
1141 |
24 Jun 09 |
martin |
</tr> |
1141 |
24 Jun 09 |
martin |
92 |
|
1141 |
24 Jun 09 |
martin |
<tr> |
1141 |
24 Jun 09 |
martin |
<td>ID</td> |
1141 |
24 Jun 09 |
martin |
<td>yes</td> |
1141 |
24 Jun 09 |
martin |
<td></td> |
1141 |
24 Jun 09 |
martin |
<td>The SessionControl ID. See {@link Application#getSessionControl(String, String)}.</td> |
1141 |
24 Jun 09 |
martin |
</tr> |
1141 |
24 Jun 09 |
martin |
99 |
|
1141 |
24 Jun 09 |
martin |
<tr> |
1141 |
24 Jun 09 |
martin |
<td>bioassayset_id</td> |
1141 |
24 Jun 09 |
martin |
<td>yes</td> |
1141 |
24 Jun 09 |
martin |
<td></td> |
1141 |
24 Jun 09 |
martin |
<td>The ID of the bioassay set to plot.</td> |
1141 |
24 Jun 09 |
martin |
</tr> |
1141 |
24 Jun 09 |
martin |
106 |
|
1141 |
24 Jun 09 |
martin |
<tr> |
1141 |
24 Jun 09 |
martin |
<td>format</td> |
1141 |
24 Jun 09 |
martin |
<td>no</td> |
1141 |
24 Jun 09 |
martin |
<td>png</td> |
1141 |
24 Jun 09 |
martin |
<td> |
1141 |
24 Jun 09 |
martin |
The format of the image, "png" and "jpg" are the only supported values. |
1141 |
24 Jun 09 |
martin |
</td> |
1141 |
24 Jun 09 |
martin |
</tr> |
1141 |
24 Jun 09 |
martin |
115 |
|
1141 |
24 Jun 09 |
martin |
<tr> |
1141 |
24 Jun 09 |
martin |
<td>cacheBase</td> |
1141 |
24 Jun 09 |
martin |
<td>no</td> |
1141 |
24 Jun 09 |
martin |
<td>plots/</td> |
1141 |
24 Jun 09 |
martin |
<td>The base-directory where cached images should be stored.</td |
1141 |
24 Jun 09 |
martin |
</tr> |
1133 |
18 Jun 09 |
martin |
122 |
|
1133 |
18 Jun 09 |
martin |
@author martin |
1133 |
18 Jun 09 |
martin |
@since 1.4 |
1133 |
18 Jun 09 |
martin |
125 |
*/ |
1133 |
18 Jun 09 |
martin |
126 |
|
1133 |
18 Jun 09 |
martin |
127 |
public final class IlluminaPlotServlet |
1133 |
18 Jun 09 |
martin |
128 |
extends HttpServlet |
1133 |
18 Jun 09 |
martin |
129 |
{ |
1141 |
24 Jun 09 |
martin |
130 |
private static final long serialVersionUID = -2969496770778710927L; |
1141 |
24 Jun 09 |
martin |
131 |
|
1141 |
24 Jun 09 |
martin |
132 |
private int width = 800; |
1141 |
24 Jun 09 |
martin |
133 |
private int height = 600; |
1133 |
18 Jun 09 |
martin |
134 |
private String defaultFormat = "png"; |
1133 |
18 Jun 09 |
martin |
135 |
private String cacheBase = "plots/"; |
1133 |
18 Jun 09 |
martin |
136 |
|
1133 |
18 Jun 09 |
martin |
137 |
@Override |
1133 |
18 Jun 09 |
martin |
138 |
public void init() |
1133 |
18 Jun 09 |
martin |
139 |
throws ServletException |
1133 |
18 Jun 09 |
martin |
140 |
{ |
1133 |
18 Jun 09 |
martin |
141 |
ServletConfig cfg = getServletConfig(); |
1133 |
18 Jun 09 |
martin |
142 |
defaultFormat = Values.getString(cfg.getInitParameter("defaultFormat"), defaultFormat); |
1133 |
18 Jun 09 |
martin |
143 |
cacheBase = Values.getString(cfg.getInitParameter("cacheBase"), cacheBase); |
1133 |
18 Jun 09 |
martin |
144 |
} |
1133 |
18 Jun 09 |
martin |
145 |
|
1133 |
18 Jun 09 |
martin |
146 |
@Override |
1133 |
18 Jun 09 |
martin |
147 |
public void doGet(HttpServletRequest request, HttpServletResponse response) |
1133 |
18 Jun 09 |
martin |
148 |
throws IOException, ServletException |
1133 |
18 Jun 09 |
martin |
149 |
{ |
1133 |
18 Jun 09 |
martin |
150 |
final String ID = request.getParameter("ID"); |
1133 |
18 Jun 09 |
martin |
151 |
|
1133 |
18 Jun 09 |
martin |
// Where to get the source data |
1141 |
24 Jun 09 |
martin |
153 |
final int bioAssaySetId = Values.getInt(request.getParameter("bioassayset_id")); |
1133 |
18 Jun 09 |
martin |
154 |
String cacheKey = Values.getStringOrNull(request.getParameter("cache")); |
1141 |
24 Jun 09 |
martin |
155 |
|
1141 |
24 Jun 09 |
martin |
// Image settings and format |
1133 |
18 Jun 09 |
martin |
157 |
String format = Values.getString(request.getParameter("format"), defaultFormat); |
1133 |
18 Jun 09 |
martin |
158 |
if (!format.equals("jpeg") && !format.equals("png")) |
1133 |
18 Jun 09 |
martin |
159 |
{ |
1133 |
18 Jun 09 |
martin |
160 |
format = defaultFormat; |
1133 |
18 Jun 09 |
martin |
161 |
} |
1133 |
18 Jun 09 |
martin |
162 |
|
1133 |
18 Jun 09 |
martin |
// Axis, legends and titles |
1178 |
20 Oct 09 |
jari |
164 |
String title = "Control summary"; |
1141 |
24 Jun 09 |
martin |
165 |
String subTitle = null; |
1133 |
18 Jun 09 |
martin |
166 |
|
1133 |
18 Jun 09 |
martin |
167 |
StaticCache cache = Application.getStaticCache(); |
1133 |
18 Jun 09 |
martin |
168 |
if (cacheKey != null) cacheKey = cacheBase + cacheKey; |
1133 |
18 Jun 09 |
martin |
169 |
InputStream cachedImageIn = null; |
1133 |
18 Jun 09 |
martin |
170 |
OutputStream cachedImageOut = null; |
1133 |
18 Jun 09 |
martin |
171 |
RenderedImage image = null; |
1133 |
18 Jun 09 |
martin |
172 |
DbControl dc = null; |
1133 |
18 Jun 09 |
martin |
173 |
boolean wasError = false; |
1141 |
24 Jun 09 |
martin |
174 |
|
1141 |
24 Jun 09 |
martin |
// Get the cached image |
1133 |
18 Jun 09 |
martin |
176 |
try |
1133 |
18 Jun 09 |
martin |
177 |
{ |
1133 |
18 Jun 09 |
martin |
178 |
if (cacheKey != null) |
1133 |
18 Jun 09 |
martin |
179 |
{ |
1133 |
18 Jun 09 |
martin |
180 |
try |
1133 |
18 Jun 09 |
martin |
181 |
{ |
1133 |
18 Jun 09 |
martin |
182 |
cachedImageIn = cache.read(cacheKey, 500); |
1133 |
18 Jun 09 |
martin |
183 |
} |
1133 |
18 Jun 09 |
martin |
184 |
catch (IOException ex) |
1133 |
18 Jun 09 |
martin |
185 |
{ |
1133 |
18 Jun 09 |
martin |
186 |
ex.printStackTrace(); |
1133 |
18 Jun 09 |
martin |
187 |
} |
1133 |
18 Jun 09 |
martin |
188 |
} |
1133 |
18 Jun 09 |
martin |
189 |
try |
1133 |
18 Jun 09 |
martin |
190 |
{ |
1133 |
18 Jun 09 |
martin |
191 |
if (cachedImageIn == null) |
1133 |
18 Jun 09 |
martin |
192 |
{ |
1133 |
18 Jun 09 |
martin |
// Only reload the image if there is no cached version |
1133 |
18 Jun 09 |
martin |
194 |
final SessionControl sc = Application.getSessionControl(ID, request.getRemoteAddr()); |
1133 |
18 Jun 09 |
martin |
195 |
dc = sc.newDbControl(); |
1133 |
18 Jun 09 |
martin |
196 |
|
1135 |
23 Jun 09 |
martin |
197 |
String perfectMatch = ":pm"; |
1135 |
23 Jun 09 |
martin |
198 |
String houseKeeping = "housekeeping"; |
1135 |
23 Jun 09 |
martin |
199 |
String restrictionColumn = "controlGroupId"; |
1135 |
23 Jun 09 |
martin |
200 |
String meanColumn = "mean"; |
1133 |
18 Jun 09 |
martin |
201 |
|
1141 |
24 Jun 09 |
martin |
// Prepare chart and datasets |
1141 |
24 Jun 09 |
martin |
203 |
DefaultCategoryDataset pmDataset = new DefaultCategoryDataset(); |
1141 |
24 Jun 09 |
martin |
204 |
DefaultCategoryDataset houseKeepingDataset = new DefaultCategoryDataset(); |
1141 |
24 Jun 09 |
martin |
205 |
|
1141 |
24 Jun 09 |
martin |
206 |
BioAssaySet bas = BioAssaySet.getById(dc, bioAssaySetId); |
1141 |
24 Jun 09 |
martin |
207 |
ItemQuery<BioAssay> bioassayQuery = bas.getBioAssays(); |
1141 |
24 Jun 09 |
martin |
208 |
subTitle = bas.getName(); |
1141 |
24 Jun 09 |
martin |
209 |
|
1141 |
24 Jun 09 |
martin |
// Prepare filter restrictions and select expression |
1135 |
23 Jun 09 |
martin |
211 |
Restriction pmRestriction = Restrictions.like(Dynamic.reporter(restrictionColumn), Expressions.string("%"+perfectMatch+"%")); |
1135 |
23 Jun 09 |
martin |
212 |
Restriction hkRestriction = Restrictions.like(Dynamic.reporter(restrictionColumn), Expressions.string("%"+houseKeeping+"%")); |
1135 |
23 Jun 09 |
martin |
213 |
Restriction restrictions = Restrictions.or(pmRestriction, hkRestriction); |
1135 |
23 Jun 09 |
martin |
214 |
Expression yExpression = Dynamic.rawData("mean"); |
1135 |
23 Jun 09 |
martin |
215 |
|
1141 |
24 Jun 09 |
martin |
// Get plot data for each bioassay |
1141 |
24 Jun 09 |
martin |
217 |
List<BioAssay> bioassays = bioassayQuery.list(dc); |
1135 |
23 Jun 09 |
martin |
218 |
for (BioAssay ba : bioassays) |
1133 |
18 Jun 09 |
martin |
219 |
{ |
1135 |
23 Jun 09 |
martin |
220 |
List<Number> perfectMatchSpots = new ArrayList<Number>(); |
1135 |
23 Jun 09 |
martin |
221 |
List<Number> houseKeepingSpots = new ArrayList<Number>(); |
1135 |
23 Jun 09 |
martin |
222 |
|
1135 |
23 Jun 09 |
martin |
// Configure query restrictions and selection |
1133 |
18 Jun 09 |
martin |
224 |
DynamicSpotQuery query = ba.getSpotData(); |
1135 |
23 Jun 09 |
martin |
225 |
query.setAutoJoinType(JoinType.INNER); |
1133 |
18 Jun 09 |
martin |
226 |
query.restrict(restrictions); |
1135 |
23 Jun 09 |
martin |
227 |
query.select(Selects.expression(yExpression, meanColumn)); |
1135 |
23 Jun 09 |
martin |
228 |
query.select(Selects.expression(Dynamic.reporter("controlGroupId"), restrictionColumn)); |
1135 |
23 Jun 09 |
martin |
229 |
|
1141 |
24 Jun 09 |
martin |
// Work through the iteration result to get the wanted plot values |
1135 |
23 Jun 09 |
martin |
231 |
DynamicResultIterator result = query.iterate(dc); |
1135 |
23 Jun 09 |
martin |
232 |
int cgiIndex = result.getIndex(restrictionColumn); |
1135 |
23 Jun 09 |
martin |
233 |
int meanIndex = result.getIndex(meanColumn); |
1135 |
23 Jun 09 |
martin |
234 |
while (result.hasNext()) |
1133 |
18 Jun 09 |
martin |
235 |
{ |
1135 |
23 Jun 09 |
martin |
236 |
SqlResult data = result.next(); |
1135 |
23 Jun 09 |
martin |
237 |
if (data.getString(cgiIndex).contains(perfectMatch)) |
1135 |
23 Jun 09 |
martin |
238 |
{ |
1135 |
23 Jun 09 |
martin |
239 |
perfectMatchSpots.add(data.getFloat(meanIndex)); |
1135 |
23 Jun 09 |
martin |
240 |
} |
1135 |
23 Jun 09 |
martin |
241 |
if (data.getString(cgiIndex).contains(houseKeeping)) |
1135 |
23 Jun 09 |
martin |
242 |
{ |
1135 |
23 Jun 09 |
martin |
243 |
houseKeepingSpots.add(data.getFloat(meanIndex)); |
1135 |
23 Jun 09 |
martin |
244 |
} |
1133 |
18 Jun 09 |
martin |
245 |
} |
1141 |
24 Jun 09 |
martin |
// Calculate the mean for each filtered data list and add it to corresponding dataset. |
1135 |
23 Jun 09 |
martin |
247 |
pmDataset.addValue(Statistics.calculateMean(perfectMatchSpots), "Perfect match", ba.getName()); |
1135 |
23 Jun 09 |
martin |
248 |
houseKeepingDataset.addValue(Statistics.calculateMean(houseKeepingSpots), "Housekeeping", ba.getName()); |
1133 |
18 Jun 09 |
martin |
249 |
} |
1135 |
23 Jun 09 |
martin |
250 |
|
1141 |
24 Jun 09 |
martin |
// Configure chart settings and create plot-image |
1141 |
24 Jun 09 |
martin |
252 |
CategoryItemRenderer renderer1 = new LineAndShapeRenderer(); |
1141 |
24 Jun 09 |
martin |
253 |
CategoryItemRenderer renderer2 = new LineAndShapeRenderer(); |
1133 |
18 Jun 09 |
martin |
254 |
NumberAxis axis = new NumberAxis("Signal"); |
1133 |
18 Jun 09 |
martin |
255 |
axis.setStandardTickUnits(NumberAxis.createIntegerTickUnits()); |
1141 |
24 Jun 09 |
martin |
256 |
axis.setLabelFont(new Font("SansSerif", Font.BOLD, 14)); |
1135 |
23 Jun 09 |
martin |
257 |
|
1135 |
23 Jun 09 |
martin |
258 |
renderer1.setSeriesPaint(0, Color.red); |
1135 |
23 Jun 09 |
martin |
259 |
renderer2.setSeriesPaint(0, Color.blue); |
1135 |
23 Jun 09 |
martin |
260 |
renderer1.setBaseToolTipGenerator(new StandardCategoryToolTipGenerator()); |
1133 |
18 Jun 09 |
martin |
261 |
|
1141 |
24 Jun 09 |
martin |
262 |
CategoryAxis domainAxis = new CategoryAxis("Bioassays"); |
1141 |
24 Jun 09 |
martin |
263 |
domainAxis.setCategoryLabelPositions(CategoryLabelPositions.UP_45); |
1141 |
24 Jun 09 |
martin |
264 |
domainAxis.setLabelFont(new Font("SansSerif", Font.BOLD, 14)); |
1141 |
24 Jun 09 |
martin |
265 |
CategoryPlot subplot1 = new CategoryPlot(pmDataset, domainAxis, axis, renderer1); |
1135 |
23 Jun 09 |
martin |
266 |
subplot1.setRenderer(1, renderer2); |
1135 |
23 Jun 09 |
martin |
267 |
subplot1.setDataset(1, houseKeepingDataset); |
1141 |
24 Jun 09 |
martin |
268 |
subplot1.setDomainGridlinesVisible(true); |
1141 |
24 Jun 09 |
martin |
269 |
|
1141 |
24 Jun 09 |
martin |
270 |
JFreeChart chart = new JFreeChart( |
1133 |
18 Jun 09 |
martin |
271 |
null, new Font("SansSerif", Font.BOLD, 12), |
1141 |
24 Jun 09 |
martin |
272 |
subplot1, true); |
1133 |
18 Jun 09 |
martin |
273 |
if (title != null) chart.setTitle(title); |
1133 |
18 Jun 09 |
martin |
274 |
|
1141 |
24 Jun 09 |
martin |
275 |
chart.addSubtitle(new TextTitle(subTitle)); |
1133 |
18 Jun 09 |
martin |
276 |
image = chart.createBufferedImage(width, height); |
1141 |
24 Jun 09 |
martin |
277 |
} |
1133 |
18 Jun 09 |
martin |
278 |
} |
1133 |
18 Jun 09 |
martin |
279 |
catch (Throwable t) |
1133 |
18 Jun 09 |
martin |
280 |
{ |
1133 |
18 Jun 09 |
martin |
281 |
wasError = true; |
1133 |
18 Jun 09 |
martin |
282 |
t.printStackTrace(); |
1141 |
24 Jun 09 |
martin |
// Generate error image |
1141 |
24 Jun 09 |
martin |
284 |
try |
1133 |
18 Jun 09 |
martin |
285 |
{ |
1141 |
24 Jun 09 |
martin |
286 |
BufferedImage img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); |
1141 |
24 Jun 09 |
martin |
287 |
Graphics2D graphics = img.createGraphics(); |
1141 |
24 Jun 09 |
martin |
288 |
graphics.setBackground(Color.WHITE); |
1141 |
24 Jun 09 |
martin |
289 |
graphics.clearRect(0, 0, width, height); |
1141 |
24 Jun 09 |
martin |
290 |
graphics.setColor(Color.RED); |
1141 |
24 Jun 09 |
martin |
291 |
FontRenderContext context = graphics.getFontRenderContext(); |
1141 |
24 Jun 09 |
martin |
292 |
|
1141 |
24 Jun 09 |
martin |
293 |
Font topFont = new Font("SansSerif", Font.BOLD, 12); |
1141 |
24 Jun 09 |
martin |
294 |
Font stackTraceFont = new Font("SansSerif", Font.PLAIN, 12); |
1141 |
24 Jun 09 |
martin |
295 |
|
1141 |
24 Jun 09 |
martin |
296 |
float x = .0f; |
1141 |
24 Jun 09 |
martin |
297 |
float y = .0f; |
1141 |
24 Jun 09 |
martin |
298 |
String causedBy = ""; |
1141 |
24 Jun 09 |
martin |
299 |
do |
1133 |
18 Jun 09 |
martin |
300 |
{ |
1141 |
24 Jun 09 |
martin |
301 |
graphics.setFont(topFont); |
1141 |
24 Jun 09 |
martin |
302 |
String msg = causedBy + t.getClass().getSimpleName() + ": " + t.getMessage(); |
1141 |
24 Jun 09 |
martin |
303 |
x = 5.0f; |
1141 |
24 Jun 09 |
martin |
304 |
Rectangle2D bounds = topFont.getStringBounds(msg, context); |
1141 |
24 Jun 09 |
martin |
305 |
y += bounds.getHeight()+5; |
1141 |
24 Jun 09 |
martin |
306 |
if (bounds.getWidth() > width - x) |
1133 |
18 Jun 09 |
martin |
307 |
{ |
1141 |
24 Jun 09 |
martin |
308 |
msg = cutMiddle(msg, (width - x) / bounds.getWidth()); |
1141 |
24 Jun 09 |
martin |
309 |
} |
1141 |
24 Jun 09 |
martin |
310 |
graphics.drawString(msg, x, y); |
1141 |
24 Jun 09 |
martin |
311 |
|
1141 |
24 Jun 09 |
martin |
312 |
graphics.setFont(stackTraceFont); |
1141 |
24 Jun 09 |
martin |
313 |
x = 15.0f; |
1141 |
24 Jun 09 |
martin |
314 |
for (StackTraceElement st : t.getStackTrace()) |
1141 |
24 Jun 09 |
martin |
315 |
{ |
1141 |
24 Jun 09 |
martin |
316 |
msg = "at " + st.getClassName() + "." + st.getMethodName() + |
1141 |
24 Jun 09 |
martin |
317 |
":" + st.getLineNumber(); |
1141 |
24 Jun 09 |
martin |
318 |
bounds = stackTraceFont.getStringBounds(msg, context); |
1141 |
24 Jun 09 |
martin |
319 |
y += bounds.getHeight(); |
1133 |
18 Jun 09 |
martin |
320 |
if (bounds.getWidth() > width - x) |
1133 |
18 Jun 09 |
martin |
321 |
{ |
1133 |
18 Jun 09 |
martin |
322 |
msg = cutMiddle(msg, (width - x) / bounds.getWidth()); |
1133 |
18 Jun 09 |
martin |
323 |
} |
1133 |
18 Jun 09 |
martin |
324 |
graphics.drawString(msg, x, y); |
1141 |
24 Jun 09 |
martin |
325 |
} |
1141 |
24 Jun 09 |
martin |
326 |
t = t.getCause(); |
1141 |
24 Jun 09 |
martin |
327 |
causedBy = "Caused by: "; |
1141 |
24 Jun 09 |
martin |
328 |
} while (t != null && y < height); |
1141 |
24 Jun 09 |
martin |
329 |
image = img; |
1133 |
18 Jun 09 |
martin |
330 |
} |
1141 |
24 Jun 09 |
martin |
331 |
catch (Throwable t2) |
1133 |
18 Jun 09 |
martin |
332 |
{ |
1141 |
24 Jun 09 |
martin |
333 |
t2.printStackTrace(); |
1133 |
18 Jun 09 |
martin |
334 |
} |
1133 |
18 Jun 09 |
martin |
335 |
} |
1133 |
18 Jun 09 |
martin |
336 |
|
1133 |
18 Jun 09 |
martin |
337 |
if (image != null || cachedImageIn != null) |
1133 |
18 Jun 09 |
martin |
338 |
{ |
1133 |
18 Jun 09 |
martin |
// Send image on HTTP response |
1133 |
18 Jun 09 |
martin |
340 |
response.setContentType("image/" + format); |
1133 |
18 Jun 09 |
martin |
341 |
response.setHeader("Cache-Control", "max-age=3600"); |
1133 |
18 Jun 09 |
martin |
342 |
OutputStream out = response.getOutputStream(); |
1133 |
18 Jun 09 |
martin |
343 |
if (cachedImageIn != null) |
1133 |
18 Jun 09 |
martin |
344 |
{ |
1133 |
18 Jun 09 |
martin |
345 |
FileUtil.copy(cachedImageIn, out); |
1133 |
18 Jun 09 |
martin |
346 |
} |
1133 |
18 Jun 09 |
martin |
347 |
else if (image != null) |
1133 |
18 Jun 09 |
martin |
348 |
{ |
1133 |
18 Jun 09 |
martin |
349 |
if (cacheKey != null && !wasError) cachedImageOut = cache.write(cacheKey, 100); |
1133 |
18 Jun 09 |
martin |
350 |
if (cachedImageOut != null) |
1133 |
18 Jun 09 |
martin |
351 |
{ |
1133 |
18 Jun 09 |
martin |
352 |
out = new TeeOutputStream(out, cachedImageOut); |
1133 |
18 Jun 09 |
martin |
353 |
} |
1133 |
18 Jun 09 |
martin |
354 |
ImageIO.write(image, format, out); |
1133 |
18 Jun 09 |
martin |
355 |
} |
1133 |
18 Jun 09 |
martin |
356 |
out.flush(); |
1133 |
18 Jun 09 |
martin |
357 |
out.close(); |
1133 |
18 Jun 09 |
martin |
358 |
} |
1133 |
18 Jun 09 |
martin |
359 |
else |
1133 |
18 Jun 09 |
martin |
360 |
{ |
1141 |
24 Jun 09 |
martin |
// Something went wrong when genering the error image - send redirect to a predefined image |
1141 |
24 Jun 09 |
martin |
362 |
response.sendRedirect(request.getContextPath() + "/images/plot_error.gif"); |
1133 |
18 Jun 09 |
martin |
363 |
} |
1133 |
18 Jun 09 |
martin |
364 |
} |
1133 |
18 Jun 09 |
martin |
365 |
finally |
1133 |
18 Jun 09 |
martin |
366 |
{ |
1133 |
18 Jun 09 |
martin |
367 |
if (dc != null) dc.close(); |
1133 |
18 Jun 09 |
martin |
368 |
if (cachedImageIn != null) cachedImageIn.close(); |
1133 |
18 Jun 09 |
martin |
369 |
if (cachedImageOut != null) cachedImageOut.close(); |
1133 |
18 Jun 09 |
martin |
370 |
} |
1133 |
18 Jun 09 |
martin |
371 |
} |
1133 |
18 Jun 09 |
martin |
372 |
|
1133 |
18 Jun 09 |
martin |
373 |
/** |
1133 |
18 Jun 09 |
martin |
Forwards requests to {@link #doGet(HttpServletRequest, HttpServletResponse)} |
1133 |
18 Jun 09 |
martin |
375 |
*/ |
1133 |
18 Jun 09 |
martin |
376 |
@Override |
1133 |
18 Jun 09 |
martin |
377 |
public void doPost(HttpServletRequest request, HttpServletResponse response) |
1133 |
18 Jun 09 |
martin |
378 |
throws IOException, ServletException |
1133 |
18 Jun 09 |
martin |
379 |
{ |
1133 |
18 Jun 09 |
martin |
380 |
doGet(request, response); |
1133 |
18 Jun 09 |
martin |
381 |
} |
1133 |
18 Jun 09 |
martin |
382 |
|
1133 |
18 Jun 09 |
martin |
383 |
|
1133 |
18 Jun 09 |
martin |
384 |
private String cutMiddle(String msg, double fraction) |
1133 |
18 Jun 09 |
martin |
385 |
{ |
1133 |
18 Jun 09 |
martin |
386 |
int charactersToCut = (int)(msg.length() * (1 - fraction)) + 3; |
1133 |
18 Jun 09 |
martin |
387 |
int beginAt = (msg.length() - charactersToCut) / 2; |
1133 |
18 Jun 09 |
martin |
388 |
return msg.substring(0, beginAt) + "..." + msg.substring(beginAt + charactersToCut); |
1133 |
18 Jun 09 |
martin |
389 |
} |
1178 |
20 Oct 09 |
jari |
390 |
} |