Package org.geoserver.feature.retype

Source Code of org.geoserver.feature.retype.RetypingDataStore

/* Copyright (c) 2001 - 2007 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.geoserver.feature.retype;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.geoserver.feature.RetypingFeatureCollection;
import org.geotools.data.DataAccess;
import org.geotools.data.DataSourceException;
import org.geotools.data.DataStore;
import org.geotools.data.DefaultQuery;
import org.geotools.data.FeatureLocking;
import org.geotools.data.FeatureReader;
import org.geotools.data.FeatureSource;
import org.geotools.data.FeatureStore;
import org.geotools.data.FeatureWriter;
import org.geotools.data.LockingManager;
import org.geotools.data.Query;
import org.geotools.data.ServiceInfo;
import org.geotools.data.Transaction;
import org.geotools.feature.NameImpl;
import org.geotools.feature.SchemaException;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.util.logging.Logging;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.Name;
import org.opengis.filter.Filter;

/**
* A simple data store that can be used to rename feature types (despite the name, the only retyping
* considered is the name change, thought it would not be that hard to extend it so that it
* could shave off some attribute too)
*/
public class RetypingDataStore implements DataStore {
    static final Logger LOGGER = Logging.getLogger(RetypingDataStore.class);
   
    private DataStore wrapped;

    private volatile Map<String, FeatureTypeMap> forwardMap = new ConcurrentHashMap<String, FeatureTypeMap>();

    private volatile Map<String, FeatureTypeMap> backwardsMap = new ConcurrentHashMap<String, FeatureTypeMap>();

    public RetypingDataStore(DataStore wrapped) throws IOException {
        this.wrapped = wrapped;
        // force update of type mapping maps
        getTypeNames();
    }

    public void createSchema(SimpleFeatureType featureType) throws IOException {
        throw new UnsupportedOperationException(
                "GeoServer does not support schema creation at the moment");
    }

    public void updateSchema(String typeName, SimpleFeatureType featureType) throws IOException {
        throw new UnsupportedOperationException(
                "GeoServer does not support schema updates at the moment");
    }

    public FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriter(String typeName,
            Filter filter, Transaction transaction) throws IOException {
        FeatureTypeMap map = getTypeMapBackwards(typeName, true);
        updateMap(map, false);
        FeatureWriter<SimpleFeatureType, SimpleFeature> writer = wrapped.getFeatureWriter(map.getOriginalName(), filter, transaction);
        if (map.isUnchanged())
            return writer;
        return new RetypingFeatureCollection.RetypingFeatureWriter(writer, map.getFeatureType());
    }

    public FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriter(String typeName, Transaction transaction)
            throws IOException {
        FeatureTypeMap map = getTypeMapBackwards(typeName, true);
        updateMap(map, false);
        FeatureWriter<SimpleFeatureType, SimpleFeature> writer;
        writer = wrapped.getFeatureWriter(map.getOriginalName(), transaction);
        if (map.isUnchanged())
            return writer;
        return new RetypingFeatureCollection.RetypingFeatureWriter(writer, map.getFeatureType());
    }

    public FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriterAppend(String typeName, Transaction transaction)
            throws IOException {
        FeatureTypeMap map = getTypeMapBackwards(typeName, true);
        updateMap(map, false);
        FeatureWriter<SimpleFeatureType, SimpleFeature> writer;
        writer = wrapped.getFeatureWriterAppend(map.getOriginalName(), transaction);
        if (map.isUnchanged())
            return writer;
        return new RetypingFeatureCollection.RetypingFeatureWriter(writer, map.getFeatureType());
    }

    public SimpleFeatureType getSchema(String typeName) throws IOException {
        FeatureTypeMap map = getTypeMapBackwards(typeName, false);
        if(map == null)
          throw new IOException("Unknown type " + typeName);
        updateMap(map, true);
        return map.getFeatureType();
    }

    public String[] getTypeNames() throws IOException {
        // here we transform the names, and also refresh the type maps so that
        // they
        // don't contain stale elements
        String[] names = wrapped.getTypeNames();
        String[] transformedNames = new String[names.length];
        Map<String, FeatureTypeMap> backup = new HashMap<String, FeatureTypeMap>(forwardMap);
       
        // Populate local hashmaps with new values.
        Map<String, FeatureTypeMap> forwardMapLocal = new ConcurrentHashMap<String, FeatureTypeMap>();
        Map<String, FeatureTypeMap> backwardsMapLocal = new ConcurrentHashMap<String, FeatureTypeMap>();
       
        for (int i = 0; i < names.length; i++) {
            String original = names[i];
            transformedNames[i] = transformFeatureTypeName(original);

            FeatureTypeMap map = backup.get(original);
            if (map == null) {
                map = new FeatureTypeMap(original, transformedNames[i]);
            }
            forwardMapLocal.put(map.getOriginalName(), map);
            backwardsMapLocal.put(map.getName(), map);
        }
       
        // Replace the member variables.
        forwardMap = forwardMapLocal;
        backwardsMap = backwardsMapLocal;
       
        return transformedNames;
    }

    public FeatureReader<SimpleFeatureType, SimpleFeature> getFeatureReader(Query query,
            Transaction transaction) throws IOException {
        FeatureTypeMap map = getTypeMapBackwards(query.getTypeName(), true);
        updateMap(map, false);
        FeatureReader<SimpleFeatureType, SimpleFeature> reader;
        reader = wrapped.getFeatureReader(retypeQuery(query, map), transaction);
        if (map.isUnchanged())
            return reader;
        return new RetypingFeatureCollection.RetypingFeatureReader(reader, map.getFeatureType());
    }

    public FeatureSource<SimpleFeatureType, SimpleFeature> getFeatureSource(String typeName) throws IOException {
        FeatureTypeMap map = getTypeMapBackwards(typeName, true);
        updateMap(map, false);
        FeatureSource<SimpleFeatureType, SimpleFeature> source = wrapped.getFeatureSource(map.getOriginalName());
        if (map.isUnchanged())
            return source;
        if (source instanceof FeatureLocking) {
            FeatureLocking<SimpleFeatureType, SimpleFeature> locking;
            locking = (FeatureLocking<SimpleFeatureType, SimpleFeature>) source;
            return new RetypingFeatureLocking(this, locking, map);
        } else if (source instanceof FeatureStore) {
            FeatureStore<SimpleFeatureType, SimpleFeature> store;
            store = (FeatureStore<SimpleFeatureType, SimpleFeature>) source;
            return new RetypingFeatureStore(this, store, map);
        }
        return new RetypingFeatureSource(this, source, map);
    }

    public LockingManager getLockingManager() {
        return wrapped.getLockingManager();
    }

    public FeatureSource<SimpleFeatureType, SimpleFeature> getView(Query query) throws IOException,
            SchemaException {
        FeatureTypeMap map = getTypeMapBackwards(query.getTypeName(), true);
        updateMap(map, false);
        FeatureSource<SimpleFeatureType, SimpleFeature> view = wrapped.getView(query);
        return new RetypingFeatureSource(this, view, map);
    }

    /**
     * Returns the type map given the external type name
     *
     * @param externalTypeName
     * @return
     * @throws IOException
     */
    FeatureTypeMap getTypeMapBackwards(String externalTypeName, boolean checkMap) throws IOException {
        FeatureTypeMap map = (FeatureTypeMap) backwardsMap.get(externalTypeName);
        if (map == null && checkMap)
            throw new IOException("Type mapping has not been established for type  "
                    + externalTypeName + ". "
                    + "Make sure you access types using getTypeNames() or getSchema() "
                    + "before trying to read/write onto them");
        return map;
    }

    /**
     * Make sure the FeatureTypeMap is fully loaded
     *
     * @param map
     * @throws IOException
     */
    void updateMap(FeatureTypeMap map, boolean forceUpdate) throws IOException {
        try {
            if (map.getFeatureType() == null || forceUpdate) {
                SimpleFeatureType original = wrapped.getSchema(map.getOriginalName());
                SimpleFeatureType transformed = transformFeatureType(original);
                map.setFeatureTypes(original, transformed);
            }
        } catch (IOException e) {
            LOGGER.log(Level.INFO, "Failure to remap feature type " + map.getOriginalName()
                    + ". The type will be ignored", e);
            // if the feature type cannot be found in the original data store,
            // remove it from the map
            backwardsMap.remove(map.getName());
            forwardMap.remove(map.getOriginalName());
        }
    }

    /**
     * Transforms the original feature type into a destination one according to
     * the renaming rules. For the moment, it's just a feature type name
     * replacement
     *
     * @param original
     * @return
     * @throws IOException
     */
    protected SimpleFeatureType transformFeatureType(SimpleFeatureType original) throws IOException {
        String transfomedName = transformFeatureTypeName(original.getTypeName());
        if (transfomedName.equals(original.getTypeName()))
            return original;

        try {
            SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
            b.init(original);
            b.setName(transfomedName);
            return b.buildFeatureType();
        } catch (Exception e) {
            throw new DataSourceException("Could not build the renamed feature type.", e);
        }
    }

    /**
     * Just transform the feature type name
     *
     * @param originalName
     * @return
     */
    protected String transformFeatureTypeName(String originalName) {
//        if(originalName.indexOf(":") >= 0) {
//            return originalName.substring(originalName.indexOf(":") + 1);
//        } else {
//            return originalName;
//        }
         return originalName.replaceAll(":", "_");
    }

    public void dispose() {
        wrapped.dispose();
    }
   
    /**
     * Retypes a query from the extenal type to the internal one using the
     * provided typemap
     * @param q
     * @param typeMap
     * @return
     * @throws IOException
     */
    Query retypeQuery(Query q, FeatureTypeMap typeMap) {
        DefaultQuery modified = new DefaultQuery(q);
        modified.setTypeName(typeMap.getOriginalName());
        modified.setFilter(retypeFilter(q.getFilter(), typeMap));
        return modified;
    }

    /**
     * Retypes a filter making sure the fids are using the internal typename prefix
     * @param filter
     * @param typeMap
     * @return
     */
    Filter retypeFilter(Filter filter, FeatureTypeMap typeMap) {
        FidTransformeVisitor visitor = new FidTransformeVisitor(typeMap);
        return (Filter) filter.accept(visitor, null);
    }

    public ServiceInfo getInfo() {
        return wrapped.getInfo();
    }
   
    /**
     * Delegates to {@link #getFeatureSource(String)} with
     * {@code name.getLocalPart()}
     *
     * @since 2.5
     * @see DataAccess#getFeatureSource(Name)
     */
    public FeatureSource<SimpleFeatureType, SimpleFeature> getFeatureSource(Name typeName)
            throws IOException {
        return getFeatureSource(typeName.getLocalPart());
    }
   
    /**
     * Returns the same list of names than {@link #getTypeNames()} meaning the
     * returned Names have no namespace set.
     *
     * @since 1.7
     * @see DataAccess#getNames()
     */
    public List<Name> getNames() throws IOException {
        String[] typeNames = getTypeNames();
        List<Name> names = new ArrayList<Name>(typeNames.length);
        for (String typeName : typeNames) {
            names.add(new NameImpl(typeName));
        }
        return names;
    }

    /**
     * Delegates to {@link #getSchema(String)} with {@code name.getLocalPart()}
     *
     * @since 1.7
     * @see DataAccess#getSchema(Name)
     */
    public SimpleFeatureType getSchema(Name name) throws IOException {
        return getSchema(name.getLocalPart());
    }

    /**
     * Delegates to {@link #updateSchema(String, SimpleFeatureType)} with
     * {@code name.getLocalPart()}
     *
     * @since 1.7
     * @see DataAccess#getFeatureSource(Name)
     */
    public void updateSchema(Name typeName, SimpleFeatureType featureType) throws IOException {
        updateSchema(typeName.getLocalPart(), featureType);
    }   
}
TOP

Related Classes of org.geoserver.feature.retype.RetypingDataStore

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.