Mercurial > dive4elements > gnv-client
comparison gnv-artifacts/src/main/java/de/intevation/gnv/state/StateBase.java @ 1119:7c4f81f74c47
merged gnv-artifacts
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:00 +0200 |
parents | dec4257ad570 |
children |
comparison
equal
deleted
inserted
replaced
1027:fca4b5eb8d2f | 1119:7c4f81f74c47 |
---|---|
1 /* | |
2 * Copyright (c) 2010 by Intevation GmbH | |
3 * | |
4 * This program is free software under the LGPL (>=v2.1) | |
5 * Read the file LGPL.txt coming with the software for details | |
6 * or visit http://www.gnu.org/licenses/ if it does not exist. | |
7 */ | |
8 | |
9 package de.intevation.gnv.state; | |
10 | |
11 import java.text.DateFormat; | |
12 import java.text.SimpleDateFormat; | |
13 | |
14 import java.util.ArrayList; | |
15 import java.util.Arrays; | |
16 import java.util.Collection; | |
17 import java.util.Date; | |
18 import java.util.GregorianCalendar; | |
19 import java.util.HashMap; | |
20 import java.util.Iterator; | |
21 import java.util.List; | |
22 import java.util.Locale; | |
23 import java.util.Map; | |
24 import java.util.Set; | |
25 import java.util.TreeMap; | |
26 | |
27 import javax.xml.xpath.XPathConstants; | |
28 | |
29 import net.sf.ehcache.Cache; | |
30 | |
31 import org.apache.log4j.Logger; | |
32 import org.w3c.dom.Document; | |
33 import org.w3c.dom.Element; | |
34 import org.w3c.dom.Node; | |
35 import org.w3c.dom.NodeList; | |
36 | |
37 import de.intevation.artifacts.common.utils.Config; | |
38 import de.intevation.artifacts.common.utils.XMLUtils; | |
39 import de.intevation.artifacts.ArtifactNamespaceContext; | |
40 import de.intevation.artifacts.CallContext; | |
41 import de.intevation.artifacts.CallMeta; | |
42 import de.intevation.gnv.artifacts.cache.CacheFactory; | |
43 import de.intevation.gnv.artifacts.ressource.RessourceFactory; | |
44 import de.intevation.gnv.geobackend.base.Result; | |
45 import de.intevation.gnv.geobackend.base.query.QueryExecutor; | |
46 import de.intevation.gnv.geobackend.base.query.QueryExecutorFactory; | |
47 import de.intevation.gnv.geobackend.base.query.exception.QueryException; | |
48 import de.intevation.gnv.geobackend.util.DateUtils; | |
49 import de.intevation.gnv.state.describedata.DefaultKeyValueDescribeData; | |
50 import de.intevation.gnv.state.describedata.KeyValueDescibeData; | |
51 import de.intevation.gnv.state.describedata.MinMaxDescribeData; | |
52 import de.intevation.gnv.state.describedata.NamedArrayList; | |
53 import de.intevation.gnv.state.describedata.NamedCollection; | |
54 import de.intevation.gnv.state.describedata.SingleValueDescribeData; | |
55 import de.intevation.gnv.state.exception.StateException; | |
56 import de.intevation.gnv.utils.ArtifactXMLUtilities; | |
57 import de.intevation.gnv.utils.InputValidator; | |
58 | |
59 /** | |
60 * This is the major implementation of <code>State</code>. Nearly every other | |
61 * state is derived by this class. | |
62 * | |
63 * @author <a href="mailto:tim.englich@intevation.de">Tim Englich</a> | |
64 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> | |
65 * @author <a href="mailto:sascha.teichmann@intevation.de">Sascha L. Teichmann</a> | |
66 */ | |
67 public abstract class StateBase implements State { | |
68 | |
69 /** | |
70 * The UID of this Class | |
71 */ | |
72 private static final long serialVersionUID = 2411169179001645426L; | |
73 | |
74 /** | |
75 * the logger, used to log exceptions and additonaly information | |
76 */ | |
77 private static Logger log = Logger.getLogger(StateBase.class); | |
78 | |
79 protected final static String MINVALUEFIELDNAME = "minvalue"; | |
80 | |
81 protected final static String MAXVALUEFIELDNAME = "maxvalue"; | |
82 | |
83 private final static String NODATASELECTIONKEY = "n/n"; | |
84 | |
85 public final static String DESCRIBEDATAKEY = "_DESCRIBEDATA"; | |
86 | |
87 public final static String XPATH_STATIC_UI = "art:static"; | |
88 | |
89 public final static String XPATH_DYNAMIC_UI = "art:dynamic"; | |
90 | |
91 public static final String EXCEPTION_NO_INPUT = "no.input.data"; | |
92 | |
93 public static final String EXCEPTION_INVALID_INPUT = | |
94 "input.is.not.valid"; | |
95 | |
96 public final static String HASH_ID_SEPARATOR = "#"; | |
97 | |
98 /** input value names which should not be rendered from State itself */ | |
99 public final static String[] BLACKLIST = {"sourceid", "fisname"}; | |
100 | |
101 private String id = null; | |
102 | |
103 protected String hash; | |
104 | |
105 private String description = null; | |
106 | |
107 protected String dataName = null; | |
108 | |
109 protected String preSettingsName = null; | |
110 | |
111 protected boolean dataMultiSelect = false; | |
112 | |
113 protected boolean dataNoSelect = false; | |
114 | |
115 protected String queryID = null; | |
116 | |
117 protected Collection<String> inputValueNames = null; | |
118 | |
119 protected Map<String, InputValue> inputValues = null; | |
120 | |
121 protected State parent = null; | |
122 | |
123 protected Map<String, InputData> inputData = null; | |
124 | |
125 protected Map<String, InputData> preSettings = null; | |
126 | |
127 | |
128 /** | |
129 * The source date format as string. | |
130 */ | |
131 public static String srcDateFormat = "yyyy.MM.dd hh:mm:ss"; | |
132 | |
133 | |
134 /** | |
135 * The source date format used to read string represented strings. | |
136 */ | |
137 public static DateFormat srcFormat; | |
138 | |
139 | |
140 static { | |
141 srcFormat = new SimpleDateFormat(srcDateFormat); | |
142 } | |
143 | |
144 | |
145 /** | |
146 * Constructor | |
147 */ | |
148 public StateBase() { | |
149 super(); | |
150 } | |
151 | |
152 | |
153 public String getID() { | |
154 return this.id; | |
155 } | |
156 | |
157 | |
158 public String getDescription() { | |
159 return this.description; | |
160 } | |
161 | |
162 | |
163 public Collection<InputValue> getRequiredInputValues() { | |
164 return this.inputValues.values(); | |
165 } | |
166 | |
167 | |
168 public void reset(String uuid) { | |
169 inputData.remove(dataName); | |
170 } | |
171 | |
172 | |
173 public void setup(Node configuration) { | |
174 this.id = ((Element)configuration).getAttribute("id"); | |
175 this.description = ((Element)configuration).getAttribute("description"); | |
176 | |
177 log.info("State-ID = " + this.id); | |
178 | |
179 NodeList inputValuesNodes = Config.getNodeSetXPath(configuration, | |
180 "inputvalues/inputvalue"); | |
181 this.inputValues = new HashMap<String, InputValue>(inputValuesNodes | |
182 .getLength()); | |
183 this.inputValueNames = new ArrayList<String>(inputValuesNodes | |
184 .getLength()); | |
185 for (int i = 0; i < inputValuesNodes.getLength(); i++) { | |
186 Element inputValueNode = (Element)inputValuesNodes.item(i); | |
187 String usedinQueryValue = inputValueNode.getAttribute("usedinquery"); | |
188 int usedinQuery = 1; | |
189 if (usedinQueryValue != null) { | |
190 try { | |
191 usedinQuery = Integer.parseInt(usedinQueryValue); | |
192 } catch (NumberFormatException e) { | |
193 log | |
194 .warn("Used in Query Value cannot be transformed into a Number"); | |
195 } | |
196 } | |
197 InputValue inputValue = new DefaultInputValue(inputValueNode.getAttribute("name"), | |
198 inputValueNode.getAttribute("type"), | |
199 Boolean.parseBoolean(inputValueNode. | |
200 getAttribute("multiselect")), usedinQuery); | |
201 this.inputValues.put(inputValue.getName(), inputValue); | |
202 this.inputValueNames.add(inputValue.getName()); | |
203 } | |
204 | |
205 this.queryID = Config.getStringXPath(configuration, "queryID"); | |
206 log.info("QueryID ==> " + this.queryID); | |
207 | |
208 this.dataName = Config.getStringXPath(configuration, "dataname"); | |
209 | |
210 String dataMultiSelectValue = Config.getStringXPath(configuration, | |
211 "data-multiselect"); | |
212 if (dataMultiSelectValue != null) { | |
213 this.dataMultiSelect = Boolean.parseBoolean(dataMultiSelectValue); | |
214 } | |
215 | |
216 String dataNoSelectValue =Config.getStringXPath(configuration, | |
217 "data-noselect"); | |
218 if (dataNoSelectValue != null) { | |
219 this. dataNoSelect = Boolean.parseBoolean(dataNoSelectValue); | |
220 } | |
221 | |
222 this.preSettingsName = Config.getStringXPath(configuration, "presettings-name"); | |
223 | |
224 } | |
225 | |
226 | |
227 public State getParent() { | |
228 return this.parent; | |
229 } | |
230 | |
231 | |
232 public void setParent(State state) { | |
233 this.parent = state; | |
234 } | |
235 | |
236 | |
237 public Document feed( | |
238 CallContext context, | |
239 Collection<InputData> inputData, | |
240 String uuid) | |
241 throws StateException | |
242 { | |
243 RessourceFactory resFactory = RessourceFactory.getInstance(); | |
244 Locale[] serverLocales = resFactory.getLocales(); | |
245 Locale locale = context.getMeta().getPreferredLocale( | |
246 serverLocales); | |
247 | |
248 if (inputData != null) { | |
249 Iterator<InputData> it = inputData.iterator(); | |
250 InputValidator iv = new InputValidator(); | |
251 while (it.hasNext()) { | |
252 InputData tmpItem = it.next(); | |
253 InputValue inputValue = this.inputValues.get(tmpItem.getName()); | |
254 if (inputValue != null) { | |
255 if (this.inputData == null) { | |
256 this.inputData = new TreeMap<String, InputData>(); | |
257 } | |
258 | |
259 boolean valid = InputValidator.isInputValid(tmpItem.getValue(), | |
260 inputValue.getType()); | |
261 if (valid) { | |
262 | |
263 if (tmpItem.getName().equals(this.dataName)){ | |
264 String[] desc = getDescriptionForInputData( | |
265 tmpItem, context, uuid); | |
266 tmpItem.setDescription(desc); | |
267 } | |
268 this.inputData.put(tmpItem.getName(), tmpItem); | |
269 } else { | |
270 String msg = resFactory.getRessource( | |
271 locale, | |
272 EXCEPTION_INVALID_INPUT, | |
273 EXCEPTION_INVALID_INPUT); | |
274 log.warn(msg); | |
275 return feedFailure(msg); | |
276 } | |
277 | |
278 } else { | |
279 String msg = resFactory.getRessource( | |
280 locale, | |
281 EXCEPTION_INVALID_INPUT, | |
282 EXCEPTION_INVALID_INPUT); | |
283 log.warn(msg); | |
284 return feedFailure(msg); | |
285 | |
286 } | |
287 } | |
288 | |
289 return feedSuccess(); | |
290 } else { | |
291 String msg = resFactory.getRessource( | |
292 locale, | |
293 EXCEPTION_NO_INPUT, | |
294 EXCEPTION_NO_INPUT); | |
295 log.warn(msg); | |
296 return feedFailure(msg); | |
297 } | |
298 } | |
299 | |
300 | |
301 protected Document feedSuccess() { | |
302 return ArtifactXMLUtilities.createSuccessReport( | |
303 "Initialize success", XMLUtils.newDocument()); | |
304 } | |
305 | |
306 | |
307 protected Document feedFailure(String msg) { | |
308 return ArtifactXMLUtilities.createInputExceptionReport( | |
309 msg, XMLUtils.newDocument()); | |
310 } | |
311 | |
312 | |
313 protected String[] getDescriptionForInputData( | |
314 InputData data, CallContext context, String uuid) | |
315 { | |
316 // there is only one element in the list, so take the first | |
317 Object obj = getDescibeData(uuid).get(0); | |
318 List descs = new ArrayList(); | |
319 | |
320 if (obj instanceof NamedArrayList) { | |
321 NamedArrayList list = (NamedArrayList) obj; | |
322 List selected = Arrays.asList(data.splitValue()); | |
323 int size = list.size(); | |
324 | |
325 for (int i = 0; i < size; i++) { | |
326 KeyValueDescibeData kv = (KeyValueDescibeData) list.get(i); | |
327 | |
328 // values are concatinated in InputData, so one InputData object can | |
329 // contain many input | |
330 String key = kv.getKey(); | |
331 int idx = selected.indexOf(key); | |
332 if (idx >= 0) { | |
333 descs.add(kv.getValue()); | |
334 | |
335 // XXX Workarround: I just wanted to remove the element at | |
336 // 'idx' from selected, but for any reason this is not | |
337 // possible (throws an exception) (iw) | |
338 List tmp = new ArrayList(); | |
339 for (int j = 0; j < selected.size(); j++) { | |
340 if (j != idx) | |
341 tmp.add(selected.get(j)); | |
342 } | |
343 | |
344 selected = tmp; | |
345 } | |
346 } | |
347 } | |
348 | |
349 return (String[]) descs.toArray(new String[descs.size()]); | |
350 } | |
351 | |
352 | |
353 public void putInputData(Collection<InputData> inputData, String uuid) | |
354 throws StateException { | |
355 if (inputData != null) { | |
356 Iterator<InputData> it = inputData.iterator(); | |
357 InputValidator iv = new InputValidator(); | |
358 while (it.hasNext()) { | |
359 InputData tmpItem = it.next(); | |
360 InputValue inputValue = this.inputValues.get(tmpItem.getName()); | |
361 if (inputValue != null) { | |
362 if (this.inputData == null) { | |
363 this.inputData = new TreeMap<String, InputData>(); | |
364 } | |
365 | |
366 boolean valid = InputValidator.isInputValid(tmpItem.getValue(), | |
367 inputValue.getType()); | |
368 if (valid) { | |
369 if (tmpItem.getName().equals(MINVALUEFIELDNAME)){ | |
370 String minValue = tmpItem.getValue(); | |
371 String maxValue = this.getInputValue4ID(inputData, MAXVALUEFIELDNAME); | |
372 valid = InputValidator.isInputValid(maxValue,inputValue.getType()); | |
373 if (!valid){ | |
374 String errMsg = "Wrong input for " + tmpItem.getValue() | |
375 + " is not an " + inputValue.getType() | |
376 + " Value."; | |
377 log.warn(errMsg); | |
378 throw new StateException(errMsg); | |
379 } | |
380 | |
381 valid = InputValidator.isInputValid(minValue, | |
382 maxValue, | |
383 inputValue.getType()); | |
384 if (!valid){ | |
385 String errMsg = "MaxValue-Input is less than MinValue-Input "; | |
386 log.warn(errMsg); | |
387 throw new StateException(errMsg); | |
388 } | |
389 }else if (tmpItem.getName().equals(MAXVALUEFIELDNAME)){ | |
390 String minValue = this.getInputValue4ID(inputData, MINVALUEFIELDNAME); | |
391 String maxValue = tmpItem.getValue(); | |
392 valid = InputValidator.isInputValid(minValue,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 } | |
410 this.inputData.put(tmpItem.getName(), tmpItem); | |
411 } else { | |
412 String errMsg = "Wrong input for " + tmpItem.getValue() | |
413 + " is not an " + inputValue.getType() | |
414 + " Value."; | |
415 log.warn(errMsg); | |
416 throw new StateException(errMsg); | |
417 } | |
418 | |
419 } else { | |
420 String errMsg = "No Inputvalue given for Inputdata " | |
421 + tmpItem.getName(); | |
422 log.warn(errMsg + "Value will be ignored"); | |
423 | |
424 } | |
425 } | |
426 } else { | |
427 log.warn("No Inputdata given"); | |
428 } | |
429 | |
430 setHash(uuid); | |
431 } | |
432 | |
433 | |
434 public void setPreSettings(Map<String, InputData> preSettings) { | |
435 this.preSettings = preSettings; | |
436 } | |
437 | |
438 | |
439 public Map<String, InputData> getPreSettings() { | |
440 return this.preSettings; | |
441 } | |
442 | |
443 | |
444 protected String getInputValue4ID(Collection<InputData> inputData, String inputName){ | |
445 Iterator<InputData> it = inputData.iterator(); | |
446 while (it.hasNext()) { | |
447 InputData tmpItem = it.next(); | |
448 if (tmpItem.getName().equals(inputName)){ | |
449 return tmpItem.getValue(); | |
450 } | |
451 } | |
452 return null; | |
453 } | |
454 | |
455 | |
456 public void advance(String uuid, CallContext context) | |
457 throws StateException | |
458 { | |
459 } | |
460 | |
461 | |
462 public void initialize(String uuid, CallContext context) | |
463 throws StateException | |
464 { | |
465 } | |
466 | |
467 | |
468 protected String[] generateFilterValuesFromInputData() { | |
469 List<String> list = new ArrayList<String>(); | |
470 Iterator<String> it = this.inputValueNames.iterator(); | |
471 while (it.hasNext()) { | |
472 String value = it.next(); | |
473 InputData data = this.inputData.get(value); | |
474 if (data != null | |
475 && this.inputValues.containsKey(data.getName())) { | |
476 | |
477 int size = this.inputValues.get(data.getName()) | |
478 .usedInQueries(); | |
479 String type = this.inputValues.get(data.getName()) | |
480 .getType(); | |
481 String requestValue = data.getValue(); | |
482 if (type.equalsIgnoreCase("string")) { | |
483 requestValue = this | |
484 .prepareInputData4DBQuery(requestValue); | |
485 } else if (type.equalsIgnoreCase("date")) { | |
486 requestValue = this | |
487 .prepareInputData4DateDBQuery(requestValue); | |
488 } else if (type.equalsIgnoreCase("coordinate") || (type.equalsIgnoreCase("geometry") && requestValue.toLowerCase().startsWith("point"))){ | |
489 requestValue = this | |
490 .prepareInputData4RegionDBQuery(requestValue); | |
491 } | |
492 for (int j = 0; j < size; j++) { | |
493 list.add(requestValue); | |
494 } | |
495 } | |
496 } | |
497 String[] filterValues = list.toArray(new String[list.size()]); | |
498 return filterValues; | |
499 } | |
500 | |
501 | |
502 protected String prepareInputData4RegionDBQuery(String value){ | |
503 return value; | |
504 } | |
505 | |
506 private String prepareInputData4DateDBQuery(String value) { | |
507 if (value != null) { | |
508 String[] values = value.split(","); | |
509 String newValue = ""; | |
510 for (int i = 0; i < values.length; i++) { | |
511 if (newValue.length() > 0) { | |
512 newValue = newValue + " , "; | |
513 } | |
514 // TODO JUST HACK FIND A BETTER RESOLUTION | |
515 newValue = newValue + "to_date('" + values[i].trim() | |
516 + "', 'YYYY.MM.DD HH24:MI:SS')"; | |
517 } | |
518 return newValue; | |
519 } | |
520 | |
521 return value; | |
522 } | |
523 | |
524 private String prepareInputData4DBQuery(String value) { | |
525 if (value != null) { | |
526 String[] values = value.split(","); | |
527 String newValue = ""; | |
528 for (int i = 0; i < values.length; i++) { | |
529 if (newValue.length() > 0) { | |
530 newValue = newValue + " , "; | |
531 } | |
532 newValue = newValue + "'" + values[i].trim() + "'"; | |
533 } | |
534 return newValue; | |
535 } | |
536 | |
537 return value; | |
538 | |
539 } | |
540 | |
541 | |
542 protected List<Object> purifyResult(Collection<Result> result, String uuid) { | |
543 List<Object> describeData = new ArrayList<Object>(); | |
544 | |
545 NamedCollection<KeyValueDescibeData> keyValueDescibeData = | |
546 extractKVP(result, "KEY", "VALUE"); | |
547 | |
548 describeData.add(keyValueDescibeData); | |
549 | |
550 return describeData; | |
551 } | |
552 | |
553 | |
554 protected NamedCollection<KeyValueDescibeData> extractKVP(Collection<Result> result, | |
555 String keyid, | |
556 String valueid) { | |
557 Iterator<Result> rit = result.iterator(); | |
558 int dataSize = (this.dataNoSelect ? result.size()+1 : result.size()); | |
559 | |
560 NamedCollection<KeyValueDescibeData> keyValueDescibeData = new NamedArrayList<KeyValueDescibeData>( | |
561 this.dataName, dataSize); | |
562 keyValueDescibeData.setMultiSelect(this.dataMultiSelect); | |
563 | |
564 if (this.dataNoSelect){ | |
565 keyValueDescibeData.add(new DefaultKeyValueDescribeData( | |
566 NODATASELECTIONKEY, | |
567 "No Selection", | |
568 getID() | |
569 )); | |
570 } | |
571 | |
572 boolean initialized = false; | |
573 int keyPos = 0; | |
574 int valuePos = 1; | |
575 String previousKey = null; | |
576 InputData preSettingsData = | |
577 (this.preSettings != null && this.preSettingsName != null) | |
578 ? this.preSettings.get(this.preSettingsName) | |
579 : null; | |
580 boolean filterWithPresettings = preSettingsData != null; | |
581 | |
582 List<String> preSettingValues = null; | |
583 if(filterWithPresettings){ | |
584 preSettingValues = Arrays.asList(preSettingsData.splitValue()); | |
585 } | |
586 while (rit.hasNext()) { | |
587 Result resultValue = rit.next(); | |
588 if (!initialized){ | |
589 keyPos = resultValue.getResultDescriptor().getColumnIndex(keyid); | |
590 valuePos = resultValue.getResultDescriptor().getColumnIndex(valueid); | |
591 if (valuePos < 0){ | |
592 valuePos = 1; | |
593 } | |
594 initialized = true; | |
595 } | |
596 String tmpKey = resultValue.getString(keyPos); | |
597 | |
598 // TODO: FIXME: We have to do that because the arcsde does not | |
599 // support a distinct Query on Layers. | |
600 if (previousKey == null || !tmpKey.equals(previousKey)){ | |
601 previousKey = tmpKey; | |
602 if (!filterWithPresettings || preSettingValues.contains(tmpKey)){ | |
603 keyValueDescibeData.add( | |
604 new DefaultKeyValueDescribeData( | |
605 tmpKey, | |
606 resultValue.getString(valuePos), | |
607 getID()) | |
608 ); | |
609 } | |
610 } | |
611 } | |
612 return keyValueDescibeData; | |
613 } | |
614 | |
615 | |
616 public static boolean inBlackList(String key) { | |
617 int length = BLACKLIST.length; | |
618 for (int i = 0; i < length; i++) { | |
619 if (BLACKLIST[i].equals(key)) { | |
620 return true; | |
621 } | |
622 } | |
623 | |
624 return false; | |
625 } | |
626 | |
627 | |
628 public void describe( | |
629 Document document, | |
630 Node rootNode, | |
631 CallContext context, | |
632 String uuid) | |
633 { | |
634 XMLUtils.ElementCreator xCreator = new XMLUtils.ElementCreator( | |
635 document, | |
636 XMLUtils.XFORM_URL, | |
637 XMLUtils.XFORM_PREFIX | |
638 ); | |
639 | |
640 XMLUtils.ElementCreator creator = new XMLUtils.ElementCreator( | |
641 document, | |
642 ArtifactNamespaceContext.NAMESPACE_URI, | |
643 ArtifactNamespaceContext.NAMESPACE_PREFIX | |
644 ); | |
645 | |
646 // append dynamic node | |
647 Node dynamic = (Node) XMLUtils.xpath( | |
648 rootNode, | |
649 XPATH_DYNAMIC_UI, | |
650 XPathConstants.NODE, | |
651 ArtifactNamespaceContext.INSTANCE | |
652 ); | |
653 | |
654 describeDynamic( | |
655 creator, xCreator, document, dynamic, context, uuid); | |
656 | |
657 // append static nodes | |
658 Node staticNode = (Node) XMLUtils.xpath( | |
659 rootNode, | |
660 XPATH_STATIC_UI, | |
661 XPathConstants.NODE, | |
662 ArtifactNamespaceContext.INSTANCE | |
663 ); | |
664 | |
665 State parent = getParent(); | |
666 if (parent != null && parent instanceof StateBase) { | |
667 ((StateBase) parent).describeStatic( | |
668 creator,xCreator, document, staticNode, context,uuid); | |
669 } | |
670 } | |
671 | |
672 | |
673 protected void describeDynamic( | |
674 XMLUtils.ElementCreator artCreator, | |
675 XMLUtils.ElementCreator creator, | |
676 Document document, | |
677 Node dynamic, | |
678 CallContext context, | |
679 String uuid) | |
680 { | |
681 CallMeta callMeta = context.getMeta(); | |
682 | |
683 if (dataName == null) | |
684 return; | |
685 | |
686 List<Object> descibeData = getDescibeData(uuid); | |
687 if (descibeData != null) { | |
688 Iterator<Object> it = descibeData.iterator(); | |
689 | |
690 while (it.hasNext()) { | |
691 Object o = it.next(); | |
692 if ((!it.hasNext() && dataName != null)) { | |
693 appendToDynamicNode( | |
694 artCreator, creator, document, dynamic, callMeta, o); | |
695 } | |
696 } | |
697 } | |
698 } | |
699 | |
700 | |
701 protected void describeStatic( | |
702 XMLUtils.ElementCreator artCreator, | |
703 XMLUtils.ElementCreator creator, | |
704 Document document, | |
705 Node staticNode, | |
706 CallContext context, | |
707 String uuid) | |
708 { | |
709 State parent = getParent(); | |
710 if (parent instanceof StateBase) { | |
711 ((StateBase) parent).describeStatic( | |
712 artCreator, creator, document, staticNode, context, uuid); | |
713 } | |
714 | |
715 CallMeta callMeta = context.getMeta(); | |
716 appendToStaticNode(artCreator, creator, document, staticNode, callMeta); | |
717 } | |
718 | |
719 | |
720 protected void appendToStaticNode( | |
721 XMLUtils.ElementCreator artCreator, | |
722 XMLUtils.ElementCreator creator, | |
723 Document document, | |
724 Node staticNode, | |
725 CallMeta callMeta | |
726 ) { | |
727 InputData data = dataName!= null ? inputData.get(dataName) : null; | |
728 | |
729 if (data == null) { | |
730 return; | |
731 } | |
732 | |
733 Element selectNode = creator.create("select1"); | |
734 creator.addAttr(selectNode, "ref", dataName); | |
735 | |
736 Element lableNode = creator.create("label"); | |
737 lableNode.setTextContent(RessourceFactory.getInstance() | |
738 .getRessource(callMeta.getLanguages(), dataName, dataName)); | |
739 Element choiceNode = creator.create("choices"); | |
740 | |
741 artCreator.addAttr( | |
742 selectNode, "state", getID(), true | |
743 ); | |
744 | |
745 String[] descriptions = data.getDescription(); | |
746 int size = descriptions.length; | |
747 | |
748 for (int i = 0; i < size; i++) { | |
749 Element itemNode = creator.create("item"); | |
750 String value = data.getValue(); | |
751 String desc = descriptions[i]; | |
752 desc = desc == null ? value : desc; | |
753 | |
754 creator.addAttr(itemNode, "selected", "true"); | |
755 | |
756 Element choiceLableNode = creator.create("label"); | |
757 choiceLableNode.setTextContent(desc); | |
758 itemNode.appendChild(choiceLableNode); | |
759 | |
760 Element choiceValueNode = creator.create("value"); | |
761 choiceValueNode.setTextContent(value); | |
762 itemNode.appendChild(choiceValueNode); | |
763 choiceNode.appendChild(itemNode); | |
764 } | |
765 | |
766 selectNode.appendChild(lableNode); | |
767 selectNode.appendChild(choiceNode); | |
768 | |
769 staticNode.appendChild(selectNode); | |
770 } | |
771 | |
772 | |
773 protected void appendToDynamicNode( | |
774 XMLUtils.ElementCreator artCreator, | |
775 XMLUtils.ElementCreator creator, | |
776 Document document, | |
777 Node dynamicNode, | |
778 CallMeta callMeta, | |
779 Object o | |
780 ) { | |
781 if (o instanceof Collection<?>) { | |
782 String name = null; | |
783 boolean multiselect = false; | |
784 if (o instanceof NamedCollection<?>) { | |
785 NamedCollection<?> nc = ((NamedCollection<?>) o); | |
786 name = nc.getName(); | |
787 multiselect = nc.isMultiSelect(); | |
788 } else { | |
789 Object[] names = this.inputValueNames.toArray(); | |
790 name = names[names.length - 1].toString(); | |
791 } | |
792 | |
793 Element selectNode = creator.create(multiselect?"select":"select1"); | |
794 creator.addAttr(selectNode, "ref", name); | |
795 | |
796 Element lableNode = creator.create("label"); | |
797 lableNode.setTextContent(RessourceFactory.getInstance() | |
798 .getRessource(callMeta.getLanguages(), name, name)); | |
799 Element choiceNode = creator.create("choices"); | |
800 | |
801 Collection<KeyValueDescibeData> values = (Collection<KeyValueDescibeData>) o; | |
802 Iterator<KeyValueDescibeData> resultIt = values.iterator(); | |
803 while (resultIt.hasNext()) { | |
804 KeyValueDescibeData result = resultIt.next(); | |
805 Element itemNode = creator.create("item"); | |
806 | |
807 if (result.isSelected()) { | |
808 itemNode.setAttribute("selected", "true"); | |
809 } | |
810 | |
811 Element choiceLableNode = creator.create("label"); | |
812 choiceLableNode.setTextContent(result.getValue()); | |
813 itemNode.appendChild(choiceLableNode); | |
814 | |
815 Element choicValueNode = creator.create("value"); | |
816 choicValueNode.setTextContent("" + result.getKey()); | |
817 itemNode.appendChild(choicValueNode); | |
818 choiceNode.appendChild(itemNode); | |
819 } | |
820 selectNode.appendChild(lableNode); | |
821 selectNode.appendChild(choiceNode); | |
822 | |
823 dynamicNode.appendChild(selectNode); | |
824 } | |
825 else if (o instanceof MinMaxDescribeData) { | |
826 appendMinMaxDescribeData( | |
827 artCreator, | |
828 creator, | |
829 document, | |
830 dynamicNode, | |
831 callMeta, | |
832 o); | |
833 } | |
834 else if (o instanceof SingleValueDescribeData) { | |
835 appendSingleValueDescribeData( | |
836 artCreator, | |
837 creator, | |
838 document, | |
839 dynamicNode, | |
840 callMeta, | |
841 o); | |
842 } | |
843 } | |
844 | |
845 | |
846 protected void appendMinMaxDescribeData( | |
847 XMLUtils.ElementCreator artCreator, | |
848 XMLUtils.ElementCreator creator, | |
849 Document document, | |
850 Node node, | |
851 CallMeta callMeta, | |
852 Object o | |
853 ) { | |
854 MinMaxDescribeData minMaxDescibeData = (MinMaxDescribeData) o; | |
855 Object min = minMaxDescibeData.getMinValue(); | |
856 Object max = minMaxDescibeData.getMaxValue(); | |
857 if (min instanceof GregorianCalendar) { | |
858 Date d = ((GregorianCalendar) min).getTime(); | |
859 min = DateUtils.getPatternedDateAmer(d); | |
860 } | |
861 | |
862 if (max instanceof GregorianCalendar) { | |
863 Date d = ((GregorianCalendar) max).getTime(); | |
864 max = DateUtils.getPatternedDateAmer(d); | |
865 } | |
866 | |
867 Element groupNode = creator.create("group"); | |
868 artCreator.addAttr(groupNode, "state", minMaxDescibeData.getState(), true); | |
869 | |
870 creator.addAttr(groupNode, "ref", minMaxDescibeData.getName()); | |
871 Element groupNodeLableNode = creator.create("label"); | |
872 groupNodeLableNode.setTextContent(RessourceFactory | |
873 .getInstance().getRessource( | |
874 callMeta.getLanguages(), | |
875 minMaxDescibeData.getName(), | |
876 minMaxDescibeData.getName())); | |
877 groupNode.appendChild(groupNodeLableNode); | |
878 | |
879 Element inputMinNode = creator.create("input"); | |
880 creator.addAttr(inputMinNode, "ref", MINVALUEFIELDNAME); | |
881 Element inputMinLableNode = creator.create("label"); | |
882 inputMinLableNode.setTextContent(RessourceFactory | |
883 .getInstance().getRessource( | |
884 callMeta.getLanguages(), MINVALUEFIELDNAME, | |
885 MINVALUEFIELDNAME)); | |
886 inputMinNode.appendChild(inputMinLableNode); | |
887 | |
888 Element inputMinValueNode = creator.create("value"); | |
889 inputMinValueNode.setTextContent(min.toString()); | |
890 inputMinNode.appendChild(inputMinValueNode); | |
891 | |
892 Element inputMaxNode = creator.create("input"); | |
893 creator.addAttr(inputMaxNode, "ref", MAXVALUEFIELDNAME); | |
894 Element inputMaxLableNode = creator.create("label"); | |
895 inputMaxLableNode.setTextContent(RessourceFactory | |
896 .getInstance().getRessource( | |
897 callMeta.getLanguages(), MAXVALUEFIELDNAME, | |
898 MAXVALUEFIELDNAME)); | |
899 inputMaxNode.appendChild(inputMaxLableNode); | |
900 | |
901 Element inputMaxValueNode = creator.create("value"); | |
902 inputMaxValueNode.setTextContent(max.toString()); | |
903 inputMaxNode.appendChild(inputMaxValueNode); | |
904 | |
905 groupNode.appendChild(inputMinNode); | |
906 groupNode.appendChild(inputMaxNode); | |
907 | |
908 node.appendChild(groupNode); | |
909 } | |
910 | |
911 | |
912 protected void appendSingleValueDescribeData( | |
913 XMLUtils.ElementCreator artCreator, | |
914 XMLUtils.ElementCreator creator, | |
915 Document document, | |
916 Node node, | |
917 CallMeta callMeta, | |
918 Object o | |
919 ) { | |
920 SingleValueDescribeData svdb = (SingleValueDescribeData) o; | |
921 | |
922 Element groupNode = creator.create("group"); | |
923 artCreator.addAttr(groupNode, "state", svdb.getState(), true); | |
924 creator.addAttr(groupNode, "ref", svdb.getName()); | |
925 | |
926 Element groupNodeLableNode = creator.create("label"); | |
927 groupNodeLableNode.setTextContent(RessourceFactory | |
928 .getInstance().getRessource( | |
929 callMeta.getLanguages(), | |
930 svdb.getName(), | |
931 svdb.getName())); | |
932 groupNode.appendChild(groupNodeLableNode); | |
933 | |
934 Element inputNode = creator.create("input"); | |
935 creator.addAttr(inputNode, "ref", svdb.getName()); | |
936 | |
937 Element inputLableNode = creator.create("label"); | |
938 inputLableNode.setTextContent(""); | |
939 inputNode.appendChild(inputLableNode); | |
940 | |
941 Element inputValueNode = creator.create("value"); | |
942 inputValueNode.setTextContent(svdb.getValue()); | |
943 inputNode.appendChild(inputValueNode); | |
944 | |
945 groupNode.appendChild(inputNode); | |
946 | |
947 node.appendChild(groupNode); | |
948 } | |
949 | |
950 | |
951 protected void setHash(String uuid) { | |
952 String newHash = uuid + HASH_ID_SEPARATOR + id + HASH_ID_SEPARATOR; | |
953 Set keys = inputData.keySet(); | |
954 | |
955 int nhash = 0; | |
956 int shift = 0; | |
957 | |
958 for (Object o: keys) { | |
959 nhash ^= inputData.get(o).hashCode() << shift; | |
960 shift += 2; | |
961 } | |
962 | |
963 log.info("### OLD HASH: " + hash); | |
964 log.info("### NEW HASH: " + (newHash + nhash)); | |
965 | |
966 this.hash = newHash + nhash; | |
967 } | |
968 | |
969 | |
970 protected String getHash() { | |
971 return this.hash; | |
972 } | |
973 | |
974 | |
975 public List<Object> getDescibeData(String uuid) { | |
976 CacheFactory factory = CacheFactory.getInstance(); | |
977 if (factory.isInitialized()) { | |
978 // we use a cache | |
979 Cache cache = factory.getCache(); | |
980 String key = getHash(); | |
981 | |
982 log.debug("Using cache - key: " + key); | |
983 | |
984 net.sf.ehcache.Element value = cache.get(key); | |
985 if (value != null) { | |
986 // element already in cache, so return it. | |
987 log.debug("Found element in cache."); | |
988 return (List<Object>) (value.getObjectValue()); | |
989 } | |
990 else { | |
991 // element is not in cache yet, so we need to fetch data from | |
992 // database and put it into cache right now | |
993 log.debug("Element not in cache, we need to ask the database"); | |
994 try { | |
995 String[] filterValues = generateFilterValuesFromInputData(); | |
996 List<Object> data = queryDatabase(filterValues, uuid); | |
997 | |
998 cache.put(new net.sf.ehcache.Element(key, data)); | |
999 | |
1000 return data; | |
1001 } | |
1002 catch (QueryException qe) { | |
1003 log.error(qe, qe); | |
1004 } | |
1005 } | |
1006 } | |
1007 else { | |
1008 // we don't use a cache, so we have to query the database every | |
1009 // single time | |
1010 log.debug("Not using cache."); | |
1011 String[] filterValues = generateFilterValuesFromInputData(); | |
1012 Collection<Result> result = null; | |
1013 try { | |
1014 return queryDatabase(filterValues, uuid); | |
1015 } | |
1016 catch (RuntimeException e) { | |
1017 log.error(e, e); | |
1018 } | |
1019 catch (QueryException e) { | |
1020 log.error(e, e); | |
1021 } | |
1022 } | |
1023 | |
1024 return null; | |
1025 } | |
1026 | |
1027 | |
1028 protected List<Object> queryDatabase(String[] filterValues, String uuid) | |
1029 throws QueryException { | |
1030 Collection<Result> result = null; | |
1031 | |
1032 if (queryID != null) { | |
1033 QueryExecutor queryExecutor = | |
1034 QueryExecutorFactory.getInstance().getQueryExecutor(); | |
1035 | |
1036 result = queryExecutor.executeQuery(queryID, filterValues); | |
1037 } | |
1038 return purifyResult(result, uuid); | |
1039 } | |
1040 | |
1041 | |
1042 | |
1043 public Map<String, InputData> inputData() { | |
1044 return inputData; | |
1045 } | |
1046 | |
1047 | |
1048 public Collection<InputData> getInputData() throws StateException { | |
1049 return this.inputData != null ? this.inputData.values() : null; | |
1050 } | |
1051 | |
1052 | |
1053 public InputData getInputDataByName(String name) { | |
1054 State state = this; | |
1055 | |
1056 while (state != null) { | |
1057 InputData data = state.inputData().get(name); | |
1058 if (data != null) { | |
1059 return data; | |
1060 } | |
1061 | |
1062 state = state.getParent(); | |
1063 } | |
1064 | |
1065 return null; | |
1066 } | |
1067 | |
1068 | |
1069 public void endOfLife(Object globalContext) { | |
1070 log.debug("end of life of the current state."); | |
1071 | |
1072 CacheFactory factory = CacheFactory.getInstance(); | |
1073 if (factory.isInitialized()) { | |
1074 Cache cache = factory.getCache(); | |
1075 String key = getHash(); | |
1076 | |
1077 if (key != null && cache.remove(key)) { | |
1078 log.info("Removed element from cache - key: " + key); | |
1079 } | |
1080 } | |
1081 } | |
1082 | |
1083 | |
1084 public void cleanup(Object context) { | |
1085 } | |
1086 } | |
1087 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |