Package org.vfny.geoserver.global.xml

Source Code of org.vfny.geoserver.global.xml.XMLConfigReader

/* Copyright (c) 2001, 2003 TOPP - www.openplans.org.  All rights reserved.
* This code is licensed under the GPL 2.0 license, availible at the root
* application directory.
*/
package org.vfny.geoserver.global.xml;

import com.vividsolutions.jts.geom.Envelope;
import org.apache.xml.serialize.LineSeparator;
import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.geotools.filter.FilterDOMParser;
import org.vfny.geoserver.global.ConfigurationException;
import org.vfny.geoserver.global.GeoServer;
import org.vfny.geoserver.global.GeoserverDataDirectory;
import org.vfny.geoserver.global.Log4JFormatter;
import org.vfny.geoserver.global.dto.AttributeTypeInfoDTO;
import org.vfny.geoserver.global.dto.ContactDTO;
import org.vfny.geoserver.global.dto.DataDTO;
import org.vfny.geoserver.global.dto.DataStoreInfoDTO;
import org.vfny.geoserver.global.dto.FeatureTypeInfoDTO;
import org.vfny.geoserver.global.dto.GeoServerDTO;
import org.vfny.geoserver.global.dto.LegendURLDTO;
import org.vfny.geoserver.global.dto.NameSpaceInfoDTO;
import org.vfny.geoserver.global.dto.ServiceDTO;
import org.vfny.geoserver.global.dto.StyleDTO;
import org.vfny.geoserver.global.dto.WFSDTO;
import org.vfny.geoserver.global.dto.WMSDTO;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.io.StringWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;


/**
* XMLConfigReader purpose.
*
* <p>
* Description of XMLConfigReader  Static class to load a configuration
* org.vfny.geoserver.global.dto
* </p>
*
* <p>
* Example Use:
* <pre><code>
* ModelConfig m = XMLConfigReader.load(new File("/conf/"));
* </code></pre>
* </p>
*
* @author dzwiers, Refractions Research, Inc.
* @version $Id: XMLConfigReader.java,v 1.43 2004/09/13 16:04:26 cholmesny Exp $
*/
public class XMLConfigReader {
    /** Used internally to create log information to detect errors. */
    private static final Logger LOGGER = Logger.getLogger(
            "org.vfny.geoserver.global");

    /** The root directory from which the configuration is loaded. */
    private File root;

    /** Is set to true after the model is loaded into memory. */
    private boolean initialized = false;
    private WMSDTO wms;
    private WFSDTO wfs;
    private GeoServerDTO geoServer;
    private DataDTO data;

    /** the servlet context **/
    ServletContext context;
   
    /**
     * XMLConfigReader constructor.
     *
     * <p>
     * Should never be called.
     * </p>
     */
    protected XMLConfigReader(ServletContext context) {
      this.context = context;
      wms = new WMSDTO();
        wfs = new WFSDTO();
        geoServer = new GeoServerDTO();
        data = new DataDTO();
        root = new File(".");
    }

    /**
     * <p>
     * This method loads the config files from the  specified directory into a
     * ModelConfig. If the path is incorrect,  or the directory is formed
     * correctly, a ConfigException  will be thrown and/or null returned. <br>
     * <br>
     * The config directory is as follows:<br>
     *
     * <ul>
     * <li>
     * ./WEB-INF/catalog.xml
     * </li>
     * <li>
     * ./WEB-INF/services.xml
     * </li>
     * <li>
     * ./data/featuretypes/  /info.xml
     * </li>
     * <li>
     * ./data/featuretypes/  /schema.xml
     * </li>
     * </ul>
     * </p>
     *
     * @param root A directory which contains the config files.
     *
     * @throws ConfigurationException When an error occurs.
     */
    public XMLConfigReader(File root, ServletContext context) throws ConfigurationException {
        this.root = root;
        this.context = context;
        wms = new WMSDTO();
        wfs = new WFSDTO();
        geoServer = new GeoServerDTO();
        data = new DataDTO();
        load();
        initialized = true;
       
    }

    public boolean isInitialized() {
        return initialized;
    }

    /**
     * load purpose.
     *
     * <p>
     * Main load routine, sets up file handles for various other portions of
     * the load procedure.
     * </p>
     *
     * @throws ConfigurationException
     */
    protected void load() throws ConfigurationException {
        root = ReaderUtils.checkFile(root, true);
  File configDir;

        //Doing some trys here for either being in the webapp, with data and web-inf defined
        //or in a true data_dir, with the catalog and service in the same root dir.
        try {
            configDir = ReaderUtils.checkFile(new File(root, "WEB-INF/"), true);
        } catch (ConfigurationException confE) {
            //no WEB-INF, so we're in a data_dir, use as root.
            configDir = root;
        }
        File configFile = ReaderUtils.checkFile(new File(configDir,
                    "services.xml"), false);

        loadServices(configFile);

        File catalogFile = ReaderUtils.checkFile(new File(configDir,
                    "catalog.xml"), false);
        File featureTypeDir = GeoserverDataDirectory.findConfigDir(root, "featureTypes/");
        File styleDir = GeoserverDataDirectory.findConfigDir(root, "styles/");

        loadCatalog(catalogFile, featureTypeDir, styleDir);

        // Future additions
        // validationDir = ReaderUtils.initFile(new File(dataDir,"validation/"),true);
        // loadValidation(validationDir); 
    }

    /**
     * loadServices purpose.
     *
     * <p>
     * loads services.xml into memory with the assistance of other class
     * methods.
     * </p>
     *
     * @param configFile services.xml
     *
     * @throws ConfigurationException When an error occurs.
     */
    protected void loadServices(File configFile) throws ConfigurationException {
        LOGGER.config("Loading configuration file: " + configFile);

        Element configElem = null;

        try {
            FileReader fr = new FileReader(configFile);
            configElem = ReaderUtils.loadConfig(fr);
            fr.close();
        } catch (FileNotFoundException e) {
            throw new ConfigurationException(e);
        } catch (IOException e) {
            throw new ConfigurationException(e);
        }

        LOGGER.config("parsing configuration documents");

        Element elem = (Element) configElem.getElementsByTagName("global").item(0);
        loadGlobal(elem);

        NodeList configuredServices = configElem.getElementsByTagName("service");
        int nServices = configuredServices.getLength();

        for (int i = 0; i < nServices; i++) {
            elem = (Element) configuredServices.item(i);

            String serviceType = elem.getAttribute("type");

            if ("WFS".equalsIgnoreCase(serviceType)) {
                loadWFS(elem);
            } else if ("WMS".equalsIgnoreCase(serviceType)) {
                loadWMS(elem);
            } else if ("Z39.50".equalsIgnoreCase(serviceType)) {
                //...
            } else {
                throw new ConfigurationException("Unknown service type: "
                    + serviceType);
            }
        }
    }

    /**
     * loadCatalog purpose.
     *
     * <p>
     * loads catalog.xml into memory with the assistance of other class
     * methods.
     * </p>
     *
     * @param catalogFile catalog.xml
     * @param featureTypeDir the directory containing the info.xml files for
     *        the featuretypes.
     *
     * @throws ConfigurationException When an error occurs.
     */
    protected void loadCatalog(File catalogFile, File featureTypeDir,
                                File styleDir)
        throws ConfigurationException {
       
        Element catalogElem = null;

        try {
          LOGGER.config("Loading configuration file: " + catalogFile);
            FileReader fr = new FileReader(catalogFile);
            catalogElem = ReaderUtils.loadConfig(fr);
            fr.close();
        } catch (FileNotFoundException e) {
            throw new ConfigurationException(e);
        } catch (IOException e) {
            throw new ConfigurationException(e);
        }

        data.setNameSpaces(loadNameSpaces(ReaderUtils.getChildElement(
                    catalogElem, "namespaces", true)));
        setDefaultNS();
        data.setDataStores(loadDataStores(ReaderUtils.getChildElement(
                    catalogElem, "datastores", true)));


        data.setStyles(loadStyles(ReaderUtils.getChildElement(catalogElem,
              "styles", false), styleDir));
//                new File(featureTypeDir.getParentFile(), "styles")));

        // must be last
        data.setFeaturesTypes(loadFeatureTypes(featureTypeDir));
    }

    /**
     * setDefaultNS purpose.
     *
     * <p>
     * Finds and sets the default namespace. The namespaces in catalog must
     * already be loaded.
     * </p>
     */
    protected void setDefaultNS() {
        Iterator i = data.getNameSpaces().values().iterator();

        while (i.hasNext()) {
            NameSpaceInfoDTO ns = (NameSpaceInfoDTO) i.next();

            if (ns.isDefault()) {
                data.setDefaultNameSpacePrefix(ns.getPrefix());
                LOGGER.finer("set default namespace pre to " + ns.getPrefix());

                return;
            }
        }
    }

    /**
     * getLoggingLevel purpose.
     *
     * <p>
     * Parses the LoggingLevel from a DOM tree and converts the level into a
     * Level Object.
     * </p>
     *
     * @param globalConfigElem
     *
     * @return The logging Level
     *
     * @throws ConfigurationException When an error occurs.
     */
    protected Level getLoggingLevel(Element globalConfigElem)
        throws ConfigurationException {
        Level level = Logger.getLogger("org.vfny.geoserver").getLevel();
        Element levelElem = ReaderUtils.getChildElement(globalConfigElem,
                "loggingLevel");

        if (levelElem != null) {
            String levelName = levelElem.getFirstChild().getNodeValue();

            try {
                level = Level.parse(levelName);
            } catch (IllegalArgumentException ex) {
                LOGGER.warning("illegal loggingLevel name: " + levelName);
            }
        } else {
            LOGGER.config("No loggingLevel found, using default "
                + "logging.properties setting");
        }

        return level;
    }

    /**
     * loadGlobal purpose.
     *
     * <p>
     * Converts a DOM tree into a GlobalData configuration.
     * </p>
     *
     * @param globalElem A DOM tree representing a complete global
     *        configuration.
     *
     * @throws ConfigurationException When an error occurs.
     */
    protected void loadGlobal(Element globalElem) throws ConfigurationException {
        geoServer = new GeoServerDTO();
        LOGGER.finer("parsing global configuration parameters");

        Level loggingLevel = getLoggingLevel(globalElem);
        geoServer.setLoggingLevel(loggingLevel);

        boolean loggingToFile = false;
        Element elem = null;
        elem = ReaderUtils.getChildElement(globalElem, "loggingToFile",false);
        if (elem != null) {
           loggingToFile = ReaderUtils.getBooleanAttribute(elem, "value", false, false);
        }
       
        String logLocation = ReaderUtils.getChildText(globalElem, "logLocation");
        if ((logLocation != null) && "".equals(logLocation.trim())) {
            logLocation = null;
        }

        geoServer.setLoggingToFile(loggingToFile);
        geoServer.setLogLocation(logLocation);

        //init this now so the rest of the config has correct log levels.
        try {
            GeoServer.initLogging(loggingLevel, loggingToFile,logLocation, context);
        } catch (IOException e) {
            throw new ConfigurationException(e);
        }

        LOGGER.config("logging level is " + loggingLevel);

        if (logLocation != null) {
            LOGGER.config("logging to " + logLocation);
        }

        elem = ReaderUtils.getChildElement(globalElem, "ContactInformation");
        geoServer.setContact(loadContact(elem));

        elem = ReaderUtils.getChildElement(globalElem, "verbose", false);

        if (elem != null) {
            geoServer.setVerbose(ReaderUtils.getBooleanAttribute(elem, "value",
                    false, true));
        }

        elem = ReaderUtils.getChildElement(globalElem, "maxFeatures");

        if (elem != null) {
            //if the element is pressent, it's "value" attribute is mandatory
            geoServer.setMaxFeatures(ReaderUtils.getIntAttribute(elem, "value",
                    true, geoServer.getMaxFeatures()));
        }

        LOGGER.config("maxFeatures is " + geoServer.getMaxFeatures());
        elem = ReaderUtils.getChildElement(globalElem, "numDecimals");

        if (elem != null) {
            geoServer.setNumDecimals(ReaderUtils.getIntAttribute(elem, "value",
                    true, geoServer.getNumDecimals()));
        }

        LOGGER.config("numDecimals returning is " + geoServer.getNumDecimals());
        elem = ReaderUtils.getChildElement(globalElem, "charSet");

        if (elem != null) {
            String chSet = ReaderUtils.getAttribute(elem, "value", true);

            try {
                Charset cs = Charset.forName(chSet);
                geoServer.setCharSet(cs);
                LOGGER.finer("charSet: " + cs.displayName());
            } catch (Exception ex) {
                LOGGER.info(ex.getMessage());
            }
        }

        LOGGER.config("charSet is " + geoServer.getCharSet());

        //Schema base doesn't work - this root thing is wrong.  So for 1.2.0 I'm
        //just going to leave it out.  The GeoServer.getSchemaBaseUrl is never
        //called, Request.getSchemaBaseUrl is used, and it always returns the
        //relative local one.  This field was a hack anyways, so I don't think
        //anyone is going to miss it much - though I could be proved wrong. ch
        String schemaBaseUrl = ReaderUtils.getChildText(globalElem,
                "SchemaBaseUrl");

        if (schemaBaseUrl != null) {
            geoServer.setSchemaBaseUrl(schemaBaseUrl);
        } else {
            //This is wrong - need some key to tell the method to return based
            //on the url passed in.
            geoServer.setSchemaBaseUrl(root.toString() + "/data/capabilities/");
        }

        String adminUserName = ReaderUtils.getChildText(globalElem,
                "adminUserName");

        if (adminUserName != null) {
            geoServer.setAdminUserName(adminUserName);
        }

        String adminPassword = ReaderUtils.getChildText(globalElem,
                "adminPassword");

        if (adminPassword != null) {
            geoServer.setAdminPassword(adminPassword);
        }

        elem = ReaderUtils.getChildElement(globalElem, "verboseExceptions",
                false);

        if (elem != null) {
            geoServer.setVerboseExceptions(ReaderUtils.getBooleanAttribute(
                    elem, "value", false, true));
        }
    }

    /**
     * loadContact purpose.
     *
     * <p>
     * Converts a DOM tree into a ContactConfig
     * </p>
     *
     * @param contactInfoElement a DOM tree to convert into a ContactConfig.
     *
     * @return The resulting ContactConfig object from the DOM tree.
     *
     * @throws ConfigurationException When an error occurs.
     */
    protected ContactDTO loadContact(Element contactInfoElement)
        throws ConfigurationException {
        ContactDTO c = new ContactDTO();

        if (contactInfoElement == null) {
            return c;
        }

        Element elem;
        NodeList nodeList;
        elem = ReaderUtils.getChildElement(contactInfoElement,
                "ContactPersonPrimary");

        if (elem != null) {
            c.setContactPerson(ReaderUtils.getChildText(elem, "ContactPerson"));
            c.setContactOrganization(ReaderUtils.getChildText(elem,
                    "ContactOrganization"));
        }

        c.setContactPosition(ReaderUtils.getChildText(contactInfoElement,
                "ContactPosition"));
        elem = ReaderUtils.getChildElement(contactInfoElement, "ContactAddress");

        if (elem != null) {
            c.setAddressType(ReaderUtils.getChildText(elem, "AddressType"));
            c.setAddress(ReaderUtils.getChildText(elem, "Address"));
            c.setAddressCity(ReaderUtils.getChildText(elem, "City"));
            c.setAddressState(ReaderUtils.getChildText(elem, "StateOrProvince"));
            c.setAddressPostalCode(ReaderUtils.getChildText(elem, "PostCode"));
            c.setAddressCountry(ReaderUtils.getChildText(elem, "Country"));
        }

        c.setContactVoice(ReaderUtils.getChildText(contactInfoElement,
                "ContactVoiceTelephone"));
        c.setContactFacsimile(ReaderUtils.getChildText(contactInfoElement,
                "ContactFacsimileTelephone"));
        c.setContactEmail(ReaderUtils.getChildText(contactInfoElement,
                "ContactElectronicMailAddress"));

        return c;
    }

    /**
     * loadWFS purpose.
     *
     * <p>
     * Converts a DOM tree into a WFS object.
     * </p>
     *
     * @param wfsElement a DOM tree to convert into a WFS object.
     *
     * @throws ConfigurationException When an error occurs.
     *
     * @see GlobalData#getBaseUrl()
     */
    protected void loadWFS(Element wfsElement) throws ConfigurationException {
        wfs = new WFSDTO();

        //try {
       
        wfs.setFeatureBounding(ReaderUtils.getBooleanAttribute(
                ReaderUtils.getChildElement(wfsElement, "featureBounding"),
                "value", false, false));

        Element elem = ReaderUtils.getChildElement(wfsElement, "srsXmlStyle",
                false);
        LOGGER.config("reading srsXmlStyle: " + elem);

        if (elem != null) {
            wfs.setSrsXmlStyle(ReaderUtils.getBooleanAttribute(elem, "value",
                    false, true));
            LOGGER.fine("set srsXmlStyle to "
                + ReaderUtils.getBooleanAttribute(elem, "value", false, true));
        }

        String serviceLevelValue = ReaderUtils.getChildText(wfsElement,
                "serviceLevel");
        int serviceLevel = WFSDTO.COMPLETE;

        if ((serviceLevelValue != null) && !serviceLevelValue.equals("")) {
            LOGGER.finer("reading serviceLevel: " + serviceLevelValue);

            if (serviceLevelValue.equalsIgnoreCase("basic")) {
                serviceLevel = WFSDTO.BASIC;
            } else if (serviceLevelValue.equalsIgnoreCase("complete")) {
                serviceLevel = WFSDTO.COMPLETE;
            } else if (serviceLevelValue.equalsIgnoreCase("transactional")) {
                serviceLevel = WFSDTO.TRANSACTIONAL;
            } else {
                try {
                    serviceLevel = Integer.parseInt(serviceLevelValue);
                } catch (NumberFormatException nfe) {
                    String mesg = "Could not parse serviceLevel.  It "
                        + "should be one of Basic, Complete, or Transactional"
                        + " or else an integer value";
                    throw new ConfigurationException(mesg, nfe);
                }
            }
        } else { //TODO: this should probably parse the strings as well,
            serviceLevel = ReaderUtils.getIntAttribute(ReaderUtils
                    .getChildElement(wfsElement, "serviceLevel"), "value",
                    false, WFSDTO.COMPLETE);
        }

        LOGGER.finer("setting service level to " + serviceLevel);
        wfs.setServiceLevel(serviceLevel);

        //get the conformance hacks attribute
        // it might not be there, in which case we just use the default value
        //  (see WFSDTO.java)       
        Element e = ReaderUtils.getChildElement(wfsElement,
                "citeConformanceHacks");

        if (e != null) {
            String text = ReaderUtils.getChildText(wfsElement,
                    "citeConformanceHacks");
            boolean citeConformanceHacks = Boolean.valueOf(text).booleanValue(); // just get the value and parse it
            wfs.setCiteConformanceHacks(citeConformanceHacks);
            LOGGER.finer("setting citeConformanceHacks to "
                + citeConformanceHacks);
        }

        //} catch (Exception e) {
        //}
        ServiceDTO s = loadService(wfsElement);
        wfs.setService(s);
    }

    /**
     * loadWMS purpose.
     *
     * <p>
     * Converts a DOM tree into a WMS object.
     * </p>
     *
     * @param wmsElement a DOM tree to convert into a WMS object.
     *
     * @throws ConfigurationException When an error occurs.
     *
     * @see GlobalData#getBaseUrl()
     */
    protected void loadWMS(Element wmsElement) throws ConfigurationException {
        wms = new WMSDTO();
        wms.setService(loadService(wmsElement));

        wms.setSvgRenderer(ReaderUtils.getChildText(wmsElement, "svgRenderer"));
        wms.setSvgAntiAlias(!"false".equals(ReaderUtils.getChildText(
                    wmsElement, "svgAntiAlias")));
    }

    /**
     * loadService purpose.
     *
     * <p>
     * Converts a DOM tree into a ServiceDTO object.
     * </p>
     *
     * @param serviceRoot a DOM tree to convert into a ServiceDTO object.
     *
     * @return A complete ServiceDTO object loaded from the DOM tree provided.
     *
     * @throws ConfigurationException When an error occurs.
     */
    protected ServiceDTO loadService(Element serviceRoot)
        throws ConfigurationException {
        ServiceDTO s = new ServiceDTO();

        s.setName(ReaderUtils.getChildText(serviceRoot, "name", true));
        s.setTitle(ReaderUtils.getChildText(serviceRoot, "title", false));
        s.setAbstract(ReaderUtils.getChildText(serviceRoot, "abstract"));
        s.setKeywords(ReaderUtils.getKeyWords(ReaderUtils.getChildElement(
                    serviceRoot, "keywords")));
        s.setFees(ReaderUtils.getChildText(serviceRoot, "fees"));
        s.setAccessConstraints(ReaderUtils.getChildText(serviceRoot,
                "accessConstraints"));
        s.setMaintainer(ReaderUtils.getChildText(serviceRoot, "maintainer"));
        s.setEnabled(ReaderUtils.getBooleanAttribute(serviceRoot, "enabled",
                false, true));

        try {
            s.setOnlineResource(new URL(ReaderUtils.getChildText(serviceRoot,
                        "onlineResource", true)));
        } catch (MalformedURLException e) {
            throw new ConfigurationException(e);
        }

        return s;
    }

    /**
     * loadNameSpaces purpose.
     *
     * <p>
     * Converts a DOM tree into a Map of NameSpaces.
     * </p>
     *
     * @param nsRoot a DOM tree to convert into a Map of NameSpaces.
     *
     * @return A complete Map of NameSpaces loaded from the DOM tree provided.
     *
     * @throws ConfigurationException When an error occurs.
     */
    protected Map loadNameSpaces(Element nsRoot) throws ConfigurationException {
        NodeList nsList = nsRoot.getElementsByTagName("namespace");
        Element elem;
        int nsCount = nsList.getLength();
        Map nameSpaces = new HashMap(nsCount);

        for (int i = 0; i < nsCount; i++) {
            elem = (Element) nsList.item(i);

            NameSpaceInfoDTO ns = new NameSpaceInfoDTO();
            ns.setUri(ReaderUtils.getAttribute(elem, "uri", true));
            ns.setPrefix(ReaderUtils.getAttribute(elem, "prefix", true));
            ns.setDefault(ReaderUtils.getBooleanAttribute(elem, "default",
                    false, false) || (nsCount == 1));
            LOGGER.config("added namespace " + ns);
            nameSpaces.put(ns.getPrefix(), ns);
        }

        return nameSpaces;
    }

    /**
     * loadStyles purpose.
     *
     * <p>
     * Converts a DOM tree into a Map of Styles.
     * </p>
     *
     * @param stylesElem a DOM tree to convert into a Map of Styles.
     * @param baseDir DOCUMENT ME!
     *
     * @return A complete Map of Styles loaded from the DOM tree provided.
     *
     * @throws ConfigurationException When an error occurs.
     */
    protected Map loadStyles(Element stylesElem, File baseDir)
       throws ConfigurationException {
        Map styles = new HashMap();

        NodeList stylesList = null;

        if (stylesElem != null) {
            stylesList = stylesElem.getElementsByTagName("style");
        }

        if ((stylesList == null) || (stylesList.getLength() == 0)) {
            //no styles where defined, just add a default one
            StyleDTO s = new StyleDTO();
            s.setId("normal");
            s.setFilename(new File(baseDir, "normal.sld"));
            s.setDefault(true);
            styles.put("normal", s);
        }

        int styleCount = stylesList.getLength();
        Element styleElem;

        for (int i = 0; i < styleCount; i++) {
            styleElem = (Element) stylesList.item(i);

            StyleDTO s = new StyleDTO();
            s.setId(ReaderUtils.getAttribute(styleElem, "id", true));
            s.setFilename(new File(baseDir,
                    ReaderUtils.getAttribute(styleElem, "filename", true)));
            s.setDefault(ReaderUtils.getBooleanAttribute(styleElem, "default",
                    false, false));
            styles.put(s.getId(), s);
           
            LOGGER.config("Loaded style " + s.getId());
        }

        return styles;
    }

    /**
     * loadDataStores purpose.
     *
     * <p>
     * Converts a DOM tree into a Map of DataStores.
     * </p>
     *
     * @param dsRoot a DOM tree to convert into a Map of DataStores.
     *
     * @return A complete Map of DataStores loaded from the DOM tree provided.
     *
     * @throws ConfigurationException When an error occurs.
     */
    protected Map loadDataStores(Element dsRoot) throws ConfigurationException {
        Map dataStores = new HashMap();

        NodeList dsElements = dsRoot.getElementsByTagName("datastore");
        int dsCnt = dsElements.getLength();
        DataStoreInfoDTO dsConfig;
        Element dsElem;

        for (int i = 0; i < dsCnt; i++) {
            dsElem = (Element) dsElements.item(i);
            dsConfig = loadDataStore(dsElem);

            if (dataStores.containsKey(dsConfig.getId())) {
                throw new ConfigurationException("duplicated datastore id: "
                    + data.getNameSpaces().get(dsConfig.getNameSpaceId()));
            }

            dataStores.put(dsConfig.getId(), dsConfig);
        }

        return dataStores;
    }

    /**
     * loadDataStore purpose.
     *
     * <p>
     * Converts a DOM tree into a DataStoreInfo object.
     * </p>
     *
     * @param dsElem a DOM tree to convert into a DataStoreInfo object.
     *
     * @return A complete DataStoreInfo object loaded from the DOM tree
     *         provided.
     *
     * @throws ConfigurationException When an error occurs.
     */
    protected DataStoreInfoDTO loadDataStore(Element dsElem)
        throws ConfigurationException {
        DataStoreInfoDTO ds = new DataStoreInfoDTO();

        LOGGER.finer("creating a new DataStoreDTO configuration");
        ds.setId(ReaderUtils.getAttribute(dsElem, "id", true));

        String namespacePrefix = ReaderUtils.getAttribute(dsElem, "namespace",
                true);

        if (data.getNameSpaces().containsKey(namespacePrefix)) {
            ds.setNameSpaceId(namespacePrefix);
        } else {
            String msg = "there is no namespace defined for datatasore '"
                + namespacePrefix + "'";
            throw new ConfigurationException(msg);
        }

        ds.setEnabled(ReaderUtils.getBooleanAttribute(dsElem, "enabled", false,
                true));
        ds.setTitle(ReaderUtils.getChildText(dsElem, "title", false));
        ds.setAbstract(ReaderUtils.getChildText(dsElem, "description", false));
        LOGGER.finer("loading connection parameters for DataStoreDTO "
            + ds.getNameSpaceId());
        ds.setConnectionParams(loadConnectionParams(ReaderUtils.getChildElement(
                    dsElem, "connectionParams", true)));

        LOGGER.config("Loaded datastore " + ds.getId());
        return ds;
    }

    /**
     * loadConnectionParams purpose.
     *
     * <p>
     * Converts a DOM tree into a Map of Strings which represent connection
     * parameters.
     * </p>
     *
     * @param connElem a DOM tree to convert into a Map of Strings which
     *        represent connection parameters.
     *
     * @return A complete Map of Strings which represent connection parameters
     *         loaded from the DOM tree provided.
     *
     * @throws ConfigurationException When an error occurs.
     */
    protected Map loadConnectionParams(Element connElem)
        throws ConfigurationException {
        Map connectionParams = new HashMap();

        NodeList paramElems = connElem.getElementsByTagName("parameter");
        int pCount = paramElems.getLength();
        Element param;
        String paramKey;
        String paramValue;

        for (int i = 0; i < pCount; i++) {
            param = (Element) paramElems.item(i);
            paramKey = ReaderUtils.getAttribute(param, "name", true);
            paramValue = ReaderUtils.getAttribute(param, "value", false);
            connectionParams.put(paramKey, paramValue);
            LOGGER.finer("added parameter " + paramKey + ": '" + paramValue
                + "'");
        }

        return connectionParams;
    }

    /**
     * Load map of FeatureTypeDTO instances from a directory.
     *
     * <p>
     * Expected directory structure:
     * </p>
     *
     * <ul>
     * <li>
     * rootDir/
     * </li>
     * <li>
     * rootDir/featureType1/info.xml - required
     * </li>
     * <li>
     * rootDir/featureType1/schema.xml - optional
     * </li>
     * <li>
     * rootDir/featureType2/info.xml - required
     * </li>
     * <li>
     * rootDir/featureType2/schema.xml - optional
     * </li>
     * </ul>
     *
     * <p>
     * If a schema.xml file is not used, the information may be generated from
     * a FeatureType using DataTransferObjectFactory.
     * </p>
     *
     * @param featureTypeRoot Root FeatureType directory
     *
     * @return Map of FeatureTypeInfoDTO by <code>dataStoreId:typeName</code>
     *
     * @throws ConfigurationException When an error occurs.
     * @throws IllegalArgumentException DOCUMENT ME!
     */
    protected Map loadFeatureTypes(File featureTypeRoot)
        throws ConfigurationException {
        LOGGER.finest("examining: " + featureTypeRoot.getAbsolutePath());
        LOGGER.finest("is dir: " + featureTypeRoot.isDirectory());

        if (!featureTypeRoot.isDirectory()) {
            throw new IllegalArgumentException(
                "featureTypeRoot must be a directoy");
        }

        File[] directories = featureTypeRoot.listFiles(new FileFilter() {
                    public boolean accept(File pathname) {
                        return pathname.isDirectory();
                    }
                });

        Map map = new HashMap();

        for (int i = 0, n = directories.length; i < n; i++) {
            File info = new File(directories[i], "info.xml");

            if (info.exists() && info.isFile()) {
                LOGGER.finer("Info dir:" + info);

                FeatureTypeInfoDTO dto = loadFeature(info);
                map.put(dto.getKey(), dto);
            }
        }

        return map;
    }

    /**
     * Load FeatureTypeInfoDTO from a directory.
     *
     * <p>
     * Expected directory structure:
     * </p>
     *
     * <ul>
     * <li>
     * info.xml - required
     * </li>
     * <li>
     * schema.xml - optional
     * </li>
     * </ul>
     *
     * <p>
     * If a schema.xml file is not used, the information may be generated from
     * a FeatureType using DataTransferObjectFactory.
     * </p>
     *
     * @param infoFile a File to convert into a FeatureTypeInfo object.
     *        (info.xml)
     *
     * @return A complete FeatureTypeInfo object loaded from the File handle
     *         provided.
     *
     * @throws ConfigurationException When an error occurs.
     * @throws IllegalArgumentException DOCUMENT ME!
     *
     * @see loadFeaturePt2(Element)
     */
    protected FeatureTypeInfoDTO loadFeature(File infoFile)
        throws ConfigurationException {
        if (!infoFile.exists()) {
            throw new IllegalArgumentException("Info File not found:"
                + infoFile);
        }

        if (!infoFile.isFile()) {
            throw new IllegalArgumentException("Info file is the wrong type:"
                + infoFile);
        }

        if (!isInfoFile(infoFile)) {
            throw new IllegalArgumentException("Info File not valid:"
                + infoFile);
        }

        Element featureElem = null;

        try {
          LOGGER.config("Loading configuration file: " + infoFile);
            Reader reader = null;
            reader = new FileReader(infoFile);
            featureElem = ReaderUtils.loadConfig(reader);
            reader.close();
        } catch (FileNotFoundException fileNotFound) {
            throw new ConfigurationException("Could not read info file:"
                + infoFile, fileNotFound);
        } catch (Exception erk) {
            throw new ConfigurationException("Could not parse info file:"
                + infoFile, erk);
        }

        FeatureTypeInfoDTO dto = loadFeaturePt2(featureElem);

        File parentDir = infoFile.getParentFile();
        dto.setDirName(parentDir.getName());

        List attributeList;

        File schemaFile = new File(parentDir, "schema.xml");

        if (schemaFile.exists() && schemaFile.isFile()) {
            // attempt to load optional schema information
            //
            LOGGER.finest("process schema file " + infoFile);

            try {
                loadSchema(schemaFile, dto);
            } catch (Exception badDog) {
                badDog.printStackTrace();
                attributeList = Collections.EMPTY_LIST;
            }
        } else {
            dto.setSchemaAttributes(Collections.EMPTY_LIST);
        }

        LOGGER.config("added featureType " + dto.getName());

        return dto;
    }

    /**
     * loadFeaturePt2 purpose.
     *
     * <p>
     * Converts a DOM tree into a FeatureTypeInfo object.
     * </p>
     *
     * @param fTypeRoot a DOM tree to convert into a FeatureTypeInfo object.
     *
     * @return A complete FeatureTypeInfo object loaded from the DOM tree
     *         provided.
     *
     * @throws ConfigurationException When an error occurs.
     */
    protected FeatureTypeInfoDTO loadFeaturePt2(Element fTypeRoot)
        throws ConfigurationException {
        FeatureTypeInfoDTO ft = new FeatureTypeInfoDTO();

        ft.setName(ReaderUtils.getChildText(fTypeRoot, "name", true));
        ft.setTitle(ReaderUtils.getChildText(fTypeRoot, "title", true));
        ft.setAbstract(ReaderUtils.getChildText(fTypeRoot, "abstract"));

        String keywords = ReaderUtils.getChildText(fTypeRoot, "keywords");

        if (keywords != null) {
            List l = new LinkedList();
            String[] ss = keywords.split(",");

            for (int i = 0; i < ss.length; i++)
                l.add(ss[i].trim());

            ft.setKeywords(l);
        }

        ft.setDataStoreId(ReaderUtils.getAttribute(fTypeRoot, "datastore", true));
        ft.setSRS(Integer.parseInt(ReaderUtils.getChildText(fTypeRoot, "SRS",
                    true)));

        Element tmp = ReaderUtils.getChildElement(fTypeRoot, "styles");

        if (tmp != null) {
            ft.setDefaultStyle(ReaderUtils.getAttribute(tmp, "default", false));
        }

        // Modif C. Kolbowicz - 06/10/2004
        Element legendURL = ReaderUtils.getChildElement(fTypeRoot, "LegendURL");

        if (legendURL != null) {
            LegendURLDTO legend = new LegendURLDTO();
            legend.setWidth(Integer.parseInt(ReaderUtils.getAttribute(
                        legendURL, "width", true)));
            legend.setHeight(Integer.parseInt(ReaderUtils.getAttribute(
                        legendURL, "height", true)));
            legend.setFormat(ReaderUtils.getChildText(legendURL, "Format", true));
            legend.setOnlineResource(ReaderUtils.getAttribute(
                    ReaderUtils.getChildElement(legendURL, "OnlineResource",
                        true), "xlink:href", true));
            ft.setLegendURL(legend);
        }

        //-- Modif C. Kolbowicz - 06/10/2004
        ft.setLatLongBBox(loadLatLongBBox(ReaderUtils.getChildElement(
                    fTypeRoot, "latLonBoundingBox")));

        Element numDecimalsElem = ReaderUtils.getChildElement(fTypeRoot,
                "numDecimals", false);

        if (numDecimalsElem != null) {
            ft.setNumDecimals(ReaderUtils.getIntAttribute(numDecimalsElem,
                    "value", false, 8));
        }

        ft.setDefinitionQuery(loadDefinitionQuery(fTypeRoot));

        return ft;
    }

    /**
     * getKeyWords purpose.
     *
     * <p>
     * Converts a DOM tree into a List of Strings representing keywords.
     * </p>
     *
     * @param keywordsElem a DOM tree to convert into a List of Strings
     *        representing keywords.
     *
     * @return A complete List of Strings representing keywords loaded from the
     *         DOM tree provided.
     */
    protected List getKeyWords(Element keywordsElem) {
        NodeList klist = keywordsElem.getElementsByTagName("keyword");
        int kCount = klist.getLength();
        List keywords = new LinkedList();
        String kword;
        Element kelem;

        for (int i = 0; i < kCount; i++) {
            kelem = (Element) klist.item(i);
            kword = ReaderUtils.getElementText(kelem);

            if (kword != null) {
                keywords.add(kword);
            }
        }

        return keywords;
    }

    /**
     * loadLatLongBBox purpose.
     *
     * <p>
     * Converts a DOM tree into a Envelope object.
     * </p>
     *
     * @param bboxElem a DOM tree to convert into a Envelope object.
     *
     * @return A complete Envelope object loaded from the DOM tree provided.
     *
     * @throws ConfigurationException When an error occurs.
     */
    protected Envelope loadLatLongBBox(Element bboxElem)
        throws ConfigurationException {
        if (bboxElem == null) {
            return new Envelope();
        }

        boolean dynamic = ReaderUtils.getBooleanAttribute(bboxElem, "dynamic",
                false, true);

        if (!dynamic) {
            double minx = ReaderUtils.getDoubleAttribute(bboxElem, "minx", true);
            double miny = ReaderUtils.getDoubleAttribute(bboxElem, "miny", true);
            double maxx = ReaderUtils.getDoubleAttribute(bboxElem, "maxx", true);
            double maxy = ReaderUtils.getDoubleAttribute(bboxElem, "maxy", true);

            return new Envelope(minx, maxx, miny, maxy);
        }

        return new Envelope();
    }

    /**
     * loadDefinitionQuery purpose.
     *
     * <p>
     * Converts a DOM tree into a Filter object.
     * </p>
     *
     * @param typeRoot a DOM tree to convert into a Filter object.
     *
     * @return A complete Filter object loaded from the DOM tree provided.
     *
     * @throws ConfigurationException When an error occurs.
     */
    protected org.geotools.filter.Filter loadDefinitionQuery(Element typeRoot)
        throws ConfigurationException {
        Element defQNode = ReaderUtils.getChildElement(typeRoot,
                "definitionQuery", false);
        org.geotools.filter.Filter filter = null;

        if (defQNode != null) {
            LOGGER.finer("definitionQuery element found, looking for Filter");

            Element filterNode = ReaderUtils.getChildElement(defQNode,
                    "Filter", false);

            if ((filterNode != null)
                    && ((filterNode = ReaderUtils.getFirstChildElement(
                            filterNode)) != null)) {
                filter = FilterDOMParser.parseFilter(filterNode);

                return filter;
            }

            LOGGER.finer("No Filter definition query found");
        }

        return filter;
    }

    /**
     * isInfoFile purpose.
     *
     * <p>
     * Used to perform safety checks on info.xml file handles.
     * </p>
     *
     * @param testFile The file to test.
     *
     * @return true if the file is an info.xml file.
     */
    protected static boolean isInfoFile(File testFile) {
        String testName = testFile.getAbsolutePath();

        int start = testName.length() - "info.xml".length();
        int end = testName.length();

        return testName.substring(start, end).equals("info.xml");
    }

    /**
     * Process schema File for a list of AttributeTypeInfoDTO.
     *
     * <p>
     * The provided FeatureTypeInfoDTO will be updated with the schemaBase.
     * </p>
     *
     * @param schemaFile File containing schema definition
     * @param dto Schema DOM element
     *
     * @throws ConfigurationException
     */
    protected void loadSchema(File schemaFile, FeatureTypeInfoDTO dto)
        throws ConfigurationException {
        schemaFile = ReaderUtils.checkFile(schemaFile, false);

        Element elem = null;
        dto.setSchemaFile(schemaFile);

        if ((schemaFile == null)
                || (!schemaFile.exists() || !schemaFile.canRead())) {
            System.err.println("File does not exist for schema for "
                + dto.getName());

            return;
        }

        try {
          LOGGER.config("Loading configuration file: " + schemaFile);
            Reader reader;
            reader = new FileReader(schemaFile);
            elem = ReaderUtils.loadConfig(reader);
            reader.close();
        } catch (FileNotFoundException e) {
            LOGGER.log(Level.FINEST, e.getMessage(), e);
            throw new ConfigurationException("Could not open schema file:"
                + schemaFile, e);
        } catch (Exception erk) {
            throw new ConfigurationException("Could not parse schema file:"
                + schemaFile, erk);
        }

        try {
            processSchema(elem, dto);
        } catch (ConfigurationException e) {
            throw new ConfigurationException("Error occured in " + schemaFile
                + "\n" + e.getMessage(), e);
        }
    }

    /**
     * Process schema DOM for a list of AttributeTypeInfoDTO.
     *
     * <p>
     * The provided FeatureTypeInfoDTO will be updated with the schemaBase.
     * </p>
     *
     * @param elem Schema DOM element
     * @param featureTypeInfoDTO
     *
     * @throws ConfigurationException
     */
    public static void processSchema(Element elem,
        FeatureTypeInfoDTO featureTypeInfoDTO) throws ConfigurationException {
        ArrayList list = new ArrayList();

        featureTypeInfoDTO.setSchemaName(ReaderUtils.getAttribute(elem, "name",
                true));

        elem = ReaderUtils.getChildElement(elem, "xs:complexContent");
        elem = ReaderUtils.getChildElement(elem, "xs:extension");

        NameSpaceTranslator gml = NameSpaceTranslatorFactory.getInstance()
                                                            .getNameSpaceTranslator("gml");
        NameSpaceElement nse = gml.getElement(ReaderUtils.getAttribute(elem,
                    "base", true));
        featureTypeInfoDTO.setSchemaBase(nse.getTypeDefName());
        elem = ReaderUtils.getChildElement(elem, "xs:sequence");

        NodeList nl = elem.getElementsByTagName("xs:element");

        for (int i = 0; i < nl.getLength(); i++) {
            // one element now
            elem = (Element) nl.item(i);

            AttributeTypeInfoDTO ati = new AttributeTypeInfoDTO();
            String name = ReaderUtils.getAttribute(elem, "name", false);
            String ref = ReaderUtils.getAttribute(elem, "ref", false);
            String type = ReaderUtils.getAttribute(elem, "type", false);

            NameSpaceTranslator nst1 = NameSpaceTranslatorFactory.getInstance()
                                                                 .getNameSpaceTranslator("xs");
            NameSpaceTranslator nst2 = NameSpaceTranslatorFactory.getInstance()
                                                                 .getNameSpaceTranslator("gml");

            if ((ref != null) && (ref != "")) {
                ati.setComplex(false);
                nse = nst1.getElement(ref);

                if (nse == null) {
                    nse = nst2.getElement(ref);
                }

                String tmp = nse.getTypeRefName();

                //tmp = Character.toLowerCase(tmp.charAt(0)) + tmp.substring(1);
                ati.setType(tmp);
                ati.setName(tmp);
            } else {
                ati.setName(name);

                if ((type != null) && (type != "")) {
                    nse = nst1.getElement(type);

                    if (nse == null) {
                        nse = nst2.getElement(type);
                    }

                    String tmp = nse.getTypeRefName();

                    ati.setType(tmp);
                    ati.setComplex(false);
                } else {
                    Element tmp = ReaderUtils.getFirstChildElement(elem);
                    OutputFormat format = new OutputFormat(tmp.getOwnerDocument());
                    format.setLineSeparator(LineSeparator.Windows);
                    format.setIndenting(true);
                    format.setLineWidth(0);
                    format.setPreserveSpace(true);

                    StringWriter sw = new StringWriter();
                    XMLSerializer serializer = new XMLSerializer(sw, format);

                    try {
                        serializer.asDOMSerializer();
                        serializer.serialize(tmp);
                    } catch (IOException e) {
                        throw new ConfigurationException(e);
                    }

                    ati.setType(elem.toString());
                    ati.setComplex(true);
                }
            }

            ati.setNillable(ReaderUtils.getBooleanAttribute(elem, "nillable",
                    false, true));
            ati.setMaxOccurs(ReaderUtils.getIntAttribute(elem, "maxOccurs",
                    false, 1));
            ati.setMinOccurs(ReaderUtils.getIntAttribute(elem, "minOccurs",
                    false, 1));
            list.add(ati);
        }

        featureTypeInfoDTO.setSchemaAttributes(list);
    }

    /**
     * getData purpose.
     *
     * <p>
     * Description ...
     * </p>
     *
     * @return
     */
    public DataDTO getData() {
        return data;
    }

    /**
     * getGeoServer purpose.
     *
     * <p>
     * Description ...
     * </p>
     *
     * @return
     */
    public GeoServerDTO getGeoServer() {
        return geoServer;
    }

    /**
     * getWfs purpose.
     *
     * <p>
     * Description ...
     * </p>
     *
     * @return
     */
    public WFSDTO getWfs() {
        return wfs;
    }

    /**
     * getWms purpose.
     *
     * <p>
     * Description ...
     * </p>
     *
     * @return
     */
    public WMSDTO getWms() {
        return wms;
    }
}
TOP

Related Classes of org.vfny.geoserver.global.xml.XMLConfigReader

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.