Mercurial > dive4elements > river
comparison artifacts/src/main/java/org/dive4elements/river/artifacts/context/RiverContextFactory.java @ 5866:9a6741ccf6d4
FLYS artifacts: Renamed FLYSContext(Factory) to RiverContext(Factory).
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Sun, 28 Apr 2013 15:14:30 +0200 |
parents | artifacts/src/main/java/org/dive4elements/river/artifacts/context/FLYSContextFactory.java@4897a58c8746 |
children | 59ff03ff48f1 |
comparison
equal
deleted
inserted
replaced
5865:73da40528cf2 | 5866:9a6741ccf6d4 |
---|---|
1 /* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde | |
2 * Software engineering by Intevation GmbH | |
3 * | |
4 * This file is Free Software under the GNU AGPL (>=v3) | |
5 * and comes with ABSOLUTELY NO WARRANTY! Check out the | |
6 * documentation coming with Dive4Elements River for details. | |
7 */ | |
8 | |
9 package org.dive4elements.river.artifacts.context; | |
10 | |
11 import org.dive4elements.artifactdatabase.state.State; | |
12 import org.dive4elements.artifactdatabase.state.StateEngine; | |
13 import org.dive4elements.artifactdatabase.transition.Transition; | |
14 import org.dive4elements.artifactdatabase.transition.TransitionEngine; | |
15 import org.dive4elements.artifacts.ArtifactContextFactory; | |
16 import org.dive4elements.artifacts.GlobalContext; | |
17 import org.dive4elements.artifacts.common.utils.Config; | |
18 import org.dive4elements.artifacts.common.utils.XMLUtils; | |
19 import org.dive4elements.river.artifacts.model.Module; | |
20 import org.dive4elements.river.artifacts.model.ZoomScale; | |
21 import org.dive4elements.river.artifacts.states.StateFactory; | |
22 import org.dive4elements.river.artifacts.transitions.TransitionFactory; | |
23 import org.dive4elements.river.themes.Theme; | |
24 import org.dive4elements.river.themes.ThemeFactory; | |
25 import org.dive4elements.river.themes.ThemeGroup; | |
26 import org.dive4elements.river.themes.ThemeMapping; | |
27 | |
28 import java.io.File; | |
29 import java.util.ArrayList; | |
30 import java.util.HashMap; | |
31 import java.util.List; | |
32 import java.util.Map; | |
33 | |
34 import javax.xml.xpath.XPathConstants; | |
35 | |
36 import org.apache.log4j.Logger; | |
37 import org.w3c.dom.Document; | |
38 import org.w3c.dom.Element; | |
39 import org.w3c.dom.Node; | |
40 import org.w3c.dom.NodeList; | |
41 | |
42 | |
43 /** | |
44 * The ArtifactContextFactory is used to initialize basic components and put | |
45 * them into the global context of the application. | |
46 * | |
47 * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> | |
48 */ | |
49 public class RiverContextFactory implements ArtifactContextFactory { | |
50 | |
51 /** The logger that is used in this class. */ | |
52 private static Logger logger = Logger.getLogger(RiverContextFactory.class); | |
53 | |
54 /** The XPath to the artifacts configured in the configuration. */ | |
55 public static final String XPATH_ARTIFACTS = | |
56 "/artifact-database/artifacts/artifact"; | |
57 | |
58 /** The XPath to the name of the artifact. */ | |
59 public static final String XPATH_ARTIFACT_NAME = "/artifact/@name"; | |
60 | |
61 /** The XPath to the xlink ref in an artifact configuration. */ | |
62 public static final String XPATH_XLINK = "xlink:href"; | |
63 | |
64 /** The XPath to the transitions configured in the artifact config. */ | |
65 public static final String XPATH_TRANSITIONS = | |
66 "/artifact/states/transition"; | |
67 | |
68 /** The XPath to the states configured in the artifact config. */ | |
69 public static final String XPATH_STATES = | |
70 "/artifact/states/state"; | |
71 | |
72 public static final String XPATH_OUTPUT_GENERATORS = | |
73 "/artifact-database/output-generators/output-generator"; | |
74 | |
75 public static final String XPATH_THEME_CONFIG = | |
76 "/artifact-database/flys/themes/configuration/text()"; | |
77 | |
78 public static final String XPATH_THEMES = | |
79 "theme"; | |
80 | |
81 public static final String XPATH_THEME_GROUPS = | |
82 "/themes/themegroup"; | |
83 | |
84 public static final String XPATH_THEME_MAPPINGS = | |
85 "/themes/mappings/mapping"; | |
86 | |
87 public static final String XPATH_RIVER_WMS = | |
88 "/artifact-database/floodmap/river"; | |
89 | |
90 public static final String XPATH_MODULES = "/artifact-database/modules/module"; | |
91 | |
92 private static final String XPATH_ZOOM_SCALES = "/artifact-database/options/zoom-scales/zoom-scale"; | |
93 | |
94 private static final String XPATH_DGM_PATH = "/artifact-database/options/dgm-path/text()"; | |
95 | |
96 | |
97 /** | |
98 * Creates a new FLYSArtifactContext object and initialize all | |
99 * components required by the application. | |
100 * | |
101 * @param config The artifact server configuration. | |
102 * @return a FLYSArtifactContext. | |
103 */ | |
104 @Override | |
105 public GlobalContext createArtifactContext(Document config) { | |
106 RiverContext context = new RiverContext(config); | |
107 | |
108 configureTransitions(config, context); | |
109 configureStates(config, context); | |
110 configureOutGenerators(config, context); | |
111 configureThemes(config, context); | |
112 configureThemesMappings(config, context); | |
113 configureFloodmapWMS(config, context); | |
114 configureModules(config, context); | |
115 configureZoomScales(config, context); | |
116 configureDGMPath(config, context); | |
117 | |
118 return context; | |
119 } | |
120 | |
121 | |
122 private void configureDGMPath(Document config, RiverContext context) { | |
123 String dgmPath = (String) XMLUtils.xpath( | |
124 config, | |
125 XPATH_DGM_PATH, | |
126 XPathConstants.STRING); | |
127 | |
128 context.put("dgm-path", dgmPath); | |
129 } | |
130 | |
131 | |
132 protected void configureZoomScales(Document config, RiverContext context) { | |
133 NodeList list = (NodeList)XMLUtils.xpath( | |
134 config, | |
135 XPATH_ZOOM_SCALES, | |
136 XPathConstants.NODESET); | |
137 ZoomScale scale = new ZoomScale(); | |
138 for (int i = 0; i < list.getLength(); i++) { | |
139 Element element = (Element)list.item(i); | |
140 String river = "default"; | |
141 double range = 0d; | |
142 double radius = 10d; | |
143 if (element.hasAttribute("river")) { | |
144 river = element.getAttribute("river"); | |
145 } | |
146 if (!element.hasAttribute("range")) { | |
147 continue; | |
148 } | |
149 else { | |
150 String r = element.getAttribute("range"); | |
151 try { | |
152 range = Double.parseDouble(r); | |
153 } | |
154 catch (NumberFormatException nfe) { | |
155 continue; | |
156 } | |
157 } | |
158 if (!element.hasAttribute("radius")) { | |
159 continue; | |
160 } | |
161 else { | |
162 String r = element.getAttribute("radius"); | |
163 try { | |
164 radius = Double.parseDouble(r); | |
165 } | |
166 catch (NumberFormatException nfe) { | |
167 continue; | |
168 } | |
169 } | |
170 scale.addRange(river, range, radius); | |
171 } | |
172 context.put("zoomscale", scale); | |
173 } | |
174 | |
175 | |
176 /** | |
177 * This method initializes the transition configuration. | |
178 * | |
179 * @param config the config document. | |
180 * @param context the RiverContext. | |
181 */ | |
182 protected void configureTransitions(Document config, RiverContext context) { | |
183 TransitionEngine engine = new TransitionEngine(); | |
184 | |
185 Document[] artifacts = getArtifactConfigurations(config); | |
186 logger.info("Found " + artifacts.length + " artifacts in the config."); | |
187 | |
188 for (Document doc: artifacts) { | |
189 | |
190 String artName = (String) XMLUtils.xpath( | |
191 doc, XPATH_ARTIFACT_NAME, XPathConstants.STRING); | |
192 | |
193 NodeList list = (NodeList) XMLUtils.xpath( | |
194 doc, XPATH_TRANSITIONS, XPathConstants.NODESET); | |
195 | |
196 if (list == null) { | |
197 logger.warn("The artifact " + artName + | |
198 " has no transitions configured."); | |
199 continue; | |
200 } | |
201 | |
202 int trans = list.getLength(); | |
203 | |
204 logger.info( | |
205 "Artifact '" + artName + "' has " + trans + " transitions."); | |
206 | |
207 for (int i = 0; i < trans; i++) { | |
208 Transition t = TransitionFactory.createTransition(list.item(i)); | |
209 String s = t.getFrom(); | |
210 engine.addTransition(s, t); | |
211 } | |
212 } | |
213 | |
214 context.put(RiverContext.TRANSITION_ENGINE_KEY, engine); | |
215 } | |
216 | |
217 | |
218 /** | |
219 * This method returns all artifact documents defined in | |
220 * <code>config</code>. <br>NOTE: The artifact configurations need to be | |
221 * stored in own files referenced by an xlink. | |
222 * | |
223 * @param config The global configuration. | |
224 * | |
225 * @return an array of Artifact configurations. | |
226 */ | |
227 protected Document[] getArtifactConfigurations(Document config) { | |
228 NodeList artifacts = (NodeList) XMLUtils.xpath( | |
229 config, XPATH_ARTIFACTS, XPathConstants.NODESET); | |
230 | |
231 int count = artifacts.getLength(); | |
232 | |
233 Document[] artifactDocs = new Document[count]; | |
234 | |
235 for (int i = 0; i < count; i++) { | |
236 Element tmp = (Element) artifacts.item(i); | |
237 | |
238 String xlink = tmp.getAttribute(XPATH_XLINK); | |
239 xlink = Config.replaceConfigDir(xlink); | |
240 | |
241 File artifactFile = new File(xlink); | |
242 artifactDocs[i] = XMLUtils.parseDocument(artifactFile); | |
243 } | |
244 | |
245 return artifactDocs; | |
246 } | |
247 | |
248 | |
249 /** | |
250 * This method initializes the transition configuration. | |
251 * | |
252 * @param config the config document. | |
253 * @param context the RiverContext. | |
254 */ | |
255 protected void configureStates(Document config, RiverContext context) { | |
256 StateEngine engine = new StateEngine(); | |
257 | |
258 Document[] artifacts = getArtifactConfigurations(config); | |
259 logger.info("Found " + artifacts.length + " artifacts in the config."); | |
260 | |
261 for (Document doc: artifacts) { | |
262 List<State> states = new ArrayList<State>(); | |
263 | |
264 String artName = (String) XMLUtils.xpath( | |
265 doc, XPATH_ARTIFACT_NAME, XPathConstants.STRING); | |
266 | |
267 NodeList stateList = (NodeList) XMLUtils.xpath( | |
268 doc, XPATH_STATES, XPathConstants.NODESET); | |
269 | |
270 if (stateList == null) { | |
271 logger.warn("The artifact " + artName + | |
272 " has no states configured."); | |
273 continue; | |
274 } | |
275 | |
276 int count = stateList.getLength(); | |
277 | |
278 logger.info( | |
279 "Artifact '" + artName + "' has " + count + " states."); | |
280 | |
281 for (int i = 0; i < count; i++) { | |
282 states.add(StateFactory.createState( | |
283 stateList.item(i))); | |
284 } | |
285 | |
286 engine.addStates(artName, states); | |
287 } | |
288 | |
289 context.put(RiverContext.STATE_ENGINE_KEY, engine); | |
290 } | |
291 | |
292 | |
293 /** | |
294 * This method intializes the provided output generators. | |
295 * | |
296 * @param config the config document. | |
297 * @param context the RiverContext. | |
298 */ | |
299 protected void configureOutGenerators(Document config, RiverContext context){ | |
300 Map<String, Class<?>> generators = new HashMap<String, Class<?>>(); | |
301 | |
302 NodeList outGenerators = (NodeList) XMLUtils.xpath( | |
303 config, | |
304 XPATH_OUTPUT_GENERATORS, | |
305 XPathConstants.NODESET); | |
306 | |
307 int num = outGenerators == null ? 0 : outGenerators.getLength(); | |
308 | |
309 if (num == 0) { | |
310 logger.warn("No output generators configured in this application."); | |
311 return; | |
312 } | |
313 | |
314 logger.info("Found " + num + " configured output generators."); | |
315 | |
316 int idx = 0; | |
317 | |
318 for (int i = 0; i < num; i++) { | |
319 Node item = outGenerators.item(i); | |
320 | |
321 String name = (String) XMLUtils.xpath( | |
322 item, "@name", XPathConstants.STRING); | |
323 | |
324 String clazz = (String) XMLUtils.xpath( | |
325 item, "text()", XPathConstants.STRING); | |
326 | |
327 if (name == null || clazz == null) { | |
328 continue; | |
329 } | |
330 | |
331 try { | |
332 generators.put(name, Class.forName(clazz)); | |
333 | |
334 idx++; | |
335 } | |
336 catch (ClassNotFoundException cnfe) { | |
337 logger.warn(cnfe, cnfe); | |
338 } | |
339 } | |
340 | |
341 logger.info("Successfully loaded " + idx + " output generators."); | |
342 context.put(RiverContext.OUTGENERATORS_KEY, generators); | |
343 } | |
344 | |
345 | |
346 /** | |
347 * This methods reads the configured themes and puts them into the | |
348 * RiverContext. | |
349 * | |
350 * @param config The global configuration. | |
351 * @param context The RiverContext. | |
352 */ | |
353 protected void configureThemes(Document config, RiverContext context) { | |
354 logger.debug("RiverContextFactory.configureThemes"); | |
355 | |
356 Document cfg = getThemeConfig(config); | |
357 | |
358 NodeList themeGroups = (NodeList) XMLUtils.xpath( | |
359 cfg, XPATH_THEME_GROUPS, XPathConstants.NODESET); | |
360 | |
361 int groupNum = themeGroups != null ? themeGroups.getLength() : 0; | |
362 | |
363 if (groupNum == 0) { | |
364 logger.warn("There are no theme groups configured!"); | |
365 } | |
366 | |
367 logger.info("Found " + groupNum + " theme groups in configuration"); | |
368 | |
369 List<ThemeGroup> groups = new ArrayList<ThemeGroup>(); | |
370 | |
371 for (int g = 0; g < groupNum; g++) { | |
372 Element themeGroup = (Element) themeGroups.item(g); | |
373 NodeList themes = (NodeList) XMLUtils.xpath( | |
374 themeGroup, XPATH_THEMES, XPathConstants.NODESET); | |
375 | |
376 int num = themes != null ? themes.getLength() : 0; | |
377 | |
378 if (num == 0) { | |
379 logger.warn("There are no themes configured!"); | |
380 return; | |
381 } | |
382 | |
383 logger.info("Theme group has " + num + " themes."); | |
384 | |
385 Map<String, Theme> theThemes = new HashMap<String, Theme>(); | |
386 | |
387 for (int i = 0; i < num; i++) { | |
388 Node theme = themes.item(i); | |
389 | |
390 Theme theTheme = ThemeFactory.createTheme(cfg, theme); | |
391 | |
392 if (theme != null) { | |
393 theThemes.put(theTheme.getName(), theTheme); | |
394 } | |
395 } | |
396 String gName = themeGroup.getAttribute("name"); | |
397 groups.add(new ThemeGroup(gName, theThemes)); | |
398 | |
399 logger.info( | |
400 "Initialized " + theThemes.size() + "/" + num + " themes " + | |
401 "of theme-group '" + gName + "'"); | |
402 } | |
403 context.put(RiverContext.THEMES, groups); | |
404 } | |
405 | |
406 /** | |
407 * This method is used to retrieve the theme configuration document. | |
408 * | |
409 * @param config The global configuration. | |
410 * | |
411 * @return the theme configuration. | |
412 */ | |
413 protected Document getThemeConfig(Document config) { | |
414 String themeConfig = (String) XMLUtils.xpath( | |
415 config, | |
416 XPATH_THEME_CONFIG, | |
417 XPathConstants.STRING); | |
418 | |
419 themeConfig = Config.replaceConfigDir(themeConfig); | |
420 | |
421 logger.debug("Parse theme cfg: " + themeConfig); | |
422 | |
423 return XMLUtils.parseDocument(new File(themeConfig)); | |
424 } | |
425 | |
426 | |
427 protected void configureThemesMappings(Document cfg, RiverContext context) { | |
428 logger.debug("RiverContextFactory.configureThemesMappings"); | |
429 | |
430 Document config = getThemeConfig(cfg); | |
431 | |
432 NodeList mappings = (NodeList) XMLUtils.xpath( | |
433 config, XPATH_THEME_MAPPINGS, XPathConstants.NODESET); | |
434 | |
435 int num = mappings != null ? mappings.getLength() : 0; | |
436 | |
437 if (num == 0) { | |
438 logger.warn("No theme <--> facet mappins found!"); | |
439 return; | |
440 } | |
441 | |
442 Map<String, List<ThemeMapping>> mapping = | |
443 new HashMap<String, List<ThemeMapping>>(); | |
444 | |
445 for (int i = 0; i < num; i++) { | |
446 Element node = (Element)mappings.item(i); | |
447 | |
448 String from = node.getAttribute("from"); | |
449 String to = node.getAttribute("to"); | |
450 String pattern = node.getAttribute("pattern"); | |
451 String masterAttrPattern = node.getAttribute("masterAttr"); | |
452 String outputPattern = node.getAttribute("output"); | |
453 | |
454 if (from.length() > 0 && to.length() > 0) { | |
455 List<ThemeMapping> tm = mapping.get(from); | |
456 | |
457 if (tm == null) { | |
458 tm = new ArrayList<ThemeMapping>(); | |
459 mapping.put(from, tm); | |
460 } | |
461 | |
462 tm.add(new ThemeMapping( | |
463 from, to, pattern, masterAttrPattern, outputPattern)); | |
464 } | |
465 } | |
466 | |
467 logger.debug("Found " + mapping.size() + " theme mappings."); | |
468 | |
469 context.put(RiverContext.THEME_MAPPING, mapping); | |
470 } | |
471 | |
472 | |
473 /** | |
474 * Reads configured floodmap river WMSs from floodmap.xml and | |
475 * loads them into the given RiverContext. | |
476 * @param cfg | |
477 * @param context | |
478 */ | |
479 protected void configureFloodmapWMS(Document cfg, RiverContext context) { | |
480 Map<String, String> riverWMS = new HashMap<String, String>(); | |
481 | |
482 NodeList rivers = (NodeList) XMLUtils.xpath( | |
483 cfg, XPATH_RIVER_WMS, XPathConstants.NODESET); | |
484 | |
485 int num = rivers != null ? rivers.getLength() : 0; | |
486 | |
487 for (int i = 0; i < num; i++) { | |
488 Element e = (Element) rivers.item(i); | |
489 | |
490 String river = e.getAttribute("name"); | |
491 String url = XMLUtils.xpathString(e, "river-wms/@url", null); | |
492 | |
493 if (river != null && url != null) { | |
494 riverWMS.put(river, url); | |
495 } | |
496 } | |
497 | |
498 logger.debug("Found " + riverWMS.size() + " river WMS."); | |
499 | |
500 context.put(RiverContext.RIVER_WMS, riverWMS); | |
501 } | |
502 | |
503 | |
504 /** | |
505 * This method initializes the modules configuration. | |
506 * | |
507 * @param config the config document. | |
508 * @param context the RiverContext. | |
509 */ | |
510 protected void configureModules(Document cfg, RiverContext context) { | |
511 NodeList modulenodes = (NodeList) XMLUtils.xpath( | |
512 cfg, XPATH_MODULES, XPathConstants.NODESET); | |
513 | |
514 int num = modulenodes != null ? modulenodes.getLength() : 0; | |
515 ArrayList<Module> modules = new ArrayList<Module>(num); | |
516 | |
517 for (int i = 0; i < num; i++) { | |
518 Element e = (Element) modulenodes.item(i); | |
519 String modulename = e.getAttribute("name"); | |
520 String attrselected = e.getAttribute("selected"); | |
521 boolean selected = attrselected == null ? false : | |
522 attrselected.equalsIgnoreCase("true"); | |
523 logger.debug("Loaded module " + modulename); | |
524 modules.add(new Module(modulename, selected)); | |
525 } | |
526 context.put(RiverContext.MODULES, modules); | |
527 } | |
528 } | |
529 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : |