/* * 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.Arrays; import java.util.Iterator; import java.util.List; import org.geotools.data.DataAccess; import org.geotools.data.DataSourceException; import org.geotools.data.DataStore; import org.geotools.data.FeatureSource; import org.geotools.data.Repository; import org.geotools.util.InterpolationProperties; import org.opengis.feature.Feature; import org.opengis.feature.type.FeatureType; import org.opengis.feature.type.Name; /** * A registry that stores data access instances per application. This allows feature sources from * different data accesses to be accessed globally. * * @author Rini Angreani (CSIRO Earth Science and Resource Engineering) * @author Niels Charlier (Curtin University Of Technology) * */ public class DataAccessRegistry implements Repository { private static final long serialVersionUID = -373404928035022963L; /** * Singleton instance */ protected static DataAccessRegistry theRegistry = null; /** * Properties for interpolation / configuration settings */ protected InterpolationProperties properties = null; /** * Data Access Resources */ protected List<DataAccess<FeatureType, Feature>> registry = new ArrayList<DataAccess<FeatureType, Feature>>(); /** * Sole constructor */ protected DataAccessRegistry() { } /** * Public method to get singleton instance to registry. * * @return An instance of this class */ public static DataAccessRegistry getInstance() { if (theRegistry == null) { theRegistry = new DataAccessRegistry(); } return theRegistry; } /** * Get a feature source for built features with supplied feature type name. * * @param featureTypeName * @return feature source * @throws IOException */ public synchronized FeatureSource<FeatureType, Feature> featureSource(Name name) throws IOException { for (DataAccess<FeatureType, Feature> dataAccess : registry) { if (dataAccess.getNames().contains(name)) { if (dataAccess instanceof AppSchemaDataAccess) { return ((AppSchemaDataAccess) dataAccess).getFeatureSourceByName(name); } else { return dataAccess.getFeatureSource(name); } } } throwDataSourceException(name); return null; } public synchronized DataAccess<FeatureType, Feature> access(Name name) { try { return featureSource(name).getDataStore(); } catch (IOException e) { return null; } } public DataStore dataStore(Name name) { throw new UnsupportedOperationException("Simple feature DataStores not supported by app-schema registry."); } public List<DataStore> getDataStores() { throw new UnsupportedOperationException("Simple feature DataStores not supported by app-schema registry."); } /** * Registers a data access * * @param dataAccess * Data access to be registered */ public synchronized void registerAccess(DataAccess<FeatureType, Feature> dataAccess) { registry.add(dataAccess); } /** * Unregister a data access. This is important especially at the end of test cases, so that the * mappings contained in the data access do not conflict with mappings of the same type used in * other tests. * * @param dataAccess * Data access to be unregistered */ public synchronized void unregisterAccess(DataAccess<FeatureType, Feature> dataAccess) { registry.remove(dataAccess); } /** * Dispose and unregister all data accesses in the registry. This is may be needed to prevent unit tests * from conflicting with data accesses with the same type name registered for other tests. */ public synchronized void disposeAndUnregisterAll() { List<DataAccess<FeatureType, Feature>> copyRegistry = new ArrayList<DataAccess<FeatureType, Feature>>(registry); for (DataAccess<FeatureType, Feature> da : copyRegistry) { da.dispose(); } registry.clear(); } /** * Return true if a type name is mapped in one of the registered data accesses. If * the type mapping has mappingName, then it will be the key that is matched in the search. If * it doesn't, then it will match the targetElementName. * * @param featureTypeName * Feature type name * @return * @throws IOException */ public synchronized boolean hasAccessName(Name name) throws IOException { for (DataAccess<FeatureType, Feature> dataAccess : registry) { if (dataAccess.getNames().contains(name)) { return true; } } return false; } /** * Return true if a type name is mapped in one of the registered app-schema data accesses. If * the type mapping has mappingName, then it will be the key that is matched in the search. If * it doesn't, then it will match the targetElementName. * * @param featureTypeName * Feature type name * @return * @throws IOException */ public synchronized boolean hasAppSchemaAccessName(Name name) throws IOException { for (DataAccess<FeatureType, Feature> dataAccess : registry) { if (dataAccess instanceof AppSchemaDataAccess && (((AppSchemaDataAccess) dataAccess).hasName(name) || ((AppSchemaDataAccess) dataAccess) .hasElement(name))) { return true; } } return false; } /** * Get a feature type mapping from a registered app-schema data access. Please note that this is * only possible for app-schema data access instances. * * @param featureTypeName * @return feature type mapping * @throws IOException */ public synchronized FeatureTypeMapping mappingByName(Name name) throws IOException { for (DataAccess<FeatureType, Feature> dataAccess : registry) { if (dataAccess instanceof AppSchemaDataAccess) { if (((AppSchemaDataAccess) dataAccess).hasName(name)) { return ((AppSchemaDataAccess) dataAccess).getMappingByName(name); } } } throwDataSourceException(name); return null; } public synchronized FeatureTypeMapping mappingByElement(Name name) throws IOException { for (DataAccess<FeatureType, Feature> dataAccess : registry) { if (dataAccess instanceof AppSchemaDataAccess) { if (((AppSchemaDataAccess) dataAccess).hasElement(name)) { return ((AppSchemaDataAccess) dataAccess).getMappingByElement(name); } } } throwDataSourceException(name); return null; } /** * Return true if a type name is mapped in one of the registered app-schema data accesses as * targetElementName, regardless whether or not mappingName exists. * * @param featureTypeName * @return * @throws IOException */ public synchronized boolean hasAppSchemaTargetElement(Name name) throws IOException { for (DataAccess<FeatureType, Feature> dataAccess : registry) { if (dataAccess instanceof AppSchemaDataAccess && Arrays.asList(((AppSchemaDataAccess) dataAccess).getTypeNames()).contains(name)) { return true; } } return false; } /** * Get properties * * @return properties */ public synchronized InterpolationProperties getProperties() { if (properties == null) { properties = new InterpolationProperties(AppSchemaDataAccessFactory.DBTYPE_STRING); } return properties; } /** * Clean-up properties, mainly used for cleaning up after tests */ public synchronized void clearProperties() { properties = null; } //------------------------------------------------------------------------------------- // Static short-cut methods for convenience and backward compatibility //------------------------------------------------------------------------------------- /** * Get a feature source for built features with supplied feature type name. * * @param featureTypeName * @return feature source * @throws IOException */ public static FeatureSource<FeatureType, Feature> getFeatureSource(Name featureTypeName) throws IOException { return getInstance().featureSource(featureTypeName); } public static DataAccess<FeatureType, Feature> getDataAccess(Name featureTypeName) throws IOException { return getInstance().featureSource(featureTypeName).getDataStore(); } /** * Registers a data access * * @param dataAccess * Data access to be registered */ public static void register(DataAccess<FeatureType, Feature> dataAccess) { getInstance().registerAccess(dataAccess); } /** * Unregister a data access. This is important especially at the end of test cases, so that the * mappings contained in the data access do not conflict with mappings of the same type used in * other tests. * Does not dispose * * This method should not be called directly, instead use dispose method from DataAccess * * @param dataAccess * Data access to be unregistered */ public static void unregister(DataAccess<FeatureType, Feature> dataAccess) { getInstance().unregisterAccess(dataAccess); } /** * Unregister * and dispose * all data accesses in the registry. This is may be needed to prevent unit tests * from conflicting with data accesses with the same type name registered for other tests. */ public static void unregisterAndDisposeAll() { getInstance().disposeAndUnregisterAll(); } /** * Unregister * and dispose * all data accesses in the registry. This is may be needed to prevent unit tests * from conflicting with data accesses with the same type name registered for other tests. * * @Deprecated use unregisterAndDisposeAll */ @Deprecated public static void unregisterAll() { getInstance().disposeAndUnregisterAll(); } /** * Return true if a type name is mapped in one of the registered data accesses. If * the type mapping has mappingName, then it will be the key that is matched in the search. If * it doesn't, then it will match the targetElementName. * * @param featureTypeName * Feature type name * @return * @throws IOException */ public static boolean hasName(Name featureTypeName) throws IOException { return getInstance().hasAccessName(featureTypeName); } //--------------------------------------------------------------------------------------- // helper methods //--------------------------------------------------------------------------------------- /** * Throws data source exception if mapping is not found. * * @param featureTypeName * Name of feature type * @throws IOException */ protected void throwDataSourceException(Name featureTypeName) throws IOException { List<Name> typeNames = new ArrayList<Name>(); for (Iterator<DataAccess<FeatureType, Feature>> dataAccessIterator = registry.iterator(); dataAccessIterator.hasNext();) { typeNames.addAll(dataAccessIterator.next().getNames()); } throw new DataSourceException("Feature type " + featureTypeName + " not found." + " Has the data access been registered in DataAccessRegistry?" + " Available: " + typeNames.toString()); } }