/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2002-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.efeature; import java.awt.RenderingHints.Key; import java.lang.ref.WeakReference; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import javax.imageio.spi.ServiceRegistry; import org.geotools.data.efeature.impl.EFeatureContextImpl; import org.geotools.data.efeature.impl.EFeatureIDFactoryImpl; import org.geotools.factory.BufferedFactory; import org.geotools.util.logging.Logging; /** * This class implements a cache of {@link EFeatureContext} instances. * <p> * Each {@link EFeatureContext instance} is associated with a factory ID. The * reference to each cached {@link EFeatureContext is} is strong (ordinary Java * object reference), ensuring that instances can not be garbage collected, even * if more memory is needed. * </p> * * @author kengu * */ public class EFeatureContextFactory implements BufferedFactory { /** * Cached {@link Logger} instance for this class */ private static final Logger LOGGER = Logging.getLogger(EFeatureContextFactory.class); /** * Weak reference to instance cached by the * {@link ServiceRegistry service registry}. */ private static WeakReference<EFeatureContextFactory> eInstance; /** * {@link Map} containing {@link EFeatureContext} instances. */ private final Map<String, EFeatureContext> eContextMap = new HashMap<String, EFeatureContext>(); /** * {@link Map} containing {@link EFeatureContextInfo} instances. */ private final Map<String, EFeatureContextInfo> eContextInfoMap = new HashMap<String, EFeatureContextInfo>(); // ----------------------------------------------------- // Constructors // ----------------------------------------------------- /** * Default construction (required by SPI) */ public EFeatureContextFactory() { /*NOP*/ } // ----------------------------------------------------- // Static helper methods // ----------------------------------------------------- /** * Get instance cached by {@link EFeatureFactoryFinder} */ public static EFeatureContextFactory eDefault(){ if(eInstance==null || eInstance.get()==null) { eInstance = new WeakReference<EFeatureContextFactory>( EFeatureFactoryFinder.getContextFactory()); } return eInstance.get(); } /** * Check to see if {@link EFeatureDataStore}s can be created. * <p> * This factory is only available if at least one * {@link EFeatureContext} instance is registered. * <p> * * @return <code>true</code> if and only if this factory is available to create * {@link EFeatureDataStore}s. * */ public boolean isAvailable() { return EFeatureUtils.isAvailable(eContextInfoMap); } /** * Check if given {@link EFeatureContext} instance is created by this factory. * <p> * This method checks for {@link Map#containsValue(Object) value equality} * between given instance and cached instances. * </p> * @param eContext - a {@link EFeatureContext} instance * @return <code>true</code> if found. * @see {@link #contains(String)} */ public boolean contains(EFeatureContext eContext) { return eContextMap.containsValue(eContext); } /** * Check if a {@link EFeatureContext} instance with given ID is created by this factory. * <p> * This method checks for {@link Map#containsKey(Object) key equality} * between given ID and cached IDs. * </p> * @param eContextID - {@link EFeature} context {@link EFeatureContext#get id} * @return <code>true</code> if found. */ public boolean contains(String eContextID) { return eContextMap.containsKey(eContextID); } /** * Create a {@link EFeatureContext} instance with given ID. * </p> * @return a {@link EFeatureContext} instance. * @throws IllegalArgumentException If an another instance with * same eContextID already exist. * {@link EFeatureContext instance}. */ public EFeatureContext create(String eContextID) throws IllegalArgumentException { return create(eContextID,new EFeatureIDFactoryImpl(), new EFeatureHints()); } /** * Create a {@link EFeatureContextInfo} instance from given * {@link EFeatureContext} instance and cache both instances. * <p> * If instance has already joined this factory, this method returns the cached * {@link EFeatureContextInfo} instance. * </p> * @param eContextID * @param eHints - {@link EFeatureHints} instance * @return a {@link EFeatureContextInfo} instance. * @throws IllegalArgumentException If an another instance with * same eContextID already exist. * {@link EFeatureContext instance}. */ public EFeatureContext create(String eContextID, EFeatureHints eHints) throws IllegalArgumentException { return create(eContextID,new EFeatureIDFactoryImpl(),eHints); } /** * Create a {@link EFeatureContextInfo} instance from given * {@link EFeatureContext} instance and cache both instances. * <p> * If instance has already joined this factory, this method returns the cached * {@link EFeatureContextInfo} instance. * </p> * @param eContextID * @param eIDFactory * @param eHints - {@link EFeatureHints} instance * @return a {@link EFeatureContextInfo} instance. * @throws IllegalArgumentException If an another instance with * same eContextID already exist. * {@link EFeatureContext instance}. */ public EFeatureContext create(String eContextID, EFeatureIDFactory eIDFactory, EFeatureHints eHints) throws IllegalArgumentException { try { // // Use default factory? // if(eIDFactory==null) eIDFactory = new EFeatureIDFactoryImpl(); // // Use default hints? // if(eHints==null) eHints = new EFeatureHints(); // // Another instance already registered with given ID? // EFeatureContextInfo eContextInfo = eContextInfoMap.get(eContextID); if(eContextInfo != null) { throw new IllegalArgumentException( "EFeatureContext " + eContextID + "' already exists"); } // // All OK, go ahead and create context and structure. // EFeatureContext eContext = new EFeatureContextImpl(this, eContextID, eIDFactory); // // Map context to id (required by subsequent create methods) // eContextMap.put(eContextID, eContext); // // Create structure info object // eContextInfo = EFeatureContextInfo.create(this,eContextID, eHints); // // Map structure to id // eContextInfoMap.put(eContextID, eContextInfo); // // ----------------------------------------------------- // Add EFeature as prototype. // ----------------------------------------------------- // This is an important step. It allows the context to // filter on any EFeature implementation, and enables // _ANY_ EFeature implementation to be adapted into // this context. // ----------------------------------------------------- // EFeaturePackage ePackage = EFeaturePackage.eINSTANCE; eContext.eAdd(ePackage); EFeatureInfo eFeatureInfo = EFeatureInfo.create(eContext, ePackage.getEFeature(), eHints); // // ----------------------------------------------------- // Validate structure (required) // ----------------------------------------------------- // This is an important step. If not done, // access to methods like getFeatureType() and // getSRID() will return null or throw exceptions. // ----------------------------------------------------- // eFeatureInfo.validate(ePackage, null); // // Success! // return eContext; } catch (IllegalArgumentException e) { // // Remove context and structure from cache // eContextMap.remove(eContextID); eContextInfoMap.remove(eContextID); // // Log the error // LOGGER.throwing(getClass().getName(), "create(EFeatureContext)", e); // // Notify again // throw e; } } /** * Dispose given {@link EFeatureContext context}. * </p> * @param eContext - the {@link EFeatureContext} instance. * @throws IllegalArgumentException If given context is not * created by this factory. */ public void dispose(EFeatureContext eContext) { if(!contains(eContext)) { throw new IllegalArgumentException("Context " + (eContext !=null ? eContext.eContextID() : "null") + " is not created by this factory"); } // // Get ID // String eContextID = eContext.eContextID(); // // Dispose structure // eStructure(eContextID).dispose(); // // Remove context from cache, allowing garbage collections // eContextMap.remove(eContextID); // // Tell garbage collector that memory can possible be reclaimed // Runtime.getRuntime().gc(); } /** * Dispose {@link EFeatureContext context} with given id. * </p> * @param eContextID - the {@link EFeatureContext} id. * @throws IllegalArgumentException If given context is not * created by this factory. */ public void dispose(String eContextID) { if(!contains(eContextID)) { throw new IllegalArgumentException("Context " + eContextID + " is not created by this factory"); } dispose(eContextMap.get(eContextID)); } /** * Get a EFeature {@link EFeatureContextInfo registry info} instance. * <p> * <strong>NOTE</strong>: If no instance was found, a * {@link IllegalArgumentException} it thrown. * </p> * @param eContextID - id of requested {@link EFeatureContextInfo} instance * @return a {@link EFeatureContextInfo} instance. * @throws IllegalArgumentException If no {@link EFeatureContext} instance with * given ID was found. */ public EFeatureContextInfo eStructure(String eContextID) throws IllegalArgumentException { EFeatureContextInfo eContextInfo = eContextInfoMap.get(eContextID); if(eContextInfo == null) { throw new IllegalArgumentException("EFeatureContext instance with ID " + eContextID + " was not found"); } return eContextInfo; } /** * Get a EFeature {@link EFeatureContext context} instance. * </p> * @param eContextID - id of requested {@link EFeatureContext} instance * @return a {@link EFeatureContextInfo} instance. * @throws IllegalArgumentException If no {@link EFeatureContext} * instance was found. */ public EFeatureContext eContext(String eContextID) { EFeatureContext eContext = eContextMap.get(eContextID); if(eContext == null) { throw new IllegalArgumentException( "EFeatureContext '" + eContextID + "' does not exist"); } return eContext; } @Override public Map<Key, ?> getImplementationHints() { // // TODO: Add hints for controlling cache size etc. // return Collections.emptyMap(); } }