package mil.nga.giat.geowave.adapter.vector.plugin;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ServiceLoader;
import java.util.stream.Collectors;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.geotools.data.DataAccessFactory.Param;
import org.geotools.data.Parameter;
import com.google.common.base.Function;
import com.google.common.collect.Lists;
import mil.nga.giat.geowave.adapter.auth.AuthorizationFactorySPI;
import mil.nga.giat.geowave.adapter.auth.EmptyAuthorizationFactory;
import mil.nga.giat.geowave.adapter.vector.index.ChooseHeuristicMatchIndexQueryStrategy;
import mil.nga.giat.geowave.adapter.vector.index.IndexQueryStrategySPI;
import mil.nga.giat.geowave.adapter.vector.plugin.lock.LockingManagementFactory;
import mil.nga.giat.geowave.core.store.DataStore;
import mil.nga.giat.geowave.core.store.GeoWaveStoreFinder;
import mil.nga.giat.geowave.core.store.StoreFactoryFamilySpi;
import mil.nga.giat.geowave.core.store.StoreFactoryOptions;
import mil.nga.giat.geowave.core.store.adapter.AdapterIndexMappingStore;
import mil.nga.giat.geowave.core.store.adapter.AdapterStore;
import mil.nga.giat.geowave.core.store.adapter.statistics.DataStatisticsStore;
import mil.nga.giat.geowave.core.store.config.ConfigOption;
import mil.nga.giat.geowave.core.store.config.ConfigUtils;
import mil.nga.giat.geowave.core.store.index.IndexStore;
import mil.nga.giat.geowave.core.store.operations.remote.options.DataStorePluginOptions;
/**
* This class encapsulates the parameterized configuration that can be provided
* per GeoWave data store within GeoTools. For GeoServer this configuration can
* be provided within the data store definition workflow.
*
*/
public class GeoWavePluginConfig
{
private final static Logger LOGGER = LoggerFactory.getLogger(
GeoWavePluginConfig.class);
public static final String GEOWAVE_NAMESPACE_KEY = StoreFactoryOptions.GEOWAVE_NAMESPACE_OPTION;
// name matches the workspace parameter provided to the factory
protected static final String FEATURE_NAMESPACE_KEY = "namespace";
protected static final String LOCK_MGT_KEY = "Lock Management";
protected static final String AUTH_MGT_KEY = "Authorization Management Provider";
protected static final String AUTH_URL_KEY = "Authorization Data URL";
protected static final String TRANSACTION_BUFFER_SIZE = "Transaction Buffer Size";
public static final String QUERY_INDEX_STRATEGY_KEY = "Query Index Strategy";
private static final Param GEOWAVE_NAMESPACE = new Param(
GEOWAVE_NAMESPACE_KEY,
String.class,
"The table namespace associated with this data store",
false);
private static final Param TRANSACTION_BUFFER_SIZE_PARAM = new Param(
TRANSACTION_BUFFER_SIZE,
Integer.class,
"Number of buffered feature insertions before flushing to the datastore.",
false);
private static final Param FEATURE_NAMESPACE = new Param(
FEATURE_NAMESPACE_KEY,
String.class,
"The overriding namespace for all feature types maintained within this data store",
false);
private static final Param LOCK_MGT = new Param(
LOCK_MGT_KEY,
String.class,
"WFS-T Locking Support.",
true,
null,
getLockMgtOptions());
private static final Param AUTH_MGT = new Param(
AUTH_MGT_KEY,
String.class,
"The provider to obtain authorization given a user.",
true,
null,
getAuthSPIOptions());
private static final Param AUTH_URL = new Param(
AUTH_URL_KEY,
String.class,
"The providers data URL.",
false);
private static final Param QUERY_INDEX_STRATEGY = new Param(
QUERY_INDEX_STRATEGY_KEY,
String.class,
"Strategy to choose an index during query processing.",
true,
null,
getIndexQueryStrategyOptions());
private static final List<Param> BASE_GEOWAVE_PLUGIN_PARAMS = Arrays.asList(
new Param[] {
FEATURE_NAMESPACE,
GEOWAVE_NAMESPACE,
LOCK_MGT,
AUTH_MGT,
AUTH_URL,
TRANSACTION_BUFFER_SIZE_PARAM,
QUERY_INDEX_STRATEGY
});
public static final List<String> BASE_GEOWAVE_PLUGIN_PARAM_KEYS = Arrays.asList(
BASE_GEOWAVE_PLUGIN_PARAMS.stream().map(
p -> p.key).toArray(
size -> new String[size]));
private final AdapterStore adapterStore;
private final DataStore dataStore;
private final IndexStore indexStore;
private final DataStatisticsStore dataStatisticsStore;
private final String name;
private final URI featureNameSpaceURI;
private final LockingManagementFactory lockingManagementFactory;
private final AuthorizationFactorySPI authorizationFactory;
private final URL authorizationURL;
private final Integer transactionBufferSize;
private final IndexQueryStrategySPI indexQueryStrategy;
private final AdapterIndexMappingStore adapterIndexMappingStore;
private static Map<String, List<Param>> paramMap = new HashMap<String, List<Param>>();
public synchronized static List<Param> getPluginParams(
final StoreFactoryFamilySpi storeFactoryFamily ) {
List<Param> params = paramMap.get(
storeFactoryFamily.getType());
if (params == null) {
final ConfigOption[] configOptions = GeoWaveStoreFinder.getAllOptions(
storeFactoryFamily,
false);
params = new ArrayList<Param>(
Lists.transform(
Lists.newArrayList(
configOptions),
new GeoWaveConfigOptionToGeoToolsConfigOption()));
params.addAll(
BASE_GEOWAVE_PLUGIN_PARAMS);
paramMap.put(
storeFactoryFamily.getType(),
params);
}
return params;
}
public GeoWavePluginConfig(
final DataStorePluginOptions params )
throws GeoWavePluginException {
this(
params.getFactoryFamily(),
// converting to Map<String,String> to Map<String,Serializable>
params.getOptionsAsMap().entrySet().stream().collect(
Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue)));
}
public GeoWavePluginConfig(
final StoreFactoryFamilySpi storeFactoryFamily,
final Map<String, Serializable> params )
throws GeoWavePluginException {
Serializable param = params.get(
GEOWAVE_NAMESPACE_KEY);
name = storeFactoryFamily.getType() + (param == null ? "" : ("_" + param));
final Map<String, String> paramStrs = new HashMap<String, String>();
// first converts serializable objects to String to avoid any issue if
// there's a difference how geotools is converting objects to how
// geowave intends to convert objects
for (final Entry<String, Serializable> e : params.entrySet()) {
paramStrs.put(
e.getKey(),
e.getValue() == null ? null : e.getValue().toString());
}
param = params.get(
FEATURE_NAMESPACE_KEY);
URI namespaceURI = null;
if (param != null) {
try {
namespaceURI = param instanceof String ? new URI(
param.toString()) : (URI) param;
}
catch (final URISyntaxException e) {
LOGGER.error(
"Malformed Feature Namespace URI : " + param,
e);
}
}
featureNameSpaceURI = namespaceURI;
param = params.get(
TRANSACTION_BUFFER_SIZE);
Integer bufferSizeFromParam = 10000;
if (param != null) {
try {
bufferSizeFromParam = param instanceof Integer ? (Integer) param : Integer.parseInt(
param.toString());
}
catch (final Exception e) {
LOGGER.error(
"Malformed buffer size : " + param,
e);
}
}
transactionBufferSize = bufferSizeFromParam;
param = params.get(
LOCK_MGT_KEY);
final Iterator<LockingManagementFactory> it = getLockManagementFactoryList();
LockingManagementFactory factory = null;
while (it.hasNext()) {
factory = it.next();
if ((param == null) || param.toString().equals(
factory.toString())) {
break;
}
}
final StoreFactoryOptions options = ConfigUtils.populateOptionsFromList(
storeFactoryFamily.getAdapterStoreFactory().createOptionsInstance(),
paramStrs);
adapterStore = storeFactoryFamily.getAdapterStoreFactory().createStore(
options);
dataStore = storeFactoryFamily.getDataStoreFactory().createStore(
options);
dataStatisticsStore = storeFactoryFamily.getDataStatisticsStoreFactory().createStore(
options);
indexStore = storeFactoryFamily.getIndexStoreFactory().createStore(
options);
adapterIndexMappingStore = storeFactoryFamily.getAdapterIndexMappingStoreFactory().createStore(
options);
lockingManagementFactory = factory;
authorizationFactory = getAuthorizationFactory(
params);
authorizationURL = getAuthorizationURL(
params);
indexQueryStrategy = getIndexQueryStrategy(
params);
}
public String getName() {
return name;
}
public static AuthorizationFactorySPI getAuthorizationFactory(
final Map<String, Serializable> params )
throws GeoWavePluginException {
final Serializable param = params.get(
AUTH_MGT_KEY);
final Iterator<AuthorizationFactorySPI> authIt = getAuthorizationFactoryList();
AuthorizationFactorySPI authFactory = new EmptyAuthorizationFactory();
while (authIt.hasNext()) {
authFactory = authIt.next();
if ((param == null) || param.toString().equals(
authFactory.toString())) {
break;
}
}
return authFactory;
}
public IndexQueryStrategySPI getIndexQueryStrategy() {
return indexQueryStrategy;
}
public AdapterStore getAdapterStore() {
return adapterStore;
}
public DataStore getDataStore() {
return dataStore;
}
public AdapterIndexMappingStore getAdapterIndexMappingStore() {
return adapterIndexMappingStore;
}
public IndexStore getIndexStore() {
return indexStore;
}
public DataStatisticsStore getDataStatisticsStore() {
return dataStatisticsStore;
}
public static IndexQueryStrategySPI getIndexQueryStrategy(
final Map<String, Serializable> params )
throws GeoWavePluginException {
final Serializable param = params.get(
QUERY_INDEX_STRATEGY_KEY);
if (param != null) {
final Iterator<IndexQueryStrategySPI> it = getInxexQueryStrategyList();
while (it.hasNext()) {
final IndexQueryStrategySPI spi = it.next();
if (spi.toString().equals(
param.toString())) {
return spi;
}
}
}
return new ChooseHeuristicMatchIndexQueryStrategy();
}
public static URL getAuthorizationURL(
final Map<String, Serializable> params )
throws GeoWavePluginException {
final Serializable param = params.get(
AUTH_URL_KEY);
if (param == null) {
return null;
}
else {
try {
return new URL(
param.toString());
}
catch (final MalformedURLException e) {
throw new GeoWavePluginException(
"Accumulo Plugin: malformed Authorization Service URL " + param.toString());
}
}
}
protected AuthorizationFactorySPI getAuthorizationFactory() {
return authorizationFactory;
}
protected URL getAuthorizationURL() {
return authorizationURL;
}
public LockingManagementFactory getLockingManagementFactory() {
return lockingManagementFactory;
}
public URI getFeatureNamespace() {
return featureNameSpaceURI;
}
public Integer getTransactionBufferSize() {
return transactionBufferSize;
}
private static Map<String, List<String>> getLockMgtOptions() {
final List<String> options = new ArrayList<String>();
final Iterator<LockingManagementFactory> it = getLockManagementFactoryList();
while (it.hasNext()) {
options.add(
it.next().toString());
}
final Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put(
Parameter.OPTIONS,
options);
return map;
}
static final List<String> BooleanOptions = Arrays.asList(
"true",
"false");
private static Map<String, List<String>> getIndexQueryStrategyOptions() {
final List<String> options = new ArrayList<String>();
final Iterator<IndexQueryStrategySPI> it = getInxexQueryStrategyList();
while (it.hasNext()) {
options.add(
it.next().toString());
}
final Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put(
Parameter.OPTIONS,
options);
return map;
}
private static Map<String, List<String>> getAuthSPIOptions() {
final List<String> options = new ArrayList<String>();
final Iterator<AuthorizationFactorySPI> it = getAuthorizationFactoryList();
while (it.hasNext()) {
options.add(
it.next().toString());
}
final Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put(
Parameter.OPTIONS,
options);
return map;
}
private static Iterator<LockingManagementFactory> getLockManagementFactoryList() {
final ServiceLoader<LockingManagementFactory> ldr = ServiceLoader.load(
LockingManagementFactory.class);
return ldr.iterator();
}
private static Iterator<AuthorizationFactorySPI> getAuthorizationFactoryList() {
final ServiceLoader<AuthorizationFactorySPI> ldr = ServiceLoader.load(
AuthorizationFactorySPI.class);
return ldr.iterator();
}
private static Iterator<IndexQueryStrategySPI> getInxexQueryStrategyList() {
final ServiceLoader<IndexQueryStrategySPI> ldr = ServiceLoader.load(
IndexQueryStrategySPI.class);
return ldr.iterator();
}
private static class GeoWaveConfigOptionToGeoToolsConfigOption implements
Function<ConfigOption, Param>
{
@Override
public Param apply(
final ConfigOption input ) {
if (input.isPassword()) {
return new Param(
input.getName(),
String.class,
input.getDescription(),
!input.isOptional(),
"mypassword",
Collections.singletonMap(
Parameter.IS_PASSWORD,
Boolean.TRUE));
}
if (input.getType().isPrimitive() && (input.getType() == boolean.class)) {
return new Param(
input.getName(),
input.getType(),
input.getDescription(),
true,
"true",
Collections.singletonMap(
Parameter.OPTIONS,
BooleanOptions));
}
return new Param(
input.getName(),
input.getType(),
input.getDescription(),
!input.isOptional());
}
}
}