Package org.geotools.data.complex

Source Code of org.geotools.data.complex.XmlFeatureTypeMapping

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2009-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;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
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 org.geotools.data.FeatureSource;
import org.geotools.data.complex.PathAttributeList.Pair;
import org.geotools.data.complex.filter.XPathUtil.Step;
import org.geotools.data.complex.filter.XPathUtil.StepList;
import org.geotools.data.complex.xml.XmlFeatureSource;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.filter.LiteralExpressionImpl;
import org.opengis.feature.Attribute;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.Name;
import org.opengis.filter.FilterFactory;
import org.opengis.filter.expression.Expression;
import org.opengis.filter.expression.Function;
import org.opengis.filter.expression.PropertyName;
import org.xml.sax.helpers.NamespaceSupport;

/**
* @author Russell Petty (GeoScience Victoria)
* @author Rini Angreani (CSIRO Earth Science and Resource Engineering)
* @version $Id$
*
*
*
* @source $URL$
*         http://svn.osgeo.org/geotools/trunk/modules/unsupported/app-schema/app-schema/src/main
*         /java/org/geotools/data/complex/FeatureTypeMapping.java $
*/
public class XmlFeatureTypeMapping extends FeatureTypeMapping {

    /**
     * Constants for manipulating XPath Expressions
     */
    private static final String XPATH_SEPARATOR = "/";

    private static final String XPATH_PROPERTY_SEPARATOR = "/@";

    private static final String XPATH_LEFT_INDEX_BRACKET = "[";

    private static final String XPATH_RIGHT_INDEX_BRACKET = "]";
   
    private static final String AS_XPATH_FUNCTION = "asXpath";

    /**
     * Output xpath to input xpath map
     */
    private Map<String, Expression> mapping = new HashMap<String, Expression>();

    /**
     * List of labelled AttributeMappings
     */
    private AttributeCreateOrderList attOrderedTypeList = null;

    /**
     * Label to AttributeMapping map
     */
    private Map<String, AttributeMapping> indexAttributeList;

    AttributeMapping rootAttribute;

    private int index = 1;
   
    private FilterFactory ff =  CommonFactoryFinder.getFilterFactory(null);
    /**
     * Attributes that don't have their own label, therefore are children of another node.
     */
    List<AttributeMapping> setterAttributes = new ArrayList<AttributeMapping>();

    PathAttributeList elements;

    protected String itemXpath;

    /**
     * No parameters constructor for use by the digester configuration engine as a JavaBean
     */
    public XmlFeatureTypeMapping() {
        super(null, null, new LinkedList<AttributeMapping>(), new NamespaceSupport());
    }

    public XmlFeatureTypeMapping(FeatureSource source, AttributeDescriptor target,
            List<AttributeMapping> mappings, NamespaceSupport namespaces, String itemXpath) {
        super(source, target, mappings, namespaces);
        this.itemXpath = itemXpath;
        elements = new PathAttributeList();
        ((XmlFeatureSource) source).setItemXpath(itemXpath);
        try {
            populateFeatureData();
        } catch (IOException ex) {
            throw new RuntimeException("Error occured when trying to create attribute mappings", ex);
        }
    }
   
    public List<Expression> getExpressionsIgnoreIndex(final StepList targetPath) {
        List<Expression> mappings = new ArrayList<Expression>();
        String path = targetPath.toString();

        Collection<String> c = mapping.keySet();

        // obtain an Iterator for Collection
        Iterator<String> itr = c.iterator();

        // iterate through HashMap values iterator
        while (itr.hasNext()) {
            String listPath = itr.next();
            String unindexedListPath = removeIndexFromPath(listPath);
            if (path.equals(unindexedListPath)) {
                mappings.add(mapping.get(listPath));
            }
        }
       
        if (mappings.isEmpty()) {
            // look in the setter attributes
            Iterator<AttributeMapping> leafAtts = setterAttributes.iterator();
            while (leafAtts.hasNext()) {
                AttributeMapping att = leafAtts.next();
                String listPath = att.getTargetXPath().toString();
                String unindexedListPath = removeIndexFromPath(listPath);
                if (path.equals(unindexedListPath)) {
                    mappings.add(att.getSourceExpression());
                }
            }
        }
       
        return mappings;
    }

    private String removeIndexFromPath(String inputPath) {
        String tempPath = inputPath;
        while (tempPath.contains(XPATH_LEFT_INDEX_BRACKET)) {
            int leftIndex = tempPath.indexOf(XPATH_LEFT_INDEX_BRACKET);
            int rightIndex = tempPath.indexOf(XPATH_RIGHT_INDEX_BRACKET, leftIndex);
            String leftTempPath = tempPath.substring(0, leftIndex);
            String rightTempPath = tempPath.substring(rightIndex + 1);
            tempPath = leftTempPath + rightTempPath;
        }

        return tempPath;
    }

    /**
     * Finds the attribute mappings for the given source expression.
     *
     * @param sourceExpression
     * @return list of matching attribute mappings
     */
    public List<AttributeMapping> getAttributeMappingsByExpression(final Expression sourceExpression) {
        AttributeMapping attMapping;
        List<AttributeMapping> mappings = Collections.emptyList();
        for (Iterator<AttributeMapping> it = attributeMappings.iterator(); it.hasNext();) {
            attMapping = (AttributeMapping) it.next();
            if (sourceExpression.equals(attMapping.getSourceExpression())) {
                if (mappings.size() == 0) {
                    mappings = new ArrayList<AttributeMapping>(2);
                }
                mappings.add(attMapping);
            }
        }
        return mappings;
    }
   
    /**
     * Finds an attribute mapping by label.
     *
     * @param label
     *            The attribute mapping label.
     * @return Attribute mapping that matches the label, or null.
     */
    public AttributeMapping getAttributeMappingByLabel(String label) {
        AttributeMapping attMapping;
        for (Iterator<AttributeMapping> it = attributeMappings.iterator(); it.hasNext();) {
            attMapping = (AttributeMapping) it.next();
            if (label.equals(attMapping.getLabel())) {
                return attMapping;
            }
        }
        return null;
    }

    /**
     * Finds the attribute mapping for the target expression <code>exactPath</code>
     *
     * @param exactPath
     *            the xpath expression on the target schema to find the mapping for
     * @return the attribute mapping that match 1:1 with <code>exactPath</code> or <code>null</code>
     *         if
     */
    public AttributeMapping getStringMapping(final StepList exactPath) {
        AttributeMapping attMapping;
        for (Iterator<AttributeMapping> it = attributeMappings.iterator(); it.hasNext();) {
            attMapping = (AttributeMapping) it.next();
            if (exactPath.equals(attMapping.getTargetXPath())) {
                return attMapping;
            }
        }
        return null;
    }

    public void populateFeatureData() throws IOException {

        List<AttributeMapping> attMap = getAttributeMappings();
        if (attOrderedTypeList == null) {
            initialiseAttributeLists(attMap);
        }
        // create required elements
        String xpath = rootAttribute.getInstanceXpath() == null ? itemXpath : itemXpath
                + XPATH_SEPARATOR + rootAttribute.getInstanceXpath();
       
        elements.put(rootAttribute.getLabel(), xpath, null);
        Expression idExpression = rootAttribute.getIdentifierExpression();
        if (!idExpression.equals(Expression.NIL)) {
            Expression id;           
            if (!(idExpression instanceof Function) && rootAttribute.getInstanceXpath() != null) {
                id = ff.property(rootAttribute.getInstanceXpath() + XPATH_SEPARATOR + idExpression);
            } else {
                id = idExpression;
            }                   
            mapping.put("@gml:id", id);   
        }       

        // iterator returns the attribute mappings starting from the root of the tree.
        // parents are always returned before children elements.
        Iterator<AttributeMapping> it = attOrderedTypeList.iterator();
        addComplexAttributes(elements, it);
        addSetterAttributes(elements);
       
        index++;
        removeAllRelativePaths();
    }

    private void addComplexAttributes(PathAttributeList elements, Iterator<AttributeMapping> it) {
        while (it.hasNext()) {
            AttributeMapping attMapping = it.next();
            final Expression sourceExpression = attMapping.getIdentifierExpression();
           
            List<Pair> ls = elements.get(attMapping.getParentLabel());
            if (ls != null) {
                for (int i = 0; i < ls.size(); i++) {
                    Pair parentAttribute = ls.get(i);                   
                    String instancePath = attMapping.getInstanceXpath();                   
                    int count = 1;
                    String countXpath = parentAttribute.getXpath();
                    // if instance path not set, then element exists, with one instance
                    if (instancePath != null) {
                        countXpath = countXpath + XPATH_SEPARATOR + instancePath;
                    }

                    for (int j = 0; j < count; j++) {
                        final String bracketIndex = "";
                        String xpath;
                        if (instancePath == null) {
                            xpath = parentAttribute.getXpath() + XPATH_SEPARATOR
                                    + sourceExpression.toString();
                        } else {
                            xpath = parentAttribute.getXpath() + XPATH_SEPARATOR
                                    + instancePath + bracketIndex
                                    + XPATH_SEPARATOR + sourceExpression.toString();
                        }
                        String label = getFullQueryPath(attMapping);

                        mapping.put(label + XPATH_PROPERTY_SEPARATOR + "gml:id", ff
                            .property(xpath));
                       
                        StepList sl = attMapping.getTargetXPath();
                        setPathIndex(j, sl);
                        Attribute subFeature = null;
                        elements.put(attMapping.getLabel(), countXpath + bracketIndex, subFeature);
                    }
                }
            }
        }
    }

    private void addSetterAttributes(PathAttributeList elements) {
        for (AttributeMapping attMapping : setterAttributes) {
            List<Pair> ls = elements.get(attMapping.getParentLabel());
            if (ls != null) {
                for (int i = 0; i < ls.size(); i++) {
                    Pair parentPair = ls.get(i);
                    final Expression sourceExpression = attMapping.getSourceExpression();
                    String prefix = parentPair.getXpath();

                    Expression usedXpath = getValue(prefix, sourceExpression,
                            attMapping);

                    String label = getFullQueryPath(attMapping);
                    mapping.put(label, usedXpath);
                    if (usedXpath instanceof PropertyName) {
                        // if current source expression is an inputAttribute
                        // work out the client properties value from the inputAttribute
                        // xpath, which would already have the parent prefix in it
                        addClientProperties(attMapping, usedXpath.toString(), label);
                    } else {
                        // if source expression is a constant or function
                        // just add the parent prefix to work out client properties values
                        addClientProperties(attMapping, prefix, label);
                    }
                }
            }

        }
    }

    private void addClientProperties(AttributeMapping attMapping, String prefix,
            String label) {
        Map<Name, Expression> clientProperties = attMapping.getClientProperties();
        if (clientProperties.size() != 0) {

            for (Map.Entry<Name, Expression> entry : clientProperties.entrySet()) {
                Name propName = entry.getKey();
                Expression propExpr = entry.getValue();
                Expression xPath = getValue(prefix, propExpr, attMapping);
                mapping.put(label + XPATH_PROPERTY_SEPARATOR + getPropertyNameXpath(propName),
                        xPath);
            }
        }
    }

    private String getPropertyNameXpath(Name propName) {
        String xpath;
        String namespaceUri = propName.getNamespaceURI();                                   
        if (namespaceUri != null) {
            String namespace = namespaces.getPrefix(namespaceUri);
            xpath = namespace + propName.getSeparator()
                        + propName.getLocalPart();
        } else {
            xpath = propName.getLocalPart();
        }
        return xpath;
    }
   
    private void setPathIndex(int j, StepList sl) {
        if (j > 0) {
            Step st = sl.get(sl.size() - 1);
            Step st2 = new Step(st.getName(), j + 1, st.isXmlAttribute());
            sl.remove(sl.size() - 1);
            sl.add(st2);
        }
    }

    protected Expression getValue(String xpathPrefix, Expression node, AttributeMapping mapping) {
        Expression value = null;
        if (node instanceof Function) {
            // function
            Function func = (Function) node;
            Expression exp = getAsXpathExpression(func, mapping);
            if (exp != null) {
                // this function must be an AsXpath
                // return the extracted expression
                value = exp;
            } else {
                // not an asXpath, but might have it in the param somewhere
                // the param would already be turned into the extracted expression
                // return the function
                value = func;
            }
        } else if (node instanceof LiteralExpressionImpl) {
            // constant
            value = node;
        } else {
            // input attribute
            String expressionValue = node.toString();
            if (xpathPrefix.length() > 0) {
                value = ff.property(xpathPrefix + XPATH_SEPARATOR + expressionValue);
            } else {
                value = node;
            }
        }
        return value;    
    }
   
    /**
     * Find asXpath in a function, which might be the function itself or a parameter of the
     * function, and extract the xpath value including itemXpath and instancePath prefixes.
     *
     * @param func
     *            The function
     * @param mapping
     *            The attribute mapping
     * @return xpath expression or null
     */
    private Expression getAsXpathExpression(Function func, AttributeMapping mapping) {
        if (func.getName().equals(AS_XPATH_FUNCTION)) {
            // get original filter xpath
            Expression queryXpath = func.getParameters().get(0);
            // get the attribute mapping full xpath and append to the function param
            String prefix;
            String parentLabel = mapping.getParentLabel();
            if (parentLabel == null) {
                // must be root
                prefix = elements.getPath(rootAttribute.getLabel());
            } else {
                prefix = elements.getPath(parentLabel);
                String instancePath = mapping.getInstanceXpath();
                if (instancePath != null) {
                    prefix += XPATH_SEPARATOR + instancePath;
                }
            }
            Expression fullXpath = ff.property(
                    prefix + XPATH_SEPARATOR + queryXpath);
            return fullXpath;
        } else
            List<Expression> params = func.getParameters();
            for (int i = 0; i < params.size(); i++) {
                Expression param = params.get(i);
                if (param instanceof Function) {
                    Expression expr = getAsXpathExpression((Function) param, mapping);
                    if (expr != null) {
                        // found asXpath and returned an expression
                        // set as the new parameter
                        func.getParameters().remove(i);
                        func.getParameters().add(expr);                      
                    }
                }
            }
            return null;
        }
    }

    private void initialiseAttributeLists(List<AttributeMapping> mappings) {

        for (AttributeMapping attMapping : mappings) {
            if (attMapping.getLabel() != null && attMapping.getParentLabel() == null
                    && attMapping.getTargetNodeInstance() == null) {

                rootAttribute = attMapping;
                break;
            }
        }

        attOrderedTypeList = new AttributeCreateOrderList(rootAttribute.getLabel());
        indexAttributeList = new HashMap<String, AttributeMapping>();
        indexAttributeList.put(rootAttribute.getLabel(), rootAttribute);

        for (AttributeMapping attMapping : mappings) {
            if (attMapping.getLabel() == null) {
                setterAttributes.add(attMapping);
            } else if (attMapping.getParentLabel() != null) {
                attOrderedTypeList.put(attMapping);
                indexAttributeList.put(attMapping.getLabel(), attMapping);
            }
        }
    }

    protected void setClientProperties(final Attribute target, final Object source,
            final Map<Name, Expression> clientProperties) {
        if (clientProperties.size() == 0) {
            return;
        }
        final Map<Name, Object> targetAttributes = new HashMap<Name, Object>();
        for (Map.Entry<Name, Expression> entry : clientProperties.entrySet()) {
            Name propName = entry.getKey();
            Expression propExpr = entry.getValue();
            Object propValue = null; // getValue(propExpr, source);
            if (propValue != null) {
                List<String> ls = (List<String>) propValue;
                if (ls.size() != 0) {
                    propValue = ls.get(0);
                } else {
                    propValue = "";
                }
            }
            targetAttributes.put(propName, propValue);
        }
    }

    private String getFullQueryPath(AttributeMapping attMapping) {
        return attMapping.getTargetXPath().toString();
    }
   
    private void removeAllRelativePaths() {

        Collection<String> c = mapping.keySet();
        Iterator<String> itr = c.iterator();

        while (itr.hasNext()) {
            String key = itr.next();
            Expression xPath = mapping.get(key);
            Expression xPath2 = removeRelativePaths(xPath);
            if (!xPath.toString().equals(xPath2.toString())) {
                mapping.put(key, xPath2);
            }
        }
    }

    private PropertyName removeRelativePaths(Expression xPath) {
        String xPathTemp = xPath.toString();
        final int NOT_FOUND = -1;
        final String RELATIVE_PATH = "/../";

        int i = xPathTemp.indexOf(RELATIVE_PATH);
        while (i != NOT_FOUND) {
            int slashPos = xPathTemp.lastIndexOf(XPATH_SEPARATOR, i - 1);
            if (slashPos != NOT_FOUND) {
                String left = xPathTemp.substring(0, slashPos + 1);
                String right = xPathTemp.substring(i + RELATIVE_PATH.length());
                xPathTemp = left + right;
            } else {
                break;
            }
            i = xPathTemp.indexOf(RELATIVE_PATH);
        }
        return ff.property(xPathTemp);
    }
   
    /**
     * Looks up for attribute mappings matching the xpath expression <code>propertyName</code>.
     * <p>
     * If any step in <code>propertyName</code> has index greater than 1, any mapping for the same
     * property applies, regardless of the mapping. For example, if there are mappings for
     * <code>gml:name[1]</code>, <code>gml:name[2]</code> and <code>gml:name[3]</code>, but
     * propertyName is just <code>gml:name</code>, all three mappings apply.
     * </p>
     *
     * @param mappings
     *            Feature type mapping to search for
     * @param simplifiedSteps
     * @return
     */
    @Override
    public List<Expression> findMappingsFor(final StepList propertyName, boolean includeNestedMappings) {
        List<Expression> expressions = null;
       
        // get all matching mappings if index is not specified, otherwise
        // get the specified mapping
        if (!propertyName.toString().contains("[")) {
            // collect all the mappings for the given property
            expressions = getExpressionsIgnoreIndex(propertyName);
        } else {
            // get specified mapping if indexed
            expressions = new ArrayList<Expression>(1);
            AttributeMapping mapping = getStringMapping(propertyName);
            if (mapping != null) {
                expressions.add(mapping.getSourceExpression());
            }
        }
        return expressions;          
    }
}
TOP

Related Classes of org.geotools.data.complex.XmlFeatureTypeMapping

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.