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@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;
ingo@341: import de.intevation.flys.themes.ThemeFactory;
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:
ingo@106: /** 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 =
ingo@341: "/themes/theme";
ingo@341:
ingo@345: public static final String XPATH_THEME_MAPPINGS =
ingo@345: "/themes/mappings/mapping";
ingo@345:
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@106: public Object 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@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) {
ingo@106: logger.warn("The artifact 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) {
ingo@107: logger.warn("The artifact 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:
ingo@341: NodeList themes = (NodeList) XMLUtils.xpath(
ingo@341: cfg, XPATH_THEMES, XPathConstants.NODESET);
ingo@341:
ingo@341: int num = themes != null ? themes.getLength() : 0;
ingo@341:
ingo@341: if (num == 0) {
ingo@341: logger.warn("There are no themes configured!");
ingo@341: return;
ingo@341: }
ingo@341:
ingo@341: logger.debug("Found " + num + " configured themes.");
ingo@341:
ingo@341: Map theThemes = new HashMap();
ingo@341:
ingo@341: for (int i = 0; i < num; i++) {
ingo@341: Node theme = themes.item(i);
ingo@341:
ingo@341: Theme theTheme = ThemeFactory.createTheme(cfg, theme);
ingo@341:
ingo@341: if (theme != null) {
ingo@341: theThemes.put(theTheme.getName(), theTheme);
ingo@341: }
ingo@341: }
ingo@341:
ingo@341: logger.debug("Initialized " + theThemes.size() + "/" + num + " themes");
ingo@341:
ingo@341: context.put(FLYSContext.THEMES, theThemes);
ingo@341: }
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@345: Map mapping = new HashMap();
ingo@345:
ingo@345: for (int i = 0; i < num; i++) {
ingo@345: Node node = mappings.item(i);
ingo@345:
ingo@345: String from = (String) XMLUtils.xpath(
ingo@345: node, "@from", XPathConstants.STRING);
ingo@345:
ingo@345: String to = (String) XMLUtils.xpath(
ingo@345: node, "@to", XPathConstants.STRING);
ingo@345:
ingo@345: if (from != null && to != null) {
ingo@345: mapping.put(from, to);
ingo@345: }
ingo@345: }
ingo@345:
ingo@345: logger.debug("Found " + mapping.size() + " theme/facet mappings.");
ingo@345:
ingo@345: context.put(FLYSContext.THEME_MAPPING, mapping);
ingo@345: }
ingo@106: }
ingo@106: // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :