Mercurial > dive4elements > river
diff 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 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/artifacts/context/RiverContextFactory.java Sun Apr 28 15:14:30 2013 +0200 @@ -0,0 +1,529 @@ +/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde + * Software engineering by Intevation GmbH + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ + +package org.dive4elements.river.artifacts.context; + +import org.dive4elements.artifactdatabase.state.State; +import org.dive4elements.artifactdatabase.state.StateEngine; +import org.dive4elements.artifactdatabase.transition.Transition; +import org.dive4elements.artifactdatabase.transition.TransitionEngine; +import org.dive4elements.artifacts.ArtifactContextFactory; +import org.dive4elements.artifacts.GlobalContext; +import org.dive4elements.artifacts.common.utils.Config; +import org.dive4elements.artifacts.common.utils.XMLUtils; +import org.dive4elements.river.artifacts.model.Module; +import org.dive4elements.river.artifacts.model.ZoomScale; +import org.dive4elements.river.artifacts.states.StateFactory; +import org.dive4elements.river.artifacts.transitions.TransitionFactory; +import org.dive4elements.river.themes.Theme; +import org.dive4elements.river.themes.ThemeFactory; +import org.dive4elements.river.themes.ThemeGroup; +import org.dive4elements.river.themes.ThemeMapping; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.xml.xpath.XPathConstants; + +import org.apache.log4j.Logger; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + + +/** + * The ArtifactContextFactory is used to initialize basic components and put + * them into the global context of the application. + * + * @author <a href="mailto:ingo.weinzierl@intevation.de">Ingo Weinzierl</a> + */ +public class RiverContextFactory implements ArtifactContextFactory { + + /** The logger that is used in this class. */ + private static Logger logger = Logger.getLogger(RiverContextFactory.class); + + /** The XPath to the artifacts configured in the configuration. */ + public static final String XPATH_ARTIFACTS = + "/artifact-database/artifacts/artifact"; + + /** The XPath to the name of the artifact. */ + public static final String XPATH_ARTIFACT_NAME = "/artifact/@name"; + + /** The XPath to the xlink ref in an artifact configuration. */ + public static final String XPATH_XLINK = "xlink:href"; + + /** The XPath to the transitions configured in the artifact config. */ + public static final String XPATH_TRANSITIONS = + "/artifact/states/transition"; + + /** The XPath to the states configured in the artifact config. */ + public static final String XPATH_STATES = + "/artifact/states/state"; + + public static final String XPATH_OUTPUT_GENERATORS = + "/artifact-database/output-generators/output-generator"; + + public static final String XPATH_THEME_CONFIG = + "/artifact-database/flys/themes/configuration/text()"; + + public static final String XPATH_THEMES = + "theme"; + + public static final String XPATH_THEME_GROUPS = + "/themes/themegroup"; + + public static final String XPATH_THEME_MAPPINGS = + "/themes/mappings/mapping"; + + public static final String XPATH_RIVER_WMS = + "/artifact-database/floodmap/river"; + + public static final String XPATH_MODULES = "/artifact-database/modules/module"; + + private static final String XPATH_ZOOM_SCALES = "/artifact-database/options/zoom-scales/zoom-scale"; + + private static final String XPATH_DGM_PATH = "/artifact-database/options/dgm-path/text()"; + + + /** + * Creates a new FLYSArtifactContext object and initialize all + * components required by the application. + * + * @param config The artifact server configuration. + * @return a FLYSArtifactContext. + */ + @Override + public GlobalContext createArtifactContext(Document config) { + RiverContext context = new RiverContext(config); + + configureTransitions(config, context); + configureStates(config, context); + configureOutGenerators(config, context); + configureThemes(config, context); + configureThemesMappings(config, context); + configureFloodmapWMS(config, context); + configureModules(config, context); + configureZoomScales(config, context); + configureDGMPath(config, context); + + return context; + } + + + private void configureDGMPath(Document config, RiverContext context) { + String dgmPath = (String) XMLUtils.xpath( + config, + XPATH_DGM_PATH, + XPathConstants.STRING); + + context.put("dgm-path", dgmPath); + } + + + protected void configureZoomScales(Document config, RiverContext context) { + NodeList list = (NodeList)XMLUtils.xpath( + config, + XPATH_ZOOM_SCALES, + XPathConstants.NODESET); + ZoomScale scale = new ZoomScale(); + for (int i = 0; i < list.getLength(); i++) { + Element element = (Element)list.item(i); + String river = "default"; + double range = 0d; + double radius = 10d; + if (element.hasAttribute("river")) { + river = element.getAttribute("river"); + } + if (!element.hasAttribute("range")) { + continue; + } + else { + String r = element.getAttribute("range"); + try { + range = Double.parseDouble(r); + } + catch (NumberFormatException nfe) { + continue; + } + } + if (!element.hasAttribute("radius")) { + continue; + } + else { + String r = element.getAttribute("radius"); + try { + radius = Double.parseDouble(r); + } + catch (NumberFormatException nfe) { + continue; + } + } + scale.addRange(river, range, radius); + } + context.put("zoomscale", scale); + } + + + /** + * This method initializes the transition configuration. + * + * @param config the config document. + * @param context the RiverContext. + */ + protected void configureTransitions(Document config, RiverContext context) { + TransitionEngine engine = new TransitionEngine(); + + Document[] artifacts = getArtifactConfigurations(config); + logger.info("Found " + artifacts.length + " artifacts in the config."); + + for (Document doc: artifacts) { + + String artName = (String) XMLUtils.xpath( + doc, XPATH_ARTIFACT_NAME, XPathConstants.STRING); + + NodeList list = (NodeList) XMLUtils.xpath( + doc, XPATH_TRANSITIONS, XPathConstants.NODESET); + + if (list == null) { + logger.warn("The artifact " + artName + + " has no transitions configured."); + continue; + } + + int trans = list.getLength(); + + logger.info( + "Artifact '" + artName + "' has " + trans + " transitions."); + + for (int i = 0; i < trans; i++) { + Transition t = TransitionFactory.createTransition(list.item(i)); + String s = t.getFrom(); + engine.addTransition(s, t); + } + } + + context.put(RiverContext.TRANSITION_ENGINE_KEY, engine); + } + + + /** + * This method returns all artifact documents defined in + * <code>config</code>. <br>NOTE: The artifact configurations need to be + * stored in own files referenced by an xlink. + * + * @param config The global configuration. + * + * @return an array of Artifact configurations. + */ + protected Document[] getArtifactConfigurations(Document config) { + NodeList artifacts = (NodeList) XMLUtils.xpath( + config, XPATH_ARTIFACTS, XPathConstants.NODESET); + + int count = artifacts.getLength(); + + Document[] artifactDocs = new Document[count]; + + for (int i = 0; i < count; i++) { + Element tmp = (Element) artifacts.item(i); + + String xlink = tmp.getAttribute(XPATH_XLINK); + xlink = Config.replaceConfigDir(xlink); + + File artifactFile = new File(xlink); + artifactDocs[i] = XMLUtils.parseDocument(artifactFile); + } + + return artifactDocs; + } + + + /** + * This method initializes the transition configuration. + * + * @param config the config document. + * @param context the RiverContext. + */ + protected void configureStates(Document config, RiverContext context) { + StateEngine engine = new StateEngine(); + + Document[] artifacts = getArtifactConfigurations(config); + logger.info("Found " + artifacts.length + " artifacts in the config."); + + for (Document doc: artifacts) { + List<State> states = new ArrayList<State>(); + + String artName = (String) XMLUtils.xpath( + doc, XPATH_ARTIFACT_NAME, XPathConstants.STRING); + + NodeList stateList = (NodeList) XMLUtils.xpath( + doc, XPATH_STATES, XPathConstants.NODESET); + + if (stateList == null) { + logger.warn("The artifact " + artName + + " has no states configured."); + continue; + } + + int count = stateList.getLength(); + + logger.info( + "Artifact '" + artName + "' has " + count + " states."); + + for (int i = 0; i < count; i++) { + states.add(StateFactory.createState( + stateList.item(i))); + } + + engine.addStates(artName, states); + } + + context.put(RiverContext.STATE_ENGINE_KEY, engine); + } + + + /** + * This method intializes the provided output generators. + * + * @param config the config document. + * @param context the RiverContext. + */ + protected void configureOutGenerators(Document config, RiverContext context){ + Map<String, Class<?>> generators = new HashMap<String, Class<?>>(); + + NodeList outGenerators = (NodeList) XMLUtils.xpath( + config, + XPATH_OUTPUT_GENERATORS, + XPathConstants.NODESET); + + int num = outGenerators == null ? 0 : outGenerators.getLength(); + + if (num == 0) { + logger.warn("No output generators configured in this application."); + return; + } + + logger.info("Found " + num + " configured output generators."); + + int idx = 0; + + for (int i = 0; i < num; i++) { + Node item = outGenerators.item(i); + + String name = (String) XMLUtils.xpath( + item, "@name", XPathConstants.STRING); + + String clazz = (String) XMLUtils.xpath( + item, "text()", XPathConstants.STRING); + + if (name == null || clazz == null) { + continue; + } + + try { + generators.put(name, Class.forName(clazz)); + + idx++; + } + catch (ClassNotFoundException cnfe) { + logger.warn(cnfe, cnfe); + } + } + + logger.info("Successfully loaded " + idx + " output generators."); + context.put(RiverContext.OUTGENERATORS_KEY, generators); + } + + + /** + * This methods reads the configured themes and puts them into the + * RiverContext. + * + * @param config The global configuration. + * @param context The RiverContext. + */ + protected void configureThemes(Document config, RiverContext context) { + logger.debug("RiverContextFactory.configureThemes"); + + Document cfg = getThemeConfig(config); + + NodeList themeGroups = (NodeList) XMLUtils.xpath( + cfg, XPATH_THEME_GROUPS, XPathConstants.NODESET); + + int groupNum = themeGroups != null ? themeGroups.getLength() : 0; + + if (groupNum == 0) { + logger.warn("There are no theme groups configured!"); + } + + logger.info("Found " + groupNum + " theme groups in configuration"); + + List<ThemeGroup> groups = new ArrayList<ThemeGroup>(); + + for (int g = 0; g < groupNum; g++) { + Element themeGroup = (Element) themeGroups.item(g); + NodeList themes = (NodeList) XMLUtils.xpath( + themeGroup, XPATH_THEMES, XPathConstants.NODESET); + + int num = themes != null ? themes.getLength() : 0; + + if (num == 0) { + logger.warn("There are no themes configured!"); + return; + } + + logger.info("Theme group has " + num + " themes."); + + Map<String, Theme> theThemes = new HashMap<String, Theme>(); + + for (int i = 0; i < num; i++) { + Node theme = themes.item(i); + + Theme theTheme = ThemeFactory.createTheme(cfg, theme); + + if (theme != null) { + theThemes.put(theTheme.getName(), theTheme); + } + } + String gName = themeGroup.getAttribute("name"); + groups.add(new ThemeGroup(gName, theThemes)); + + logger.info( + "Initialized " + theThemes.size() + "/" + num + " themes " + + "of theme-group '" + gName + "'"); + } + context.put(RiverContext.THEMES, groups); + } + + /** + * This method is used to retrieve the theme configuration document. + * + * @param config The global configuration. + * + * @return the theme configuration. + */ + protected Document getThemeConfig(Document config) { + String themeConfig = (String) XMLUtils.xpath( + config, + XPATH_THEME_CONFIG, + XPathConstants.STRING); + + themeConfig = Config.replaceConfigDir(themeConfig); + + logger.debug("Parse theme cfg: " + themeConfig); + + return XMLUtils.parseDocument(new File(themeConfig)); + } + + + protected void configureThemesMappings(Document cfg, RiverContext context) { + logger.debug("RiverContextFactory.configureThemesMappings"); + + Document config = getThemeConfig(cfg); + + NodeList mappings = (NodeList) XMLUtils.xpath( + config, XPATH_THEME_MAPPINGS, XPathConstants.NODESET); + + int num = mappings != null ? mappings.getLength() : 0; + + if (num == 0) { + logger.warn("No theme <--> facet mappins found!"); + return; + } + + Map<String, List<ThemeMapping>> mapping = + new HashMap<String, List<ThemeMapping>>(); + + for (int i = 0; i < num; i++) { + Element node = (Element)mappings.item(i); + + String from = node.getAttribute("from"); + String to = node.getAttribute("to"); + String pattern = node.getAttribute("pattern"); + String masterAttrPattern = node.getAttribute("masterAttr"); + String outputPattern = node.getAttribute("output"); + + if (from.length() > 0 && to.length() > 0) { + List<ThemeMapping> tm = mapping.get(from); + + if (tm == null) { + tm = new ArrayList<ThemeMapping>(); + mapping.put(from, tm); + } + + tm.add(new ThemeMapping( + from, to, pattern, masterAttrPattern, outputPattern)); + } + } + + logger.debug("Found " + mapping.size() + " theme mappings."); + + context.put(RiverContext.THEME_MAPPING, mapping); + } + + + /** + * Reads configured floodmap river WMSs from floodmap.xml and + * loads them into the given RiverContext. + * @param cfg + * @param context + */ + protected void configureFloodmapWMS(Document cfg, RiverContext context) { + Map<String, String> riverWMS = new HashMap<String, String>(); + + NodeList rivers = (NodeList) XMLUtils.xpath( + cfg, XPATH_RIVER_WMS, XPathConstants.NODESET); + + int num = rivers != null ? rivers.getLength() : 0; + + for (int i = 0; i < num; i++) { + Element e = (Element) rivers.item(i); + + String river = e.getAttribute("name"); + String url = XMLUtils.xpathString(e, "river-wms/@url", null); + + if (river != null && url != null) { + riverWMS.put(river, url); + } + } + + logger.debug("Found " + riverWMS.size() + " river WMS."); + + context.put(RiverContext.RIVER_WMS, riverWMS); + } + + + /** + * This method initializes the modules configuration. + * + * @param config the config document. + * @param context the RiverContext. + */ + protected void configureModules(Document cfg, RiverContext context) { + NodeList modulenodes = (NodeList) XMLUtils.xpath( + cfg, XPATH_MODULES, XPathConstants.NODESET); + + int num = modulenodes != null ? modulenodes.getLength() : 0; + ArrayList<Module> modules = new ArrayList<Module>(num); + + for (int i = 0; i < num; i++) { + Element e = (Element) modulenodes.item(i); + String modulename = e.getAttribute("name"); + String attrselected = e.getAttribute("selected"); + boolean selected = attrselected == null ? false : + attrselected.equalsIgnoreCase("true"); + logger.debug("Loaded module " + modulename); + modules.add(new Module(modulename, selected)); + } + context.put(RiverContext.MODULES, modules); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :