/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2001 - 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.vfny.geoserver.util;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import org.geoserver.catalog.ResourcePool;
import org.geoserver.data.DataStoreFactoryInitializer;
import org.geoserver.data.DataAccessFactoryProducer;
import org.geoserver.feature.FeatureSourceUtils;
import org.geoserver.feature.retype.RetypingDataStore;
import org.geoserver.platform.GeoServerExtensions;
import org.geoserver.platform.GeoServerResourceLoader;
import org.geotools.data.DataAccess;
import org.geotools.data.DataAccessFactory;
import org.geotools.data.DataAccessFinder;
import org.geotools.data.DataStore;
import org.geotools.data.DataStoreFactorySpi;
import org.geotools.data.DataStoreFinder;
import org.geotools.data.FeatureSource;
import org.geotools.data.DataAccessFactory.Param;
import org.geotools.util.logging.Logging;
import org.opengis.feature.Feature;
import org.opengis.feature.type.FeatureType;
import com.vividsolutions.jts.geom.Envelope;
/**
* A collecitno of utilties for dealing with GeotTools DataStore.
*
* @author Richard Gould, Refractions Research, Inc.
* @author $Author: cholmesny $ (last modification)
* @version $Id$
*/
public abstract class DataStoreUtils {
/**
* logger
*/
static Logger LOGGER = Logging.getLogger("org.geoserver.data");
/**
* Looks up the datastore using the given params, verbatim, and then
* eventually wraps it into a renaming wrapper so that feature type
* names are good ones from the wfs point of view (that is, no ":" in the type names)
* @param params
*
* @deprecated use {@link #getDataAccess(Map)}
*/
public static DataStore getDataStore(Map params) throws IOException {
DataAccess<? extends FeatureType, ? extends Feature> store;
store = getDataAccess(params);
if (!(store instanceof DataStore)) {
return null;
}
return (DataStore) store;
}
/**
* Looks up the {@link DataAccess} using the given params, verbatim, and then eventually wraps
* it into a renaming wrapper so that feature type names are good ones from the wfs point of
* view (that is, no ":" in the type names)
*
* @param params
*
*/
public static DataAccess<? extends FeatureType, ? extends Feature> getDataAccess(Map params)
throws IOException {
DataAccessFactory factory = aquireFactory(params);
if (factory == null) {
return null;
}
DataAccess<? extends FeatureType, ? extends Feature> store = factory
.createDataStore(params);
if (store == null) {
return null;
}
if (store instanceof DataStore) {
try {
String[] names = ((DataStore) store).getTypeNames();
for (int i = 0; i < names.length; i++) {
if (names[i].indexOf(":") >= 0)
return new RetypingDataStore((DataStore) store);
}
} catch(IOException | RuntimeException e) {
// in case of exception computing the feature types make sure we clean up the store
store.dispose();
throw e;
}
}
return store;
}
/**
* processed parameters with relative URLs resolved against data directory.
* @param m
* @return processed parameters with relative URLs resolved against data directory
* @deprecated Unused, call {@link ResourcePool#getParams(Map, GeoServerResourceLoader)} directly.
*/
public static<K,V> Map<K,V> getParams(Map<K,V> m) {
return getParams(m,null);
}
/**
* processed parameters with relative URLs resolved against data directory.
* @param m
* @param sc Context used to create GeoServerResourceLoader if required
* @return processed parameters with relative URLs resolved against data directory
* @deprecated Unused, call {@link ResourcePool#getParams(Map, GeoServerResourceLoader)} directly.
*/
public static<K,V> Map<K,V> getParams(Map<K,V> m, ServletContext sc) {
GeoServerResourceLoader loader;
if( sc != null ){
String basePath = GeoServerResourceLoader.lookupGeoServerDataDirectory(sc);
File baseDir = new File(basePath);
loader = new GeoServerResourceLoader( baseDir );
}
else {
loader = GeoServerExtensions.bean( GeoServerResourceLoader.class);
}
return ResourcePool.getParams(m, loader );
}
/**
* When loading from DTO use the params to locate factory.
*
* <p>
* bleck
* </p>
*
* @param params
*
*
*/
public static DataAccessFactory aquireFactory(Map params) {
for (Iterator i = getAvailableDataStoreFactories().iterator(); i.hasNext();) {
DataAccessFactory factory = (DataAccessFactory) i.next();
initializeDataStoreFactory( factory );
if (factory.canProcess(params)) {
return factory;
}
}
return null;
}
/**
* After user has selected Description can aquire Factory based on
* display name.
*
* <p>
* Use factory for:
* </p>
*
* <ul>
* <li>
* List of Params (attrb name, help text)
* </li>
* <li>
* Checking user's input with factory.canProcess( params )
* </li>
* </ul>
*
*
* @param diplayName
*
*
*/
public static DataAccessFactory aquireFactory(String displayName) {
if(displayName == null) {
return null;
}
for (Iterator i = getAvailableDataStoreFactories().iterator(); i.hasNext();) {
DataAccessFactory factory = (DataAccessFactory) i.next();
initializeDataStoreFactory( factory );
if (displayName.equals(factory.getDisplayName())) {
return factory;
}
if (displayName.equals(factory.getClass().toString())) {
return factory;
}
}
return null;
}
/**
* Initializes a newly created data store factory by processing the {@link DataStoreFactoryInitializer}
* extension point.
*
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
static DataAccessFactory initializeDataStoreFactory( DataAccessFactory factory ) {
List<DataStoreFactoryInitializer> initializers = GeoServerExtensions.extensions( DataStoreFactoryInitializer.class );
for ( DataStoreFactoryInitializer initer : initializers ) {
if ( initer.getFactoryClass().isAssignableFrom( factory.getClass() ) ) {
try {
initer.initialize( factory );
}
catch( Throwable t ) {
final Logger LOGGER2 = Logging.getLogger( "org.geoserver.platform" );
String msg = "Error occured processing extension: " + initer.getClass().getName();
LOGGER2.log( Level.WARNING, msg, t );
}
}
}
return factory;
}
/**
* Utility methods for find param by key
*
* @param params DOCUMENT ME!
* @param key DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public static Param find(Param[] params, String key) {
for (int i = 0; i < params.length; i++) {
if (key.equalsIgnoreCase(params[i].key)) {
return params[i];
}
}
return null;
}
/**
* Returns the descriptions for the available DataStores.
*
* <p>
* Arrrg! Put these in the select box.
* </p>
*
* @return Descriptions for user to choose from
*/
public static List listDataStoresDescriptions() {
List list = new ArrayList();
for (Iterator i = getAvailableDataStoreFactories().iterator(); i.hasNext();) {
DataAccessFactory factory = (DataAccessFactory) i.next();
initializeDataStoreFactory(factory);
list.add(factory.getDisplayName());
}
return list;
}
public static Map defaultParams(String description) {
return defaultParams(aquireFactory(description));
}
public static Map defaultParams(DataAccessFactory factory) {
Map defaults = new HashMap();
Param[] params = factory.getParametersInfo();
for (int i = 0; i < params.length; i++) {
Param param = params[i];
String key = param.key;
String value = null;
//if (param.required ) {
if (param.sample != null) {
// Required params may have nice sample values
//
value = param.text(param.sample);
}
if (value == null) {
// or not
value = "";
}
//}
if (value != null) {
defaults.put(key, value);
}
}
return defaults;
}
/**
* Convert map to real values based on factory Params.
*
* <p>
* The resulting map should still be checked with factory.acceptsMap( map )
* </p>
*
* @param factory
* @param params
*
* @return Map with real values that may be acceptable to Factory
*
* @throws IOException DOCUMENT ME!
*/
public static Map toConnectionParams(DataAccessFactory factory, Map params)
throws IOException {
Map map = new HashMap(params.size());
Param[] info = factory.getParametersInfo();
// Convert Params into the kind of Map we actually need
for (Iterator i = params.keySet().iterator(); i.hasNext();) {
String key = (String) i.next();
Object value = find(info, key).lookUp(params);
if (value != null) {
map.put(key, value);
}
}
return map;
}
/**
* @deprecated use {@link org.geoserver.feature.FeatureSourceUtils#getBoundingBoxEnvelope(FeatureSource)}
*/
public static Envelope getBoundingBoxEnvelope(FeatureSource<? extends FeatureType, ? extends Feature> fs)
throws IOException {
return FeatureSourceUtils.getBoundingBoxEnvelope(fs);
}
public static Collection<DataAccessFactory> getAvailableDataStoreFactories() {
List<DataAccessFactory> factories = new ArrayList();
Iterator<DataAccessFactory> it = DataAccessFinder.getAvailableDataStores();
while(it.hasNext()) {
factories.add(it.next());
}
for (DataAccessFactoryProducer producer : GeoServerExtensions.extensions(DataAccessFactoryProducer.class)) {
try {
factories.addAll(producer.getDataStoreFactories());
}
catch(Throwable t) {
LOGGER.log(Level.WARNING, "Error occured loading data access factories. " +
"Ignoring producer", t);
}
}
return factories;
}
}