/*
* Geotoolkit - An Open Source Java GIS Toolkit
* http://www.geotoolkit.org
*
* (C) 2011, Geomatys
*
* 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.geotoolkit.data.memory;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.sis.storage.DataStoreException;
import org.apache.sis.storage.IllegalNameException;
import org.geotoolkit.data.AbstractFeatureStore;
import org.geotoolkit.data.FeatureReader;
import org.geotoolkit.data.FeatureStore;
import org.geotoolkit.data.FeatureStoreUtilities;
import org.geotoolkit.data.FeatureWriter;
import org.geotoolkit.data.query.Query;
import org.geotoolkit.data.query.QueryCapabilities;
import org.geotoolkit.factory.Hints;
import org.geotoolkit.storage.StorageListener;
import org.apache.sis.util.ArgumentChecks;
import org.geotoolkit.data.internal.GenericNameIndex;
import org.opengis.util.GenericName;
import org.geotoolkit.storage.DataStoreFactory;
import org.geotoolkit.util.NamesExt;
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureType;
import org.opengis.feature.MismatchedFeatureException;
import org.opengis.filter.Filter;
import org.opengis.filter.identity.FeatureId;
import org.opengis.geometry.Envelope;
import org.opengis.parameter.ParameterValueGroup;
/**
* Wraps a feature store and store additional queries which will be made available
* like any other types.
*
* @author Johann Sorel (Geomatys)
* @module
*/
public final class ExtendedFeatureStore extends AbstractFeatureStore{
private final GenericNameIndex<Query> queries = new GenericNameIndex<>();
private final Map<GenericName,FeatureType> featureTypes = new ConcurrentHashMap<>();
private final FeatureStore wrapped;
public ExtendedFeatureStore(final FeatureStore wrapped) {
super(null);
ArgumentChecks.ensureNonNull("feature store", wrapped);
this.wrapped = wrapped;
}
@Override
public ParameterValueGroup getConfiguration() {
return wrapped.getConfiguration();
}
@Override
public DataStoreFactory getFactory() {
return wrapped.getFactory();
}
public Set<GenericName> getQueryNames() {
return queries.getNames();
}
public Query getQuery(final GenericName name) throws IllegalNameException{
return queries.get(name.toString());
}
public void addQuery(final Query query) throws IllegalNameException{
ArgumentChecks.ensureNonNull("query name", query.getTypeName());
queries.add(NamesExt.valueOf(query.getTypeName()), query);
featureTypes.clear();
}
public void removeQuery(final GenericName name) throws IllegalNameException{
queries.remove(name);
featureTypes.clear();
}
@Override
public Set<GenericName> getNames() throws DataStoreException {
final Set<GenericName> all = new HashSet<>(wrapped.getNames());
all.addAll(getQueryNames());
return all;
}
@Override
public void createFeatureType(final FeatureType featureType) throws DataStoreException {
if(getQueryNames().contains(featureType.getName())){
throw new DataStoreException("Type for name "+featureType.getName() +" already exist.");
}
wrapped.createFeatureType(featureType);
}
@Override
public void updateFeatureType(final FeatureType featureType) throws DataStoreException {
if(getQueryNames().contains(featureType.getName())){
throw new DataStoreException("Type for name "+featureType.getName() +" is a stred query, it can not be updated.");
}
wrapped.updateFeatureType(featureType);
featureTypes.clear();
}
@Override
public void deleteFeatureType(final String typeName) throws DataStoreException {
if(queries.get(typeName)!=null){
removeQuery(NamesExt.valueOf(typeName));
}
wrapped.deleteFeatureType(typeName);
featureTypes.clear();
}
@Override
public FeatureType getFeatureType(final String typeName) throws DataStoreException {
if(queries.get(typeName)!=null){
// return from cache when available
final GenericName n = NamesExt.valueOf(typeName);
if (featureTypes.containsKey(n)) {
return featureTypes.get(n);
}
final Query original = queries.get(typeName);
try {
final FeatureType ft = wrapped.getFeatureType(original);
featureTypes.put(n, ft);
return ft;
} catch (MismatchedFeatureException ex) {
throw new DataStoreException(ex);
}
}
return wrapped.getFeatureType(typeName);
}
@Override
public boolean isWritable(final String typeName) throws DataStoreException {
if(queries.get(typeName)!=null){
//stored queries are not writeable.
return false;
}
return wrapped.isWritable(typeName);
}
@Override
public QueryCapabilities getQueryCapabilities() {
return wrapped.getQueryCapabilities();
}
@Override
public long getCount(final Query query) throws DataStoreException {
if(queries.get(query.getTypeName())!=null){
try(FeatureReader reader = getFeatureReader(query)) {
return FeatureStoreUtilities.calculateCount(reader);
}
}
return wrapped.getCount(query);
}
@Override
public Envelope getEnvelope(final Query query) throws DataStoreException {
if(queries.get(query.getTypeName())!=null){
try(FeatureReader reader = getFeatureReader(query)) {
return FeatureStoreUtilities.calculateEnvelope(reader);
}
}
return wrapped.getEnvelope(query);
}
public FeatureStore getWrapped() {
return wrapped;
}
@Override
public List<FeatureId> addFeatures(final String typeName,
final Collection<? extends Feature> newFeatures, final Hints hints) throws DataStoreException {
if(queries.get(typeName)!=null){
throw new DataStoreException("Group name corresponed to a stored query, it can not be updated.");
}
return wrapped.addFeatures(typeName, newFeatures, hints);
}
@Override
public void updateFeatures(final String typeName, final Filter filter,
final Map<String, ?> values)
throws DataStoreException {
if(queries.get(typeName)!=null){
throw new DataStoreException("Group name corresponed to a stored query, it can not be updated.");
}
wrapped.updateFeatures(typeName, filter, values);
}
@Override
public void removeFeatures(final String typeName, final Filter filter) throws DataStoreException {
if(queries.get(typeName)!=null){
throw new DataStoreException("Group name corresponed to a stored query, it can not be updated.");
}
wrapped.removeFeatures(typeName, filter);
}
@Override
public FeatureReader getFeatureReader(final Query query) throws DataStoreException {
final String typeName = query.getTypeName();
if(queries.get(typeName)!=null){
final Query original = queries.get(typeName);
final FeatureReader baseReader = wrapped.getFeatureReader(original);
return handleRemaining(baseReader, query);
}
return wrapped.getFeatureReader(query);
}
@Override
public FeatureWriter getFeatureWriter(Query query) throws DataStoreException {
if(queries.get(query.getTypeName())!=null){
throw new DataStoreException("Group name corresponed to a stored query, writing is not possible.");
}
return wrapped.getFeatureWriter(query);
}
@Override
public void close() throws DataStoreException {
wrapped.close();
}
@Override
public void addStorageListener(final StorageListener listener) {
wrapped.addStorageListener(listener);
}
@Override
public void removeStorageListener(final StorageListener listener) {
wrapped.removeStorageListener(listener);
}
@Override
public void refreshMetaModel() throws DataStoreException {
wrapped.refreshMetaModel();
}
}