comparison flys-artifacts/src/main/java/de/intevation/flys/artifacts/services/FixingsKMChartService.java @ 2620:cc0fa1798a3c

FixingsKMChartService: Generate chart and deliver the image as the response of the service. flys-artifacts/trunk@4205 c6561f87-3c4e-4783-a992-168aeb5c3f6f
author Sascha L. Teichmann <sascha.teichmann@intevation.de>
date Thu, 05 Apr 2012 18:07:47 +0000
parents b0597a63fe70
children f0cc556eda29
comparison
equal deleted inserted replaced
2619:6ed24efc80de 2620:cc0fa1798a3c
1 package de.intevation.flys.artifacts.services; 1 package de.intevation.flys.artifacts.services;
2
3 import java.util.List;
4 2
5 import de.intevation.artifactdatabase.DefaultService; 3 import de.intevation.artifactdatabase.DefaultService;
6 4
7 import de.intevation.artifacts.CallMeta; 5 import de.intevation.artifacts.CallMeta;
8 import de.intevation.artifacts.GlobalContext; 6 import de.intevation.artifacts.GlobalContext;
9 import de.intevation.artifacts.Service; 7 import de.intevation.artifacts.Service;
10 8
11 import de.intevation.flys.artifacts.model.FixingsFilterBuilder;
12 import de.intevation.flys.artifacts.model.FixingsOverview;
13 import de.intevation.flys.artifacts.model.FixingsColumn; 9 import de.intevation.flys.artifacts.model.FixingsColumn;
14 import de.intevation.flys.artifacts.model.FixingsColumnFactory; 10 import de.intevation.flys.artifacts.model.FixingsColumnFactory;
11 import de.intevation.flys.artifacts.model.FixingsFilterBuilder;
12
13 import de.intevation.flys.artifacts.model.FixingsOverview.Fixing;
14
15 import de.intevation.flys.artifacts.model.FixingsOverview;
15 import de.intevation.flys.artifacts.model.FixingsOverviewFactory; 16 import de.intevation.flys.artifacts.model.FixingsOverviewFactory;
16 17
17 import de.intevation.flys.artifacts.model.FixingsOverview.Fixing;
18
19 import de.intevation.flys.backend.SessionHolder; 18 import de.intevation.flys.backend.SessionHolder;
20 19
20 import de.intevation.flys.utils.Pair;
21
22 import gnu.trove.TDoubleArrayList;
23
24 import java.awt.Dimension;
25 import java.awt.Transparency;
26
27 import java.awt.image.BufferedImage;
28
29 import java.io.ByteArrayOutputStream;
30 import java.io.IOException;
31
32 import java.util.ArrayList;
33 import java.util.List;
34
35 import javax.imageio.ImageIO;
36
21 import org.apache.log4j.Logger; 37 import org.apache.log4j.Logger;
38
39 import org.jfree.chart.ChartFactory;
40 import org.jfree.chart.ChartUtilities;
41 import org.jfree.chart.JFreeChart;
42
43 import org.jfree.chart.plot.PlotOrientation;
44 import org.jfree.chart.plot.XYPlot;
45
46 import org.jfree.data.xy.DefaultXYDataset;
22 47
23 import org.w3c.dom.Document; 48 import org.w3c.dom.Document;
24 import org.w3c.dom.Element; 49 import org.w3c.dom.Element;
25 import org.w3c.dom.NodeList; 50 import org.w3c.dom.NodeList;
26 51
28 extends DefaultService 53 extends DefaultService
29 { 54 {
30 private static final Logger log = 55 private static final Logger log =
31 Logger.getLogger(FixingsKMChartService.class); 56 Logger.getLogger(FixingsKMChartService.class);
32 57
58 public static final int DEFAULT_WIDTH = 240;
59 public static final int DEFAULT_HEIGHT = 180;
60
61 public static final String DEFAULT_FORMAT = "png";
62
63 // TODO: Load fancy image from resources.
33 public static final byte [] EMPTY = { 64 public static final byte [] EMPTY = {
34 (byte)0x89, (byte)0x50, (byte)0x4e, (byte)0x47, 65 (byte)0x89, (byte)0x50, (byte)0x4e, (byte)0x47,
35 (byte)0x0d, (byte)0x0a, (byte)0x1a, (byte)0x0a, 66 (byte)0x0d, (byte)0x0a, (byte)0x1a, (byte)0x0a,
36 (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0d, 67 (byte)0x00, (byte)0x00, (byte)0x00, (byte)0x0d,
37 (byte)0x49, (byte)0x48, (byte)0x44, (byte)0x52, 68 (byte)0x49, (byte)0x48, (byte)0x44, (byte)0x52,
89 SessionHolder.release(); 120 SessionHolder.release();
90 } 121 }
91 } 122 }
92 123
93 protected Service.Output doProcess( 124 protected Service.Output doProcess(
94 Document data, 125 Document input,
95 GlobalContext globalContext, 126 GlobalContext globalContext,
96 CallMeta callMeta 127 CallMeta callMeta
97 ) { 128 ) {
98 NodeList rivers = data.getElementsByTagName("river"); 129 String river = getRiverName(input);
99 NodeList kms = data.getElementsByTagName("km"); 130 Double km = getKM(input);
100 131 Dimension extent = getExtent(input);
101 if (rivers.getLength() == 0 || kms.getLength() == 0) { 132 String format = getFormat(input);
102 log.warn("Missing river and/or km."); 133
103 return empty(); 134 if (river == null || km == null) {
104 } 135 log.warn("River and/or km invalid.");
105
106 String river = ((Element)rivers.item(0)).getAttribute("name");
107 String kmS = ((Element)kms .item(0)).getAttribute("value");
108
109 if (river.length() == 0 || kmS.length() == 0) {
110 log.warn("River and/or km empty string.");
111 return empty();
112 }
113
114 double km;
115 try {
116 km = Double.parseDouble(kmS);
117 }
118 catch (NumberFormatException nfe) {
119 log.warn("Km '" + kmS + " is not a valid number.");
120 return empty(); 136 return empty();
121 } 137 }
122 138
123 FixingsOverview overview = FixingsOverviewFactory.getOverview(river); 139 FixingsOverview overview = FixingsOverviewFactory.getOverview(river);
124 140
125 if (overview == null) { 141 if (overview == null) {
126 log.warn("No overview found for river '" + river + "'"); 142 log.warn("No overview found for river '" + river + "'");
127 return empty(); 143 return empty();
128 } 144 }
129 145
130 FixingsFilterBuilder ffb = new FixingsFilterBuilder(data); 146 FixingsFilterBuilder ffb = new FixingsFilterBuilder(input);
131 147
132 List<Fixing.Column> columns = overview.filter( 148 List<Fixing.Column> columns = overview.filter(
133 ffb.getRange(), 149 ffb.getRange(),
134 ffb.getFilter()); 150 ffb.getFilter());
135 151
136 for (Fixing.Column column: columns) { 152 List<Pair<Fixing.Column, FixingsColumn>> cols =
137 FixingsColumn columnData = 153 new ArrayList<Pair<Fixing.Column, FixingsColumn>>();
138 FixingsColumnFactory.INSTANCE.getColumnData(column); 154
139 if (columnData == null) { 155 for (Fixing.Column col: columns) {
140 continue; 156 FixingsColumn data =
141 } 157 FixingsColumnFactory.INSTANCE.getColumnData(col);
142 } 158 if (data != null) {
143 // TODO: Implement chart generation! 159 cols.add(new Pair<Fixing.Column, FixingsColumn>(col, data));
144 160 }
145 return empty(); 161 }
162
163 JFreeChart chart = createChart(cols, river, km);
164
165 return encode(chart, extent, format);
166 }
167
168 protected static Output encode(
169 JFreeChart chart,
170 Dimension extent,
171 String format
172 ) {
173 BufferedImage image = chart.createBufferedImage(
174 extent.width, extent.height,
175 Transparency.BITMASK,
176 null);
177
178 ByteArrayOutputStream out = new ByteArrayOutputStream();
179
180 try {
181 ImageIO.write(image, format, out);
182 }
183 catch (IOException ioe) {
184 log.warn("writing image failed", ioe);
185 return empty();
186 }
187
188 return new Output(out.toByteArray(), "image/" + format);
189 }
190
191 protected static JFreeChart createChart(
192 List<Pair<Fixing.Column, FixingsColumn>> cols,
193 String river,
194 double km
195 ) {
196
197 TDoubleArrayList ws = new TDoubleArrayList(cols.size());
198 TDoubleArrayList qs = new TDoubleArrayList(cols.size());
199
200 double [] w = new double[1];
201 for (Pair<Fixing.Column, FixingsColumn> col: cols) {
202 boolean interpolated = col.getB().getW(km, w);
203 // TODO: Do something special with the interpolated values.
204 double q = col.getB().getQ(km);
205 if (!Double.isNaN(w[0]) && !Double.isNaN(q)) {
206 ws.add(w[0]);
207 qs.add(q);
208 // TODO: Generate labels depending on sectors.
209 }
210 }
211
212 DefaultXYDataset dataset = new DefaultXYDataset();
213
214 dataset.addSeries(
215 "Fixierungen", // TODO: i18n
216 new double [][] { ws.toNativeArray(), qs.toNativeArray() });
217
218 JFreeChart chart = ChartFactory.createXYLineChart(
219 "Fixierungen " + river + ": km " + km, // TODO: i18n
220 "Q", // TODO: i18n
221 "W", // TODO: i18n
222 null,
223 PlotOrientation.VERTICAL,
224 true,
225 true,
226 false);
227
228 XYPlot plot = chart.getXYPlot();
229
230 plot.setDataset(dataset);
231
232 ChartUtilities.applyCurrentTheme(chart);
233
234 return chart;
235 }
236
237 protected static String getRiverName(Document input) {
238 NodeList rivers = input.getElementsByTagName("river");
239
240 if (rivers.getLength() == 0) {
241 return null;
242 }
243
244 String river = ((Element)rivers.item(0)).getAttribute("name");
245
246 return river.length() == 0 ? river : null;
247 }
248
249 protected static Double getKM(Document input) {
250 NodeList kms = input.getElementsByTagName("km");
251
252 if (kms.getLength() == 0) {
253 return null;
254 }
255
256 String km = ((Element)kms.item(0)).getAttribute("value");
257
258 try {
259 return Double.valueOf(km);
260 }
261 catch (NumberFormatException nfe) {
262 log.warn("Km '" + km + " is not a valid number.");
263 return null;
264 }
265 }
266
267 protected static Dimension getExtent(Document input) {
268
269 int width = DEFAULT_WIDTH;
270 int height = DEFAULT_HEIGHT;
271
272 NodeList extents = input.getElementsByTagName("extent");
273
274 if (extents.getLength() > 0) {
275 Element element = (Element)extents.item(0);
276 String w = element.getAttribute("width");
277 String h = element.getAttribute("height");
278
279 try {
280 width = Math.max(1, Integer.parseInt(w));
281 }
282 catch (NumberFormatException nfe) {
283 log.warn("width '" + w + "' is not a valid.");
284 }
285
286 try {
287 height = Math.max(1, Integer.parseInt(h));
288 }
289 catch (NumberFormatException nfe) {
290 log.warn("height '" + h + "' is not a valid");
291 }
292 }
293
294 return new Dimension(width, height);
295 }
296
297 protected static String getFormat(Document input) {
298 String format = DEFAULT_FORMAT;
299
300 NodeList formats = input.getElementsByTagName("format");
301
302 if (formats.getLength() > 0) {
303 String type = ((Element)formats.item(0)).getAttribute("type");
304 if (type.length() > 0) {
305 format = type;
306 }
307 }
308
309 return format;
146 } 310 }
147 } 311 }
148 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : 312 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org