org.geotools.data.complex.config.XMLConfigDigester.java Source code

Java tutorial

Introduction

Here is the source code for org.geotools.data.complex.config.XMLConfigDigester.java

Source

/*
 *    GeoTools - The Open Source Java GIS Toolkit
 *    http://geotools.org
 *
 *    (C) 2007-2011, Open Source Geospatial Foundation (OSGeo)
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation;
 *    version 2.1 of the License.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 */

package org.geotools.data.complex.config;

import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.apache.commons.digester.Digester;
import org.geotools.data.complex.AppSchemaDataAccessFactory;
import org.geotools.data.complex.AppSchemaDataAccessRegistry;
import org.geotools.util.InterpolationProperties;
import org.xml.sax.SAXException;

/**
 * Digester to consume the app-schema {@link AppSchemaDataAccessFactory} configuration file.
 * 
 * @author Gabriel Roldan (Axios Engineering)
 * @author Rini Angreani (CSIRO Earth Science and Resource Engineering)
 * @author Ben Caradoc-Davies (CSIRO Earth Science and Resource Engineering)
 * @author Russell Petty (GeoScience Victoria)
 * @version $Id$
 *
 *
 *
 * @source $URL$
 * @since 2.4
 */
public class XMLConfigDigester {
    /** DOCUMENT ME! */
    private static final Logger LOGGER = org.geotools.util.logging.Logging
            .getLogger(XMLConfigDigester.class.getPackage().getName());

    /** Namespace URI for the AppSchemaDataAccess configuration files */
    private static final String CONFIG_NS_URI = "http://www.geotools.org/app-schema";

    /** 
     * Properties
     */
    protected InterpolationProperties properties;

    /**
     * Creates a new XMLConfigReader object.
     */
    public XMLConfigDigester() {
        this(AppSchemaDataAccessRegistry.getAppSchemaProperties());
    }

    /**
     * Creates a new XMLConfigReader object.
     * 
     * @param properties Properties to use for interpolation
     */
    public XMLConfigDigester(InterpolationProperties properties) {
        this.properties = properties;
    }

    /**
     * Parses a complex datastore configuration file in xml format into a
     * {@link AppSchemaDataAccessDTO}
     * 
     * @param dataStoreConfigUrl
     *            config file location
     * 
     * @return a DTO object representing the datastore's configuration
     * 
     * @throws IOException
     *             if an error occurs parsing the file
     */
    public AppSchemaDataAccessDTO parse(URL dataStoreConfigUrl) throws IOException {
        AppSchemaDataAccessDTO config = digest(dataStoreConfigUrl);
        return config;
    }

    /**
     * DOCUMENT ME!
     * 
     * @param dataStoreConfigUrl
     *            DOCUMENT ME!
     * 
     * @return DOCUMENT ME!
     * 
     * @throws IOException
     *             DOCUMENT ME!
     * @throws NullPointerException
     *             DOCUMENT ME!
     */
    private AppSchemaDataAccessDTO digest(final URL dataStoreConfigUrl) throws IOException {
        if (dataStoreConfigUrl == null) {
            throw new NullPointerException("datastore config url");
        }

        // read mapping file into configString and interpolate properties
        InputStream configStream = null;
        String configString = null;
        try {
            configStream = dataStoreConfigUrl.openStream();
            if (configStream == null) {
                throw new IOException("Can't open datastore config file " + dataStoreConfigUrl);
            } else {
                configString = properties.interpolate(InterpolationProperties.readAll(configStream));
            }
        } finally {
            if (configStream != null) {
                configStream.close();
            }
        }

        XMLConfigDigester.LOGGER.fine("parsing complex datastore config: " + dataStoreConfigUrl.toExternalForm());

        Digester digester = new Digester();
        XMLConfigDigester.LOGGER.fine("digester created");
        // URL schema = getClass()
        // .getResource("../test-data/AppSchemaDataAccess.xsd");
        // digester.setSchema(schema.toExternalForm());
        digester.setValidating(false);
        digester.setNamespaceAware(true);
        digester.setRuleNamespaceURI(XMLConfigDigester.CONFIG_NS_URI);

        // digester.setRuleNamespaceURI(OGC_NS_URI);
        AppSchemaDataAccessDTO configDto = new AppSchemaDataAccessDTO();
        configDto.setBaseSchemasUrl(dataStoreConfigUrl.toExternalForm());

        digester.push(configDto);

        try {
            setNamespacesRules(digester);

            setIncludedTypesRules(digester);

            setSourceDataStoresRules(digester);

            setTargetSchemaUriRules(digester);

            setTypeMappingsRules(digester);

        } catch (Exception e) {
            e.printStackTrace();
            XMLConfigDigester.LOGGER.log(Level.SEVERE, "setting digester properties: ", e);
            throw new IOException("Error setting digester properties: " + e.getMessage());
        }

        try {
            digester.parse(new StringReader(configString));
        } catch (SAXException e) {
            e.printStackTrace();
            XMLConfigDigester.LOGGER.log(Level.SEVERE, "parsing " + dataStoreConfigUrl, e);

            IOException ioe = new IOException("Can't parse complex datastore config. ");
            ioe.initCause(e);
            throw ioe;
        }

        AppSchemaDataAccessDTO config = (AppSchemaDataAccessDTO) digester.getRoot();

        return config;
    }

    private void setTypeMappingsRules(Digester digester) {
        final String mappings = "AppSchemaDataAccess/typeMappings";
        digester.addObjectCreate(mappings, XMLConfigDigester.CONFIG_NS_URI, HashSet.class);

        final String typeMapping = mappings + "/FeatureTypeMapping";

        digester.addObjectCreate(typeMapping, XMLConfigDigester.CONFIG_NS_URI, TypeMapping.class);
        digester.addCallMethod(typeMapping + "/mappingName", "setMappingName", 1);
        digester.addCallParam(typeMapping + "/mappingName", 0);
        digester.addCallMethod(typeMapping + "/sourceDataStore", "setSourceDataStore", 1);
        digester.addCallParam(typeMapping + "/sourceDataStore", 0);
        digester.addCallMethod(typeMapping + "/sourceType", "setSourceTypeName", 1);
        digester.addCallParam(typeMapping + "/sourceType", 0);
        digester.addCallMethod(typeMapping + "/targetElement", "setTargetElementName", 1);
        digester.addCallParam(typeMapping + "/targetElement", 0);
        digester.addCallMethod(typeMapping + "/itemXpath", "setItemXpath", 1);
        digester.addCallParam(typeMapping + "/itemXpath", 0);

        // isXmlDataStore is a flag to denote that AppSchema needs to process
        // the data from the datastore differently as it returns xml rather than features.
        digester.addCallMethod(typeMapping + "/isXmlDataStore", "setXmlDataStore", 1);
        digester.addCallParam(typeMapping + "/isXmlDataStore", 0);

        // create attribute mappings
        final String attMappings = typeMapping + "/attributeMappings";
        digester.addObjectCreate(attMappings, XMLConfigDigester.CONFIG_NS_URI, ArrayList.class);

        final String attMap = attMappings + "/AttributeMapping";
        digester.addObjectCreate(attMap, XMLConfigDigester.CONFIG_NS_URI, AttributeMapping.class);

        digester.addCallMethod(attMap + "/label", "setLabel", 1);
        digester.addCallParam(attMap + "/label", 0);

        digester.addCallMethod(attMap + "/parentLabel", "setParentLabel", 1);
        digester.addCallParam(attMap + "/parentLabel", 0);

        digester.addCallMethod(attMap + "/targetQueryString", "setTargetQueryString", 1);
        digester.addCallParam(attMap + "/targetQueryString", 0);

        digester.addCallMethod(attMap + "/instancePath", "setInstancePath", 1);
        digester.addCallParam(attMap + "/instancePath", 0);

        digester.addCallMethod(attMap + "/isMultiple", "setMultiple", 1);
        digester.addCallParam(attMap + "/isMultiple", 0);

        digester.addCallMethod(attMap + "/encodeIfEmpty", "setEncodeIfEmpty", 1);
        digester.addCallParam(attMap + "/encodeIfEmpty", 0);

        digester.addCallMethod(attMap + "/isList", "setList", 1);
        digester.addCallParam(attMap + "/isList", 0);

        digester.addCallMethod(attMap + "/targetAttribute", "setTargetAttributePath", 1);
        digester.addCallParam(attMap + "/targetAttribute", 0);

        digester.addCallMethod(attMap + "/targetAttributeNode", "setTargetAttributeSchemaElement", 1);
        digester.addCallParam(attMap + "/targetAttributeNode", 0);

        digester.addCallMethod(attMap + "/idExpression/OCQL", "setIdentifierExpression", 1);
        digester.addCallParam(attMap + "/idExpression/OCQL", 0);

        digester.addCallMethod(attMap + "/sourceExpression/OCQL", "setSourceExpression", 1);
        digester.addCallParam(attMap + "/sourceExpression/OCQL", 0);

        digester.addCallMethod(attMap + "/sourceExpression/index", "setSourceIndex", 1);
        digester.addCallParam(attMap + "/sourceExpression/index", 0);

        digester.addCallMethod(attMap + "/idExpression/inputAttribute", "setIdentifierPath", 1);
        digester.addCallParam(attMap + "/idExpression/inputAttribute", 0);

        // if the source is a data access, then the input is in XPath expression
        digester.addCallMethod(attMap + "/sourceExpression/inputAttribute", "setInputAttributePath", 1);
        digester.addCallParam(attMap + "/sourceExpression/inputAttribute", 0);

        // for feature chaining: this refers to the nested feature type
        digester.addCallMethod(attMap + "/sourceExpression/linkElement", "setLinkElement", 1);
        digester.addCallParam(attMap + "/sourceExpression/linkElement", 0);

        // for feature chaining: this refers to the nested feature attribute
        digester.addCallMethod(attMap + "/sourceExpression/linkField", "setLinkField", 1);
        digester.addCallParam(attMap + "/sourceExpression/linkField", 0);

        digester.addCallMethod(attMap + "/ClientProperty", "putClientProperty", 2);
        digester.addCallParam(attMap + "/ClientProperty/name", 0);
        digester.addCallParam(attMap + "/ClientProperty/value", 1);

        // add the AttributeMapping to the list
        digester.addSetNext(attMap, "add");

        // set attribute mappings
        digester.addSetNext(attMappings, "setAttributeMappings");

        // add the TypeMapping to the Set
        digester.addSetNext(typeMapping, "add");

        // set the TypeMapping on AppSchemaDataAccessDTO
        digester.addSetNext(mappings, "setTypeMappings");
    }

    private void setTargetSchemaUriRules(Digester digester) {
        final String targetSchemas = "AppSchemaDataAccess/targetTypes";

        digester.addBeanPropertySetter("AppSchemaDataAccess/catalog");
        // digester.addCallMethod(targetSchemas + "/Catalog", "setCatalog", 1);
        // digester.addCallParam(targetSchemas + "/Catalog", 0);

        digester.addObjectCreate(targetSchemas, XMLConfigDigester.CONFIG_NS_URI, ArrayList.class);

        final String schema = targetSchemas + "/FeatureType/schemaUri";
        digester.addCallMethod(schema, "add", 1);
        digester.addCallParam(schema, 0);
        // set the list of XSD file uris on AppSchemaDataAccessDTO
        digester.addSetNext(targetSchemas, "setTargetSchemasUris");
    }

    private void setSourceDataStoresRules(Digester digester) {
        final String dataStores = "AppSchemaDataAccess/sourceDataStores";
        digester.addObjectCreate(dataStores, XMLConfigDigester.CONFIG_NS_URI, ArrayList.class);

        // create a SourceDataStore for each DataStore tag
        digester.addObjectCreate(dataStores + "/DataStore", XMLConfigDigester.CONFIG_NS_URI, SourceDataStore.class);
        digester.addCallMethod(dataStores + "/DataStore/id", "setId", 1);
        digester.addCallParam(dataStores + "/DataStore/id", 0);

        digester.addObjectCreate(dataStores + "/DataStore/parameters", XMLConfigDigester.CONFIG_NS_URI,
                HashMap.class);
        digester.addCallMethod(dataStores + "/DataStore/parameters/Parameter", "put", 2);
        digester.addCallParam(dataStores + "/DataStore/parameters/Parameter/name", 0);
        digester.addCallParam(dataStores + "/DataStore/parameters/Parameter/value", 1);
        digester.addSetNext(dataStores + "/DataStore/parameters", "setParams");

        // isDataAccess is a flag to denote that we want to connect to the data access
        // that is connected to the data store specified
        digester.addCallMethod(dataStores + "/DataStore/isDataAccess", "setDataAccess", 1);
        digester.addCallParam(dataStores + "/DataStore/isDataAccess", 0);

        // add the SourceDataStore to the list
        digester.addSetNext(dataStores + "/DataStore", "add");

        // set the list of SourceDataStores for ComlexDataStoreDTO
        digester.addSetNext(dataStores, "setSourceDataStores");
    }

    private void setNamespacesRules(Digester digester) {
        final String ns = "AppSchemaDataAccess/namespaces";
        digester.addObjectCreate(ns, XMLConfigDigester.CONFIG_NS_URI, HashMap.class);
        digester.addCallMethod(ns + "/Namespace", "put", 2);
        digester.addCallParam(ns + "/Namespace/prefix", 0);
        digester.addCallParam(ns + "/Namespace/uri", 1);
        digester.addSetNext(ns, "setNamespaces");
    }

    private void setIncludedTypesRules(Digester digester) {
        final String includes = "AppSchemaDataAccess/includedTypes";
        digester.addObjectCreate(includes, XMLConfigDigester.CONFIG_NS_URI, ArrayList.class);
        // point to related type config path relative to this mapping file location
        final String includePath = includes + "/Include";
        digester.addCallMethod(includePath, "add", 1);
        digester.addCallParam(includePath, 0);
        digester.addSetNext(includes, "setIncludedTypes");
    }
}