view flys-artifacts/src/main/java/de/intevation/flys/artifacts/context/FLYSContextFactory.java @ 4655:cd44d28d0fbc

Move the access to artifact data to the Access object Use BedHeightAccess class to receive the data from the artifact. This abstracts the data access from the actual artifact.
author Björn Ricks <bjoern.ricks@intevation.de>
date Tue, 11 Dec 2012 09:44:04 +0100
parents e29f368c09ba
children 442fbb290fa8
line wrap: on
line source
package de.intevation.flys.artifacts.context;

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;

import de.intevation.artifacts.ArtifactContextFactory;
import de.intevation.artifacts.GlobalContext;

import de.intevation.artifacts.common.utils.XMLUtils;
import de.intevation.artifacts.common.utils.Config;

import de.intevation.artifactdatabase.state.State;
import de.intevation.artifactdatabase.state.StateEngine;
import de.intevation.artifactdatabase.transition.Transition;
import de.intevation.artifactdatabase.transition.TransitionEngine;

import de.intevation.flys.artifacts.model.Module;
import de.intevation.flys.artifacts.model.ZoomScale;
import de.intevation.flys.artifacts.states.StateFactory;
import de.intevation.flys.artifacts.transitions.TransitionFactory;
import de.intevation.flys.themes.Theme;
import de.intevation.flys.themes.ThemeGroup;
import de.intevation.flys.themes.ThemeFactory;
import de.intevation.flys.themes.ThemeMapping;


/**
 * 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 FLYSContextFactory implements ArtifactContextFactory {

    /** The logger that is used in this class. */
    private static Logger logger = Logger.getLogger(FLYSContextFactory.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";

    /**
     * Creates a new FLYSArtifactContext object and initialize all
     * components required by the application.
     *
     * @param config The artifact server configuration.
     * @return a FLYSArtifactContext.
     */
    public GlobalContext createArtifactContext(Document config) {
        FLYSContext context = new FLYSContext(config);

        configureTransitions(config, context);
        configureStates(config, context);
        configureOutGenerators(config, context);
        configureThemes(config, context);
        configureThemesMappings(config, context);
        configureRiverWMS(config, context);
        configureModules(config, context);
        configureZoomScales(config, context);

        return context;
    }


    private void configureZoomScales(Document config, FLYSContext 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 FLYSContext.
     */
    protected void configureTransitions(Document config, FLYSContext 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(FLYSContext.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 FLYSContext.
     */
    protected void configureStates(Document config, FLYSContext 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(FLYSContext.STATE_ENGINE_KEY, engine);
    }


    /**
     * This method intializes the provided output generators.
     *
     * @param config the config document.
     * @param context the FLYSContext.
     */
    protected void configureOutGenerators(Document config, FLYSContext 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(FLYSContext.OUTGENERATORS_KEY, generators);
    }


    /**
     * This methods reads the configured themes and puts them into the
     * FLYSContext.
     *
     * @param config The global configuration.
     * @param context The FLYSContext.
     */
    protected void configureThemes(Document config, FLYSContext context) {
        logger.debug("FLYSContextFactory.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(FLYSContext.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, FLYSContext context) {
        logger.debug("FLYSContextFactory.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(FLYSContext.THEME_MAPPING, mapping);
    }


    protected void configureRiverWMS(Document cfg, FLYSContext 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(FLYSContext.RIVER_WMS, riverWMS);
    }


    /**
     * This method initializes the modules configuration.
     *
     * @param config the config document.
     * @param context the FLYSContext.
     */
    protected void configureModules(Document cfg, FLYSContext 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(FLYSContext.MODULES, modules);
    }
}
// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org