Skip to content

Commit

Permalink
Basic support for querying and editing the configuration for layer as…
Browse files Browse the repository at this point in the history
…sociated to the collection. No layer creation/removal implemented yet
  • Loading branch information
aaime committed Aug 25, 2017
1 parent 03a0ed5 commit 88243fc
Show file tree
Hide file tree
Showing 10 changed files with 366 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@
import java.net.URI;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.StringJoiner;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.logging.Logger;
Expand Down Expand Up @@ -117,7 +119,7 @@ public AbstractMappingStore(JDBCOpenSearchAccess openSearchAccess,
this.propertyMapper = new SourcePropertyMapper(schema);
this.defaultSort = buildDefaultSort(schema);
this.linkFeatureType = buildLinkFeatureType();
this.collectionLayerFeatureType = buildCollectionLayerFeatureType();
this.collectionLayerFeatureType = (SimpleFeatureType) openSearchAccess.collectionFeatureType.getDescriptor(LAYER_PROPERTY_NAME).getType();
}

protected SimpleFeatureType buildLinkFeatureType() throws IOException {
Expand All @@ -132,25 +134,6 @@ protected SimpleFeatureType buildLinkFeatureType() throws IOException {
}
}

protected SimpleFeatureType buildCollectionLayerFeatureType() throws IOException {
SimpleFeatureType source = openSearchAccess.getDelegateStore().getSchema(getCollectionLayerTable());
try {
SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
for (AttributeDescriptor ad : source.getAttributeDescriptors()) {
if("bands".equals(ad.getLocalName()) || "browseBands".equals(ad.getLocalName())) {
b.add(ad.getLocalName(), String[].class);
} else {
b.add(ad);
}
}

b.setName(LAYER_PROPERTY_NAME);
return b.buildFeatureType();
} catch (Exception e) {
throw new DataSourceException("Could not build the renamed feature type.", e);
}
}

/**
* Builds the default sort for the underlying feature source query
*
Expand Down Expand Up @@ -537,9 +520,9 @@ protected void mapPropertiesToComplex(ComplexFeatureBuilder builder, SimpleFeatu
SimpleFeature retyped = retypeLayerFeature(layerFeature);

ab.setDescriptor((AttributeDescriptor) schema.getDescriptor(LAYER_PROPERTY_NAME));
Attribute attribute = ab.buildSimple(null, retyped);
final Collection<Property> properties = retyped.getProperties();
Attribute attribute = ab.buildSimple(retyped.getID(), properties);
builder.append(LAYER_PROPERTY_NAME, attribute);

}

}
Expand All @@ -549,7 +532,8 @@ private SimpleFeature retypeLayerFeature(SimpleFeature layerFeature) {
for (AttributeDescriptor att : layerFeature.getType().getAttributeDescriptors()) {
final Name attName = att.getName();
Object value = layerFeature.getAttribute( attName );
if("bands".equals(att.getLocalName()) || "browseBands".equals(att.getLocalName())) {
final String localName = att.getLocalName();
if(value != null && ("bands".equals(localName) || "browseBands".equals(localName))) {
String[] split = ((String) value).split("\\s*,\\s*");
retypeBuilder.set(attName, split);
} else {
Expand Down Expand Up @@ -733,6 +717,30 @@ public void modifyFeatures(Name[] attributeNames, Object[] attributeValues, Filt
// this one done
continue;
}
if (LAYER_PROPERTY_NAME.equals(name)) {
final String tableName = getCollectionLayerTable();
modifySecondaryTable(mappedFilter, value, tableName,
id -> FF.id(FF.featureId(tableName + "." + id)), (id, secondaryStore) -> {
SimpleFeatureBuilder fb = new SimpleFeatureBuilder(secondaryStore.getSchema());
Feature f = (Feature) value;
for (Property p : f.getProperties()) {
String attributeName = p.getName().getLocalPart();
Object attributeValue = p.getValue();
if(("bands".equals(attributeName) || "browseBands".equals(attributeName)) && attributeValue instanceof String[]) {
final String[] stringArray = (String[]) attributeValue;
attributeValue = Arrays.stream(stringArray).collect(Collectors.joining(","));
}
fb.set(attributeName, attributeValue);
}
fb.set("cid", id);
SimpleFeature thumbnailFeature = fb.buildFeature(tableName + "." + id);
thumbnailFeature.getUserData().put(Hints.USE_PROVIDED_FID, true);
return DataUtilities.collection(thumbnailFeature);
});

// this one done
continue;
}
if (OpenSearchAccess.OGC_LINKS_PROPERTY_NAME.equals(name)) {
final String tableName = getLinkTable();
modifySecondaryTable(mappedFilter, value, tableName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
import java.util.stream.Collectors;

import org.apache.commons.lang.StringUtils;
import org.geotools.data.DataSourceException;
import org.geotools.data.DataStore;
import org.geotools.data.DataUtilities;
import org.geotools.data.FeatureSource;
Expand All @@ -36,6 +37,7 @@
import org.geotools.feature.SchemaException;
import org.geotools.feature.TypeBuilder;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.filter.text.cql2.CQLException;
import org.geotools.filter.text.ecql.ECQL;
import org.geotools.jdbc.JDBCDataStore;
Expand Down Expand Up @@ -166,7 +168,7 @@ private FeatureType buildCollectionFeatureType(DataStore delegate) throws IOExce

// adding the layer publishing property
Name layerPropertyName = new NameImpl(this.namespaceURI, OpenSearchAccess.LAYER);
AttributeDescriptor layerDescriptor = buildSimpleDescriptor(layerPropertyName, String.class);
AttributeDescriptor layerDescriptor = buildFeatureDescriptor(layerPropertyName, buildCollectionLayerFeatureType(layerPropertyName), 0, 1);
typeBuilder.add(layerDescriptor);

// map OGC links
Expand All @@ -179,19 +181,42 @@ private FeatureType buildCollectionFeatureType(DataStore delegate) throws IOExce
return typeBuilder.feature();
}

protected SimpleFeatureType buildCollectionLayerFeatureType(Name name) throws IOException {
SimpleFeatureType source = getDelegateStore().getSchema("collection_layer");
try {
SimpleFeatureTypeBuilder b = new SimpleFeatureTypeBuilder();
for (AttributeDescriptor ad : source.getAttributeDescriptors()) {
if("bands".equals(ad.getLocalName()) || "browseBands".equals(ad.getLocalName())) {
b.add(ad.getLocalName(), String[].class);
} else {
b.add(ad);
}
}

b.setName(name);
return b.buildFeatureType();
} catch (Exception e) {
throw new DataSourceException("Could not build the renamed feature type.", e);
}
}

private AttributeDescriptor buildSimpleDescriptor(Name name, Class binding) {
AttributeTypeBuilder ab = new AttributeTypeBuilder();
ab.name(name.getLocalPart()).namespaceURI(name.getNamespaceURI());
ab.setBinding(String.class);
ab.setBinding(binding);
AttributeDescriptor descriptor = ab.buildDescriptor(name, ab.buildType());
return descriptor;
}

private AttributeDescriptor buildFeatureListDescriptor(Name name, SimpleFeatureType schema) {
return buildFeatureDescriptor(name, schema, 0, Integer.MAX_VALUE);
}

private AttributeDescriptor buildFeatureDescriptor(Name name, SimpleFeatureType schema, int minOccurs, int maxOccurs) {
AttributeTypeBuilder ab = new AttributeTypeBuilder();
ab.name(name.getLocalPart()).namespaceURI(name.getNamespaceURI());
ab.setMinOccurs(0);
ab.setMaxOccurs(Integer.MAX_VALUE);
ab.setMinOccurs(minOccurs);
ab.setMaxOccurs(maxOccurs);
AttributeDescriptor descriptor = ab.buildDescriptor(name, schema);
return descriptor;
}
Expand Down Expand Up @@ -555,7 +580,7 @@ private void checkName(String tableName, String lookup) {
}

public FeatureStore<FeatureType, Feature> getProductSource() throws IOException {
return new JDBCProductFeatureSource(this, productFeatureType);
return new JDBCProductFeatureStore(this, productFeatureType);
}

public FeatureStore<FeatureType, Feature> getCollectionSource() throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@
*
* @author Andrea Aime - GeoSolutions
*/
public class JDBCProductFeatureSource extends AbstractMappingStore {
public class JDBCProductFeatureStore extends AbstractMappingStore {

static final Logger LOGGER = Logging.getLogger(JDBCProductFeatureSource.class);
static final Logger LOGGER = Logging.getLogger(JDBCProductFeatureStore.class);

String granuleForeignKey;

public JDBCProductFeatureSource(JDBCOpenSearchAccess openSearchAccess,
public JDBCProductFeatureStore(JDBCOpenSearchAccess openSearchAccess,
FeatureType collectionFeatureType) throws IOException {
super(openSearchAccess, collectionFeatureType);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,7 @@
import static org.geoserver.opensearch.eo.store.OpenSearchAccess.ProductClass.OPTICAL;
import static org.geoserver.opensearch.eo.store.OpenSearchAccess.ProductClass.RADAR;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.*;

import java.io.File;
import java.io.IOException;
Expand All @@ -39,13 +36,17 @@
import org.geotools.data.DataStoreFinder;
import org.geotools.data.DataUtilities;
import org.geotools.data.FeatureSource;
import org.geotools.data.FeatureStore;
import org.geotools.data.Query;
import org.geotools.data.Transaction;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.AttributeImpl;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.NameImpl;
import org.geotools.feature.PropertyImpl;
import org.geotools.jdbc.JDBCDataStore;
import org.geotools.jdbc.JDBCDataStoreFactory;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
Expand All @@ -58,6 +59,7 @@
import org.opengis.feature.type.Name;
import org.opengis.feature.type.PropertyDescriptor;
import org.opengis.filter.FilterFactory2;
import org.opengis.filter.PropertyIsEqualTo;

import com.vividsolutions.jts.geom.Polygon;

Expand All @@ -70,6 +72,8 @@ public class JDBCOpenSearchAccessTest {
private static OpenSearchAccess osAccess;

private static FilterFactory2 FF = CommonFactoryFinder.getFilterFactory2();

static final Name LAYER_NAME = new NameImpl(TEST_NAMESPACE, OpenSearchAccess.LAYER);

@BeforeClass
public static void setupStore() throws IOException, SQLException {
Expand All @@ -96,6 +100,19 @@ public static void setupStore() throws IOException, SQLException {
params.put("repository", repository);
osAccess = (OpenSearchAccess) DataAccessFinder.getDataStore(params);
}

@After
public void resetCollectionLayer() throws IOException, SQLException {
String s1 = "DELETE public.collection_layer";
String s2 = "INSERT into public.collection_layer\n" +
"(\"cid\", \"workspace\", \"layer\", \"separateBands\", \"bands\", \"browseBands\", \"heterogeneousCRS\", \"mosaicCRS\")\n" +
"VALUES(17, 'gs', 'sentinel2', true, 'B1,B2,B3,B4,B5,B6,B7,B8,B9,B10,B11,B12', 'B4,B3,B2', true, 'EPSG:4326')";
try (Connection conn = h2.getConnection(Transaction.AUTO_COMMIT);
Statement st = conn.createStatement()) {
st.execute(s1);
st.execute(s2);
}
}

public static void populateTestDatabase(JDBCDataStore h2, boolean addGranuleTable)
throws SQLException, IOException {
Expand Down Expand Up @@ -346,7 +363,6 @@ public void testCollectionLayerInformation() throws Exception {
FeatureType schema = osAccess.getCollectionSource().getSchema();
Name name = schema.getName();
assertEquals(TEST_NAMESPACE, name.getNamespaceURI());
final Name LAYER_NAME = new NameImpl(TEST_NAMESPACE, OpenSearchAccess.LAYER);
final PropertyDescriptor layerDescriptor = schema.getDescriptor(LAYER_NAME);
assertNotNull(layerDescriptor);

Expand All @@ -361,17 +377,102 @@ public void testCollectionLayerInformation() throws Exception {
Feature collection = DataUtilities.first(features);
assertNotNull(collection);
Property layerProperty = collection.getProperty(LAYER_NAME);
assertThat(layerProperty, notNullValue());
final SimpleFeature layerValue = (SimpleFeature) layerProperty.getValue();
final Feature layerValue = (Feature) layerProperty;
assertThat(layerValue, notNullValue());

assertEquals("gs", layerValue.getAttribute("workspace"));
assertEquals("sentinel2", layerValue.getAttribute("layer"));
assertEquals(Boolean.TRUE, layerValue.getAttribute("separateBands"));
assertThat(layerValue.getAttribute("bands"), equalTo(new String[] {"B1","B2","B3","B4","B5","B6","B7","B8","B9","B10","B11","B12"}));
assertThat(layerValue.getAttribute("browseBands"), equalTo(new String[] {"B4","B3","B2"}));
assertEquals(Boolean.TRUE, layerValue.getAttribute("heterogeneousCRS"));
assertEquals("EPSG:4326", layerValue.getAttribute("mosaicCRS"));
assertEquals("gs", getAttribute(layerValue, "workspace"));
assertEquals("sentinel2", getAttribute(layerValue, "layer"));
assertEquals(Boolean.TRUE, getAttribute(layerValue, "separateBands"));
assertThat(getAttribute(layerValue, "bands"), equalTo(new String[] {"B1","B2","B3","B4","B5","B6","B7","B8","B9","B10","B11","B12"}));
assertThat(getAttribute(layerValue, "browseBands"), equalTo(new String[] {"B4","B3","B2"}));
assertEquals(Boolean.TRUE, getAttribute(layerValue, "heterogeneousCRS"));
assertEquals("EPSG:4326", getAttribute(layerValue, "mosaicCRS"));
}

@Test
public void testCollectionLayerUpdate() throws Exception {
// read it
FeatureStore<FeatureType, Feature> store = (FeatureStore<FeatureType, Feature>) osAccess.getCollectionSource();
Query q = new Query();
q.setProperties(Arrays.asList(FF.property(LAYER_NAME)));
final PropertyIsEqualTo filter = FF.equal(FF.property(new NameImpl(OpenSearchAccess.EO_NAMESPACE, "identifier")), FF.literal("SENTINEL2"), false);
q.setFilter(filter);
FeatureCollection<FeatureType, Feature> features = store.getFeatures(q);

final Feature layerValue = getLayerPropertyFromCollection(features);

// modify it
setAttribute(layerValue, "workspace", "gs2");
setAttribute(layerValue, "layer", "sentinel12345");
setAttribute(layerValue, "separateBands", false);
setAttribute(layerValue, "bands", new String[] {"B1","B4","B6"});
setAttribute(layerValue, "browseBands", null);
setAttribute(layerValue, "heterogeneousCRS", false);
setAttribute(layerValue, "mosaicCRS", "EPSG:3857");

// update the feature
store.modifyFeatures(new Name[] {LAYER_NAME}, new Object[] {layerValue}, filter);

// read it back and check
final Feature layerValue2 = getLayerPropertyFromCollection(store.getFeatures(q));
assertEquals("gs2", getAttribute(layerValue2, "workspace"));
assertEquals("sentinel12345", getAttribute(layerValue2, "layer"));
assertEquals(Boolean.FALSE, getAttribute(layerValue2, "separateBands"));
assertThat(getAttribute(layerValue2, "bands"), equalTo(new String[] {"B1","B4","B6"}));
assertThat(getAttribute(layerValue2, "browseBands"), nullValue());
assertEquals(Boolean.FALSE, getAttribute(layerValue2, "heterogeneousCRS"));
assertEquals("EPSG:3857", getAttribute(layerValue2, "mosaicCRS"));
}

private Object getAttribute(Feature sf, String name) {
Property p = sf.getProperty(name);
if(p != null) {
return p.getValue();
} else {
return null;
}
}

private void setAttribute(Feature sf, String name, Object value) {
Property p = sf.getProperty(name);
if(p != null) {
p.setValue(value);
} else {
List<Property> properties = new ArrayList<>(sf.getValue());
AttributeDescriptor ad = (AttributeDescriptor) sf.getType().getDescriptor(name);
properties.add(new AttributeImpl(value, ad, null));
}
}


private Feature getLayerPropertyFromCollection(
FeatureCollection<FeatureType, Feature> features) {
// get the simple feature representing the layer publishing info
Feature collection = DataUtilities.first(features);
assertNotNull(collection);
Property layerProperty = collection.getProperty(LAYER_NAME);
assertThat(layerProperty, notNullValue());
final Feature layerValue = (Feature) layerProperty;
return layerValue;
}

@Test
public void testCollectionLayerRemoval() throws Exception {
// read it
FeatureStore<FeatureType, Feature> store = (FeatureStore<FeatureType, Feature>) osAccess.getCollectionSource();
Query q = new Query();
q.setProperties(Arrays.asList(FF.property(LAYER_NAME)));
final PropertyIsEqualTo filter = FF.equal(FF.property(new NameImpl(OpenSearchAccess.EO_NAMESPACE, "identifier")), FF.literal("SENTINEL2"), false);
q.setFilter(filter);

// update the feature to remove the layer information
store.modifyFeatures(new Name[] {LAYER_NAME}, new Object[] {null}, filter);

// read it back and check it's not set
Feature collection = DataUtilities.first(store.getFeatures(q));
assertNotNull(collection);
Property layerProperty = collection.getProperty(LAYER_NAME);
assertNull(layerProperty);
}

}

0 comments on commit 88243fc

Please sign in to comment.