ingo@106: package de.intevation.flys.artifacts.context; ingo@106: ingo@106: import java.io.File; ingo@106: import java.util.ArrayList; ingo@295: import java.util.HashMap; ingo@106: import java.util.List; ingo@295: import java.util.Map; ingo@106: ingo@106: import javax.xml.xpath.XPathConstants; ingo@106: ingo@106: import org.apache.log4j.Logger; ingo@106: ingo@106: import org.w3c.dom.Document; ingo@106: import org.w3c.dom.Element; ingo@295: import org.w3c.dom.Node; ingo@106: import org.w3c.dom.NodeList; ingo@106: ingo@106: import de.intevation.artifacts.ArtifactContextFactory; ingo@939: import de.intevation.artifacts.GlobalContext; ingo@106: ingo@106: import de.intevation.artifacts.common.utils.XMLUtils; sascha@130: import de.intevation.artifacts.common.utils.Config; ingo@106: ingo@107: import de.intevation.artifactdatabase.state.State; ingo@107: import de.intevation.artifactdatabase.state.StateEngine; ingo@107: import de.intevation.artifactdatabase.transition.Transition; ingo@107: import de.intevation.artifactdatabase.transition.TransitionEngine; ingo@106: ingo@107: import de.intevation.flys.artifacts.states.StateFactory; ingo@106: import de.intevation.flys.artifacts.transitions.TransitionFactory; ingo@341: import de.intevation.flys.themes.Theme; raimund@2737: import de.intevation.flys.themes.ThemeGroup; ingo@341: import de.intevation.flys.themes.ThemeFactory; ingo@1747: import de.intevation.flys.themes.ThemeMapping; ingo@106: ingo@106: ingo@106: /** ingo@106: * The ArtifactContextFactory is used to initialize basic components and put ingo@106: * them into the global context of the application. ingo@106: * ingo@106: * @author Ingo Weinzierl ingo@106: */ ingo@106: public class FLYSContextFactory implements ArtifactContextFactory { ingo@106: felix@1826: /** The logger that is used in this class. */ ingo@106: private static Logger logger = Logger.getLogger(FLYSContextFactory.class); ingo@106: ingo@106: /** The XPath to the artifacts configured in the configuration. */ ingo@106: public static final String XPATH_ARTIFACTS = ingo@106: "/artifact-database/artifacts/artifact"; ingo@106: ingo@106: /** The XPath to the name of the artifact. */ ingo@107: public static final String XPATH_ARTIFACT_NAME = "/artifact/@name"; ingo@106: ingo@106: /** The XPath to the xlink ref in an artifact configuration. */ ingo@106: public static final String XPATH_XLINK = "xlink:href"; ingo@106: ingo@106: /** The XPath to the transitions configured in the artifact config. */ ingo@106: public static final String XPATH_TRANSITIONS = ingo@106: "/artifact/states/transition"; ingo@106: ingo@107: /** The XPath to the states configured in the artifact config. */ ingo@107: public static final String XPATH_STATES = ingo@107: "/artifact/states/state"; ingo@107: ingo@295: public static final String XPATH_OUTPUT_GENERATORS = ingo@295: "/artifact-database/output-generators/output-generator"; ingo@295: ingo@341: public static final String XPATH_THEME_CONFIG = ingo@341: "/artifact-database/flys/themes/configuration/text()"; ingo@341: ingo@341: public static final String XPATH_THEMES = raimund@2737: "theme"; raimund@2737: raimund@2737: public static final String XPATH_THEME_GROUPS = raimund@2737: "/themes/themegroup"; ingo@341: ingo@345: public static final String XPATH_THEME_MAPPINGS = ingo@345: "/themes/mappings/mapping"; ingo@345: ingo@958: public static final String XPATH_RIVER_WMS = ingo@1062: "/artifact-database/floodmap/river"; ingo@958: ingo@106: /** ingo@106: * Creates a new FLYSArtifactContext object and initialize all ingo@106: * components required by the application. ingo@106: * ingo@106: * @param config The artifact server configuration. ingo@106: * @return a FLYSArtifactContext. ingo@106: */ ingo@939: public GlobalContext createArtifactContext(Document config) { ingo@106: FLYSContext context = new FLYSContext(config); ingo@106: ingo@106: configureTransitions(config, context); ingo@107: configureStates(config, context); ingo@295: configureOutGenerators(config, context); ingo@341: configureThemes(config, context); ingo@345: configureThemesMappings(config, context); ingo@958: configureRiverWMS(config, context); ingo@106: ingo@106: return context; ingo@106: } ingo@106: ingo@106: ingo@106: /** ingo@106: * This method initializes the transition configuration. ingo@106: * ingo@106: * @param config the config document. ingo@106: * @param context the FLYSContext. ingo@106: */ ingo@106: protected void configureTransitions(Document config, FLYSContext context) { ingo@106: TransitionEngine engine = new TransitionEngine(); ingo@106: ingo@106: Document[] artifacts = getArtifactConfigurations(config); ingo@106: logger.info("Found " + artifacts.length + " artifacts in the config."); ingo@106: ingo@106: for (Document doc: artifacts) { ingo@106: List transitions = new ArrayList(); ingo@106: ingo@106: String artName = (String) XMLUtils.xpath( ingo@106: doc, XPATH_ARTIFACT_NAME, XPathConstants.STRING); ingo@106: ingo@111: NodeList list = (NodeList) XMLUtils.xpath( ingo@106: doc, XPATH_TRANSITIONS, XPathConstants.NODESET); ingo@106: ingo@111: if (list == null) { felix@2141: logger.warn("The artifact " + artName + felix@2141: " has no transitions configured."); ingo@107: continue; ingo@106: } ingo@106: ingo@111: int trans = list.getLength(); ingo@106: ingo@106: logger.info( ingo@106: "Artifact '" + artName + "' has " + trans + " transitions."); ingo@106: ingo@106: for (int i = 0; i < trans; i++) { ingo@111: Transition t = TransitionFactory.createTransition(list.item(i)); ingo@111: String s = t.getFrom(); ingo@111: engine.addTransition(s, t); ingo@106: } ingo@106: } ingo@106: ingo@106: context.put(FLYSContext.TRANSITION_ENGINE_KEY, engine); ingo@106: } ingo@106: ingo@106: ingo@106: /** ingo@106: * This method returns all artifact documents defined in ingo@106: * config.
NOTE: The artifact configurations need to be ingo@106: * stored in own files referenced by an xlink. ingo@106: * ingo@106: * @param config The global configuration. ingo@106: * ingo@106: * @return an array of Artifact configurations. ingo@106: */ ingo@106: protected Document[] getArtifactConfigurations(Document config) { ingo@106: NodeList artifacts = (NodeList) XMLUtils.xpath( ingo@106: config, XPATH_ARTIFACTS, XPathConstants.NODESET); ingo@106: ingo@106: int count = artifacts.getLength(); ingo@106: ingo@106: Document[] artifactDocs = new Document[count]; ingo@106: ingo@106: for (int i = 0; i < count; i++) { ingo@106: Element tmp = (Element) artifacts.item(i); ingo@106: ingo@106: String xlink = tmp.getAttribute(XPATH_XLINK); ingo@106: xlink = Config.replaceConfigDir(xlink); ingo@106: ingo@106: File artifactFile = new File(xlink); ingo@106: artifactDocs[i] = XMLUtils.parseDocument(artifactFile); ingo@106: } ingo@106: ingo@106: return artifactDocs; ingo@106: } ingo@107: ingo@107: ingo@107: /** ingo@107: * This method initializes the transition configuration. ingo@107: * ingo@107: * @param config the config document. ingo@107: * @param context the FLYSContext. ingo@107: */ ingo@107: protected void configureStates(Document config, FLYSContext context) { ingo@107: StateEngine engine = new StateEngine(); ingo@107: ingo@107: Document[] artifacts = getArtifactConfigurations(config); ingo@107: logger.info("Found " + artifacts.length + " artifacts in the config."); ingo@107: ingo@107: for (Document doc: artifacts) { ingo@107: List states = new ArrayList(); ingo@107: ingo@107: String artName = (String) XMLUtils.xpath( ingo@107: doc, XPATH_ARTIFACT_NAME, XPathConstants.STRING); ingo@107: ingo@107: NodeList stateList = (NodeList) XMLUtils.xpath( ingo@107: doc, XPATH_STATES, XPathConstants.NODESET); ingo@107: ingo@107: if (stateList == null) { felix@2141: logger.warn("The artifact " + artName + felix@2141: " has no states configured."); ingo@107: continue; ingo@107: } ingo@107: ingo@107: int count = stateList.getLength(); ingo@107: ingo@107: logger.info( ingo@107: "Artifact '" + artName + "' has " + count + " states."); ingo@107: ingo@107: for (int i = 0; i < count; i++) { ingo@107: states.add(StateFactory.createState( ingo@107: stateList.item(i))); ingo@107: } ingo@107: ingo@107: engine.addStates(artName, states); ingo@107: } ingo@107: ingo@107: context.put(FLYSContext.STATE_ENGINE_KEY, engine); ingo@107: } ingo@295: ingo@295: ingo@295: /** ingo@295: * This method intializes the provided output generators. ingo@295: * ingo@295: * @param config the config document. ingo@295: * @param context the FLYSContext. ingo@295: */ ingo@295: protected void configureOutGenerators(Document config, FLYSContext context){ ingo@295: Map generators = new HashMap(); ingo@295: ingo@295: NodeList outGenerators = (NodeList) XMLUtils.xpath( ingo@295: config, ingo@295: XPATH_OUTPUT_GENERATORS, ingo@295: XPathConstants.NODESET); ingo@295: ingo@295: int num = outGenerators == null ? 0 : outGenerators.getLength(); ingo@295: ingo@295: if (num == 0) { ingo@295: logger.warn("No output generators configured in this application."); ingo@295: return; ingo@295: } ingo@295: ingo@295: logger.info("Found " + num + " configured output generators."); ingo@295: ingo@295: int idx = 0; ingo@295: ingo@295: for (int i = 0; i < num; i++) { ingo@295: Node item = outGenerators.item(i); ingo@295: ingo@295: String name = (String) XMLUtils.xpath( ingo@295: item, "@name", XPathConstants.STRING); ingo@295: ingo@295: String clazz = (String) XMLUtils.xpath( ingo@295: item, "text()", XPathConstants.STRING); ingo@295: ingo@295: if (name == null || clazz == null) { ingo@295: continue; ingo@295: } ingo@295: ingo@295: try { ingo@295: generators.put(name, Class.forName(clazz)); ingo@295: ingo@295: idx++; ingo@295: } ingo@295: catch (ClassNotFoundException cnfe) { ingo@295: logger.warn(cnfe, cnfe); ingo@295: } ingo@295: } ingo@295: ingo@295: logger.info("Successfully loaded " + idx + " output generators."); ingo@295: context.put(FLYSContext.OUTGENERATORS_KEY, generators); ingo@295: } ingo@341: ingo@341: ingo@341: /** ingo@341: * This methods reads the configured themes and puts them into the ingo@341: * FLYSContext. ingo@341: * ingo@341: * @param config The global configuration. ingo@341: * @param context The FLYSContext. ingo@341: */ ingo@341: protected void configureThemes(Document config, FLYSContext context) { ingo@341: logger.debug("FLYSContextFactory.configureThemes"); ingo@341: ingo@341: Document cfg = getThemeConfig(config); ingo@341: raimund@2737: NodeList themeGroups = (NodeList) XMLUtils.xpath( raimund@2737: cfg, XPATH_THEME_GROUPS, XPathConstants.NODESET); ingo@341: raimund@2737: int groupNum = themeGroups != null ? themeGroups.getLength() : 0; ingo@341: raimund@2737: if (groupNum == 0) { raimund@2737: logger.warn("There are no theme groups configured!"); ingo@341: } ingo@3239: ingo@3239: logger.info("Found " + groupNum + " theme groups in configuration"); ingo@341: raimund@2737: List groups = new ArrayList(); ingo@341: raimund@2737: for (int g = 0; g < groupNum; g++) { raimund@2737: Element themeGroup = (Element) themeGroups.item(g); raimund@2737: NodeList themes = (NodeList) XMLUtils.xpath( raimund@2737: themeGroup, XPATH_THEMES, XPathConstants.NODESET); ingo@341: raimund@2737: int num = themes != null ? themes.getLength() : 0; ingo@341: raimund@2737: if (num == 0) { raimund@2737: logger.warn("There are no themes configured!"); raimund@2737: return; raimund@2737: } raimund@2737: ingo@3239: logger.info("Theme group has " + num + " themes."); raimund@2737: raimund@2737: Map theThemes = new HashMap(); raimund@2737: raimund@2737: for (int i = 0; i < num; i++) { raimund@2737: Node theme = themes.item(i); raimund@2737: raimund@2737: Theme theTheme = ThemeFactory.createTheme(cfg, theme); raimund@2737: raimund@2737: if (theme != null) { raimund@2737: theThemes.put(theTheme.getName(), theTheme); raimund@2737: } raimund@2737: } raimund@2737: String gName = themeGroup.getAttribute("name"); raimund@2737: groups.add(new ThemeGroup(gName, theThemes)); ingo@3239: ingo@3239: logger.info( ingo@3239: "Initialized " + theThemes.size() + "/" + num + " themes " + ingo@3239: "of theme-group '" + gName + "'"); raimund@2737: } raimund@2737: context.put(FLYSContext.THEMES, groups); ingo@341: } ingo@341: ingo@341: /** ingo@341: * This method is used to retrieve the theme configuration document. ingo@341: * ingo@341: * @param config The global configuration. ingo@341: * ingo@341: * @return the theme configuration. ingo@341: */ ingo@341: protected Document getThemeConfig(Document config) { ingo@341: String themeConfig = (String) XMLUtils.xpath( ingo@341: config, ingo@341: XPATH_THEME_CONFIG, ingo@341: XPathConstants.STRING); ingo@341: ingo@341: themeConfig = Config.replaceConfigDir(themeConfig); ingo@341: ingo@341: logger.debug("Parse theme cfg: " + themeConfig); ingo@341: ingo@341: return XMLUtils.parseDocument(new File(themeConfig)); ingo@341: } ingo@345: ingo@345: ingo@345: protected void configureThemesMappings(Document cfg, FLYSContext context) { ingo@345: logger.debug("FLYSContextFactory.configureThemesMappings"); ingo@345: ingo@345: Document config = getThemeConfig(cfg); ingo@345: ingo@345: NodeList mappings = (NodeList) XMLUtils.xpath( ingo@345: config, XPATH_THEME_MAPPINGS, XPathConstants.NODESET); ingo@345: ingo@345: int num = mappings != null ? mappings.getLength() : 0; ingo@345: ingo@345: if (num == 0) { ingo@345: logger.warn("No theme <--> facet mappins found!"); ingo@345: return; ingo@345: } ingo@345: ingo@1747: Map> mapping = ingo@1747: new HashMap>(); ingo@345: ingo@345: for (int i = 0; i < num; i++) { raimund@2742: Element node = (Element)mappings.item(i); ingo@345: raimund@2742: String from = node.getAttribute("from"); raimund@2742: String to = node.getAttribute("to"); raimund@2742: String pattern = node.getAttribute("pattern"); raimund@2742: String masterAttrPattern = node.getAttribute("masterAttr"); raimund@2742: String outputPattern = node.getAttribute("output"); ingo@1747: raimund@2742: if (from.length() > 0 && to.length() > 0) { ingo@1747: List tm = mapping.get(from); ingo@1747: ingo@1747: if (tm == null) { ingo@1747: tm = new ArrayList(); ingo@1747: mapping.put(from, tm); ingo@1747: } ingo@1747: felix@1822: tm.add(new ThemeMapping( felix@1828: from, to, pattern, masterAttrPattern, outputPattern)); ingo@345: } ingo@345: } ingo@345: ingo@1747: logger.debug("Found " + mapping.size() + " theme mappings."); ingo@345: ingo@345: context.put(FLYSContext.THEME_MAPPING, mapping); ingo@345: } ingo@958: ingo@958: ingo@958: protected void configureRiverWMS(Document cfg, FLYSContext context) { ingo@958: Map riverWMS = new HashMap(); ingo@958: ingo@958: NodeList rivers = (NodeList) XMLUtils.xpath( ingo@958: cfg, XPATH_RIVER_WMS, XPathConstants.NODESET); ingo@958: ingo@958: int num = rivers != null ? rivers.getLength() : 0; ingo@958: ingo@958: for (int i = 0; i < num; i++) { ingo@958: Element e = (Element) rivers.item(i); ingo@958: ingo@1062: String river = e.getAttribute("name"); ingo@1062: String url = XMLUtils.xpathString(e, "river-wms/@url", null); ingo@958: ingo@958: if (river != null && url != null) { ingo@958: riverWMS.put(river, url); ingo@958: } ingo@958: } ingo@958: ingo@958: logger.debug("Found " + riverWMS.size() + " river WMS."); ingo@958: ingo@958: context.put(FLYSContext.RIVER_WMS, riverWMS); ingo@958: } ingo@106: } ingo@106: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :