/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2012 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.csw.store;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.geoserver.catalog.util.CloseableIterator;
import org.geoserver.catalog.util.CloseableIteratorAdapter;
import org.geoserver.csw.records.AbstractRecordDescriptor;
import org.geoserver.csw.records.CSWRecordDescriptor;
import org.geoserver.csw.records.RecordDescriptor;
import org.geotools.data.Query;
import org.geotools.data.Transaction;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.NameImpl;
import org.opengis.feature.Feature;
import org.opengis.feature.FeatureVisitor;
import org.opengis.feature.Property;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.feature.type.Name;
import org.opengis.filter.Filter;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.identity.FeatureId;
/**
*
* @author Andrea Aime - GeoSolutions
* @author Niels Charlier
*
*/
public abstract class AbstractCatalogStore implements CatalogStore {
protected Map<Name, RecordDescriptor> descriptorByType = new RecordDescriptorsMap();
protected Map<String, RecordDescriptor> descriptorByOutputSchema = new HashMap<String, RecordDescriptor>();
protected void support(RecordDescriptor descriptor) {
descriptorByType.put(descriptor.getFeatureDescriptor().getName(), descriptor);
descriptorByOutputSchema.put(descriptor.getOutputSchema(), descriptor);
}
@Override
public RecordDescriptor[] getRecordDescriptors() throws IOException {
ArrayList<RecordDescriptor> ft = new ArrayList<RecordDescriptor>(descriptorByType.values());
return ft.toArray(new RecordDescriptor[ft.size()]);
}
@Override
public CloseableIterator<String> getDomain(Name typeName, final Name attributeName) throws IOException {
final RecordDescriptor rd = descriptorByType.get(typeName);
if (rd==null) {
throw new IOException(typeName + " is not a supported type");
}
// do we have such attribute?
final PropertyName property = rd.translateProperty(attributeName);
AttributeDescriptor ad = (AttributeDescriptor) property.evaluate(rd.getFeatureType());
if(ad == null) {
return new CloseableIteratorAdapter<String>(new ArrayList<String>().iterator());
}
// build the query against csw:record
Query q = new Query(typeName.getLocalPart());
q.setProperties(Arrays.asList(translateProperty(rd, attributeName)));
// collect the values without duplicates
final Set<String> values = new HashSet<String>();
getRecords(q, Transaction.AUTO_COMMIT, rd.getOutputSchema()).accepts(new FeatureVisitor() {
@Override
public void visit(Feature feature) {
Property prop = (Property) property.evaluate(feature);
if (prop != null)
try {
values.add( new String(((String) prop.getValue()).getBytes("ISO-8859-1"), "UTF-8" ) );
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
}, null);
// sort and return
List<String> result = new ArrayList(values);
Collections.sort(result);
return new CloseableIteratorAdapter<String>(result.iterator());
}
@Override
public FeatureCollection getRecords(Query q, Transaction t, String outputSchema) throws IOException {
RecordDescriptor rd;
Name typeName = null;
if (q.getTypeName() == null) {
typeName = CSWRecordDescriptor.RECORD_DESCRIPTOR.getName();
} else if(q.getNamespace() != null) {
typeName = new NameImpl(q.getNamespace().toString(), q.getTypeName());
} else {
typeName = new NameImpl(q.getTypeName());
}
rd = descriptorByType.get(typeName);
RecordDescriptor rdOutput;
if (outputSchema == null || "".equals(outputSchema)) {
rdOutput = descriptorByOutputSchema.get(CSWRecordDescriptor.getInstance().getOutputSchema());
} else {
rdOutput = descriptorByOutputSchema.get(outputSchema);
}
if (rd==null) {
throw new IOException(q.getTypeName() + " is not a supported type");
}
if (rdOutput==null) {
throw new IOException(outputSchema + " is not a supported output schema");
}
return getRecordsInternal(rd, rdOutput, q, t);
}
public abstract FeatureCollection getRecordsInternal(RecordDescriptor rd, RecordDescriptor rdOutput, Query q, Transaction t) throws IOException;
@Override
public RepositoryItem getRepositoryItem(String recordId) throws IOException {
// not supported
return null;
}
@Override
public int getRecordsCount(Query q, Transaction t) throws IOException {
// simply delegate to the feature collection, we have no optimizations
// available for the time being (even counting the files in case of no filtering
// would be wrong as we have to
return getRecords(q, t, null).size();
}
@Override
public List<FeatureId> addRecord(Feature f, Transaction t) throws IOException {
throw new UnsupportedOperationException("This store does not support transactions yet");
}
@Override
public void deleteRecord(Filter f, Transaction t) throws IOException {
throw new UnsupportedOperationException("This store does not support transactions yet");
}
@Override
public void updateRecord(Name typeName, Name[] attributeNames, Object[] attributeValues,
Filter filter, Transaction t) throws IOException {
throw new UnsupportedOperationException("This store does not support transactions yet");
}
@Override
public CatalogStoreCapabilities getCapabilities() {
return new CatalogStoreCapabilities(descriptorByType);
}
@Override
public PropertyName translateProperty(RecordDescriptor rd, Name name) {
return AbstractRecordDescriptor.buildPropertyName(rd.getNamespaceSupport(), name);
}
}