comparison gnv-artifacts/src/main/java/de/intevation/gnv/state/OutputStateBase.java @ 875:5e9efdda6894

merged gnv-artifacts/1.0
author Thomas Arendsen Hein <thomas@intevation.de>
date Fri, 28 Sep 2012 12:13:56 +0200
parents 499cfbbb61bc
children c07d9f9a738c
comparison
equal deleted inserted replaced
722:bb3ffe7d719e 875:5e9efdda6894
1 package de.intevation.gnv.state;
2
3 import java.io.OutputStream;
4 import java.util.ArrayList;
5 import java.util.Collection;
6 import java.util.HashMap;
7 import java.util.Iterator;
8 import java.util.List;
9 import java.util.Locale;
10
11 import javax.xml.xpath.XPathConstants;
12
13 import net.sf.ehcache.Cache;
14
15 import org.apache.log4j.Logger;
16 import org.w3c.dom.Document;
17 import org.w3c.dom.Element;
18 import org.w3c.dom.Node;
19 import org.w3c.dom.NodeList;
20
21 import de.intevation.artifactdatabase.Config;
22 import de.intevation.artifactdatabase.XMLUtils;
23 import de.intevation.artifacts.CallContext;
24 import de.intevation.artifacts.CallMeta;
25 import de.intevation.gnv.artifacts.cache.CacheFactory;
26 import de.intevation.gnv.artifacts.ressource.RessourceFactory;
27 import de.intevation.gnv.geobackend.base.Result;
28 import de.intevation.gnv.geobackend.base.query.QueryExecutor;
29 import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory;
30 import de.intevation.gnv.geobackend.base.query.exception.QueryException;
31 import de.intevation.gnv.state.describedata.MinMaxDescribeData;
32 import de.intevation.gnv.state.exception.StateException;
33 import de.intevation.gnv.utils.InputValidator;
34
35 /**
36 * This is the default implementation of <code>OutputState</code>. Artifacts
37 * having reached this state or a subclass of this state are able to produce
38 * some output (e.g. chart, histograms, statistic, etc).
39 *
40 * @author <a href="mailto:tim.englich@intevation.de">Tim Englich</a>
41 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a>
42 *
43 */
44 public abstract class OutputStateBase
45 extends StateBase
46 implements OutputState
47 {
48 public static final String XPATH_OUTPUT_MODE =
49 "/art:action/art:out/@name";
50
51 public static final String XPATH_EXPORT_MODE =
52 "/art:action/art:out/art:export/@name";
53
54 public static final String XPATH_MIME_TYPE =
55 "/art:action/art:out/art:mime-type/@value";
56
57 public static final String XPATH_EXPORTS =
58 "exportModes/export";
59
60 /**
61 * The UID of this Class
62 */
63 private static final long serialVersionUID = -1718732895737303823L;
64
65 /**
66 * the logger, used to log exceptions and additonaly information
67 */
68 private static Logger log = Logger.getLogger(OutputStateBase.class);
69
70 /**
71 * The different Outputmodes which are provided by an OutputState
72 */
73 protected Collection<OutputMode> outputModes = null;
74
75 protected String queryODVID = null;
76
77 /**
78 * Constructor
79 */
80 public OutputStateBase() {
81 super();
82 }
83
84 public Collection<OutputMode> getOutputModes() {
85 log.debug("OutputStateBase.getOutputModes");
86 return this.outputModes;
87 }
88
89
90 @Override
91 public void setup(Node configuration) {
92 log.debug("OutputStateBase.setup");
93 super.setup(configuration);
94
95 this.queryODVID = Config.getStringXPath(configuration,"queryID-odv");
96
97 NodeList outputModeList = Config.getNodeSetXPath(configuration,
98 "outputsModes/outputsMode");
99 if (outputModeList != null) {
100 log.debug(outputModeList.getLength() + " were found.");
101 this.outputModes = new ArrayList<OutputMode>(outputModeList
102 .getLength());
103 for (int i = 0; i < outputModeList.getLength(); i++) {
104 Element currentNode = (Element)outputModeList.item(i);
105 String name = currentNode.getAttribute("name");
106 String description =currentNode.getAttribute("description");
107 String mimeType = currentNode.getAttribute("mime-type");
108 NodeList inputValuesList = Config.getNodeSetXPath(currentNode,
109 "parameters/inputvalue");
110 Collection<InputValue> inputParameters = null;
111 if (inputValuesList != null) {
112 inputParameters = new ArrayList<InputValue>(inputValuesList
113 .getLength());
114 for (int j = 0; j < inputValuesList.getLength(); j++) {
115 Element currentInputValuesNode = (Element)inputValuesList.item(j);
116 String inputValueName = currentInputValuesNode.getAttribute("name");
117 String inputValueType = currentInputValuesNode.getAttribute("type");
118 String defaultValue =currentInputValuesNode.getAttribute("value");
119 boolean isMultiselect = false;
120 InputValue inputValue = new DefaultInputValue(
121 inputValueName, inputValueType, defaultValue,
122 isMultiselect);
123 inputParameters.add(inputValue);
124 }
125 }
126
127 // parse export modes
128 List<ExportMode> exportList = null;
129 NodeList exports = (NodeList) XMLUtils.xpath(
130 currentNode, XPATH_EXPORTS, XPathConstants.NODESET);
131
132 if (exports != null) {
133 int exportSize = exports.getLength();
134
135 exportList = new ArrayList<ExportMode>(exportSize);
136 for (int k = 0; k < exportSize; k++) {
137 Element exp = (Element) exports.item(k);
138 String expName = exp.getAttribute("name");
139 String expDesc = exp.getAttribute("description");
140 String expMime = exp.getAttribute("mime-type");
141
142 exportList.add(
143 new DefaultExportMode(expName, expDesc, expMime));
144 }
145 }
146
147 OutputMode outputMode = new DefaultOutputMode(name,
148 description, mimeType, inputParameters, exportList);
149 log.debug(outputMode.toString());
150 this.outputModes.add(outputMode);
151
152 }
153 }
154 }
155
156
157 @Override
158 public void advance(String uuid, CallContext context)
159 throws StateException
160 {
161 }
162
163
164 @Override
165 public void initialize(String uuid, CallContext context)
166 throws StateException
167 {
168 }
169
170 /**
171 * This method needs to be defined by concrete subclasses. Nothing is done
172 * here.
173 */
174 public void out(
175 Document format,
176 Collection<InputData> inputData,
177 OutputStream outputStream,
178 String uuid,
179 CallMeta callMeta
180 )
181 throws StateException
182 {
183 }
184
185 /**
186 * This method needs to be defined by concrete subclasses. Nothing is done
187 * here.
188 */
189 public void out(String outputMode, Collection<InputData> inputData,
190 OutputStream outputStream) throws StateException {
191 }
192
193 /**
194 * Returns the data used to create charts. If a cache is configured, try to
195 * fetch the data from cache. The database is queried if the data is not in
196 * cache yet, or if no cache is configured. If the cache is configured, but
197 * the data is not in cache yet, put it into cache for a faster access
198 * in a later time.
199 *
200 * @param uuid The uuid of an artifact.
201 * @param callContext The CallContext.
202 * @return the chart data.
203 */
204 protected Object getChartResult(String uuid, CallContext callContext) {
205 log.debug("OutputStateBase.getChartResult");
206 CacheFactory factory = CacheFactory.getInstance();
207
208 if (factory.isInitialized()) {
209 // we use a cache
210 log.info("Using cache.");
211 Cache cache = factory.getCache();
212 String key = "chart_" + getHash();
213
214 net.sf.ehcache.Element value = cache.get(key);
215 if (value != null) {
216 log.debug("Found element in cache.");
217 return value.getObjectValue();
218 }
219 else {
220 log.debug("Element not in cache, we need to ask the database");
221 Object result = getData(queryID);
222 cache.put(new net.sf.ehcache.Element(key, result));
223
224 return result;
225 }
226 }
227 else {
228 // we don't use a cache, so we have to query the database every
229 // single time
230 log.info("Not using a cache.");
231 return getData(queryID);
232 }
233 }
234
235 /**
236 * This method should no longer be used, because it is not good to put a
237 * chart into cache. Parameter changes done by the user wouldn't be detected
238 * proper.
239 * @deprecated
240 */
241 protected Object getChartFromCache(String uuid, CallContext callContext) {
242 log.debug("Fetch chart [" + uuid + "] from cache");
243 CacheFactory cacheFactory = CacheFactory.getInstance();
244 if (cacheFactory.isInitialized()) {
245 String key = "chart_" + getHash();
246 net.sf.ehcache.Element object = cacheFactory.getCache().get(key);
247
248 if (object != null) {
249 return object.getObjectValue();
250 }
251 }
252 return null;
253 }
254
255 /**
256 * Retrieves the data used to create an ODV export.
257 *
258 * @param uuid
259 * @return odv data.
260 */
261 protected Collection<Result> getODVResult(String uuid) {
262 log.debug("OutputStateBase.getODVResult");
263 // TODO add Caching? I think it's not nessessary
264 Collection<Result> returnValue = null;
265 if (this.queryODVID != null){
266 returnValue = this.getData(this.queryODVID);
267 }else{
268 log.warn("No Query for ODV Data is defined.");
269 }
270 return returnValue;
271 }
272
273 /**
274 * Retrieve data from database with help of queryID.
275 *
276 * @param queryID A query id defined in sql statements properties file.
277 * @return some data.
278 */
279 protected Collection<Result> getData(String queryID) {
280 log.debug("OutputStateBase.getData");
281 Collection<Result> returnValue = null;
282 try {
283 String[] filterValues = this.generateFilterValuesFromInputData();
284 try {
285 QueryExecutor queryExecutor = QueryExecutorFactory
286 .getInstance()
287 .getQueryExecutor();
288 returnValue = queryExecutor.executeQuery(queryID,filterValues);
289 } catch (RuntimeException e) {
290 log.error(e, e);
291 }
292 } catch (QueryException e) {
293 log.error(e, e);
294 }
295 return returnValue;
296 }
297
298 /**
299 * This method removes the data used for creating charts from cache.
300 *
301 */
302 protected void removeChartResult(String uuid) {
303 log.debug("OutputStateBase.getChartResult");
304 if (CacheFactory.getInstance().isInitialized()) {
305 String key = "chart_" + getHash();
306 log.debug("Hash for Queryelements: " + key);
307 net.sf.ehcache.Element value = CacheFactory.getInstance().getCache().get(key);
308 if (value != null) {
309 CacheFactory.getInstance().getCache().remove(key);
310 }
311 }
312 }
313
314 /**
315 * This method should no longer be used. It removes a chart from cache.
316 *
317 * @deprecated
318 */
319 protected void removeChart(String uuid) {
320 log.debug("OutputStateBase.removeChart from cache");
321
322 CacheFactory cacheFactory = CacheFactory.getInstance();
323 if (cacheFactory.isInitialized()) {
324 String key = "chart_" + getHash();
325 net.sf.ehcache.Element object = cacheFactory.getCache().get(key);
326 if (object != null)
327 cacheFactory.getCache().remove(key);
328 }
329 }
330
331 /**
332 * This is an internal method used while database query.
333 */
334 protected void purifyChart(Object chart, String uuid) {
335 log.debug("Prufify chart [" + uuid + "]");
336 CacheFactory cacheFactory = CacheFactory.getInstance();
337 if (cacheFactory.isInitialized()) {
338 String key = "chart_" + getHash();
339 cacheFactory.getCache().put(new net.sf.ehcache.Element(key, chart));
340 }
341 }
342
343
344 /**
345 * Use this method to feed a state with new data.
346 */
347 @Override
348 public Document feed(
349 CallContext context,
350 Collection<InputData> inputData,
351 String uuid)
352 throws StateException
353 {
354 putInputData(inputData, uuid);
355
356 return feedSuccess();
357 }
358
359 /**
360 * This method is used to put new data into a next state. The difference
361 * between this method and feed is, that this method should be used to
362 * transfer some old input data required by this state. New data need to be
363 * inserted via feed!
364 */
365 @Override
366 public void putInputData(Collection<InputData> inputData,
367 String uuid)
368 throws StateException {
369 log.debug("OutputStateBase.putInputData");
370 this.removeChartResult(uuid);
371 this.removeChart(uuid);
372
373 if (inputData != null) {
374 Iterator<InputData> it = inputData.iterator();
375 InputValidator iv = new InputValidator();
376 while (it.hasNext()) {
377 InputData tmpItem = it.next();
378 Object tmpObj = tmpItem.getObject();
379 InputValue inputValue = this.inputValues.get(tmpItem.getName());
380 if (inputValue != null) {
381 if (this.inputData == null) {
382 this.inputData = new HashMap<String, InputData>(
383 inputData.size());
384 }
385
386 boolean valid = InputValidator.isInputValid(tmpItem.getValue(),
387 inputValue.getType());
388 if (valid) {
389 if (tmpItem.getName().equals(MINVALUEFIELDNAME)){
390 String minValue = tmpItem.getValue();
391 String maxValue = getInputValue4ID(inputData, MAXVALUEFIELDNAME);
392 valid = InputValidator.isInputValid(maxValue,inputValue.getType());
393 if (!valid){
394 String errMsg = "Wrong input for " + tmpItem.getValue()
395 + " is not an " + inputValue.getType()
396 + " Value.";
397 log.warn(errMsg);
398 throw new StateException(errMsg);
399 }
400
401 valid = InputValidator.isInputValid(minValue,
402 maxValue,
403 inputValue.getType());
404 if (!valid){
405 String errMsg = "MaxValue-Input is less than MinValue-Input ";
406 log.warn(errMsg);
407 throw new StateException(errMsg);
408 }
409 }else if (tmpItem.getName().equals(MAXVALUEFIELDNAME)){
410 String minValue = getInputValue4ID(inputData, MINVALUEFIELDNAME);
411 String maxValue = tmpItem.getValue();
412 valid = InputValidator.isInputValid(minValue,inputValue.getType());
413 if (!valid){
414 String errMsg = "Wrong input for " + tmpItem.getValue()
415 + " is not an " + inputValue.getType()
416 + " Value.";
417 log.warn(errMsg);
418 throw new StateException(errMsg);
419 }
420
421 valid = InputValidator.isInputValid(minValue,
422 maxValue,
423 inputValue.getType());
424 if (!valid){
425 String errMsg = "MaxValue-Input is less than MinValue-Input ";
426 log.warn(errMsg);
427 throw new StateException(errMsg);
428 }
429 }
430 this.inputData.put(tmpItem.getName(), tmpItem);
431 } else {
432 String errMsg = "Wrong input for " + tmpItem.getValue()
433 + " is not an " + inputValue.getType()
434 + " Value.";
435 log.warn(errMsg);
436 throw new StateException(errMsg);
437 }
438
439 }
440 else if (tmpObj != null && tmpObj instanceof MinMaxDescribeData) {
441 MinMaxDescribeData data = (MinMaxDescribeData) tmpObj;
442 if (this.inputData == null) {
443 this.inputData = new HashMap<String, InputData>(inputData.size());
444 }
445 this.inputData.put(tmpItem.getName(), tmpItem);
446 this.inputData.put("minvalue", new DefaultInputData("minvalue", (String) data.getMinValue()));
447 this.inputData.put("maxvalue", new DefaultInputData("maxvalue", (String) data.getMaxValue()));
448 }
449 else {
450
451 String errMsg = "No Inputvalue given for Inputdata "
452 + tmpItem.getName();
453 log.warn(errMsg + "Value will be ignored");
454
455 }
456 }
457 } else {
458 log.warn("No Inputdata given");
459 }
460 setHash(uuid);
461 }
462
463
464 public void out(
465 String outputMode,
466 Collection<InputData> inputData,
467 OutputStream outputStream,
468 String uuid,
469 CallMeta callMeta)
470 throws StateException { }
471
472
473 /**
474 * Retrieves a message from resource bundle specified by locale.
475 *
476 * @param locale Locale to use.
477 * @param key The key of the message.
478 * @param value The default value.
479 * @return The value.
480 */
481 protected String getMessage(Locale locale, String key, String value) {
482 return RessourceFactory.getInstance().getRessource(
483 locale,
484 key,
485 value
486 );
487 }
488 }
489 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org