Skip to content

Commit

Permalink
[GEOS-9009] Allow opensearch-eo to publish multiple layers per collec…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
aaime committed Nov 13, 2018
1 parent ba255ef commit 1b7154a
Show file tree
Hide file tree
Showing 18 changed files with 1,416 additions and 543 deletions.
563 changes: 324 additions & 239 deletions doc/en/api/1.0.0/opensearch-eo.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package org.geoserver.opensearch.eo.store;

import static org.geoserver.opensearch.eo.store.JDBCOpenSearchAccess.FF;
import static org.geoserver.opensearch.eo.store.OpenSearchAccess.LAYERS_PROPERTY_NAME;
import static org.geoserver.opensearch.eo.store.OpenSearchAccess.METADATA_PROPERTY_NAME;
import static org.geoserver.opensearch.eo.store.OpenSearchAccess.OGC_LINKS_PROPERTY_NAME;

Expand All @@ -13,7 +14,6 @@
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;
Expand Down Expand Up @@ -48,7 +48,6 @@
import org.geotools.feature.ComplexFeatureBuilder;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.feature.NameImpl;
import org.geotools.feature.simple.SimpleFeatureBuilder;
import org.geotools.feature.simple.SimpleFeatureTypeBuilder;
import org.geotools.geometry.jts.ReferencedEnvelope;
Expand Down Expand Up @@ -102,29 +101,39 @@ public interface IOBiFunction<T, U, R> {

private SimpleFeatureType linkFeatureType;

private SimpleFeatureType collectionLayerFeatureType;
private SimpleFeatureType collectionLayerSchema;

private Transaction transaction;

private final Name LAYER_PROPERTY_NAME;

public AbstractMappingStore(
JDBCOpenSearchAccess openSearchAccess, FeatureType collectionFeatureType)
throws IOException {
this.LAYER_PROPERTY_NAME =
new NameImpl(openSearchAccess.getNamespaceURI(), OpenSearchAccess.LAYER);

this.openSearchAccess = openSearchAccess;
this.schema = collectionFeatureType;
this.propertyMapper = new SourcePropertyMapper(schema);
this.defaultSort = buildDefaultSort(schema);
this.linkFeatureType = buildLinkFeatureType();
this.collectionLayerFeatureType =
(SimpleFeatureType)
openSearchAccess
.collectionFeatureType
.getDescriptor(LAYER_PROPERTY_NAME)
.getType();
this.collectionLayerSchema = buildCollectionLayerFeatureType();
}

protected SimpleFeatureType buildCollectionLayerFeatureType() throws IOException {
SimpleFeatureType source =
openSearchAccess.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(LAYERS_PROPERTY_NAME);
return b.buildFeatureType();
} catch (Exception e) {
throw new DataSourceException("Could not build the renamed feature type.", e);
}
}

protected SimpleFeatureType buildLinkFeatureType() throws IOException {
Expand Down Expand Up @@ -325,7 +334,8 @@ protected Query mapToSimpleCollectionQuery(Query query, boolean addJoins) throws
}

// same for output layer, if necessary
if (hasOutputProperty(query, LAYER_PROPERTY_NAME, false)) {
if (hasOutputProperty(query, LAYERS_PROPERTY_NAME, false)
|| hasOutputProperty(query, LAYERS_PROPERTY_NAME, false)) {
Filter filter = FF.equal(FF.property("id"), FF.property("layer.cid"), true);
final String layerTable = getCollectionLayerTable();
Join join = new Join(layerTable, filter);
Expand Down Expand Up @@ -361,7 +371,7 @@ private Filter mapFilterToDelegateSchema(final Filter filter) {
}

/**
* Name of the table to join in case the {@link OpenSearchAccess#LAYER} property is requested
* Name of the table to join in case the {@link OpenSearchAccess#LAYERS} property is requested
*
* @return
*/
Expand Down Expand Up @@ -466,30 +476,47 @@ protected Feature mapToComplexFeature(PushbackFeatureIterator<SimpleFeature> it)
mapPropertiesToComplex(builder, fi);

// the OGC links can be more than one
Object link = fi.getAttribute("link");
while (link instanceof SimpleFeature) {
// retype the feature to have the right name
SimpleFeature linkFeature =
SimpleFeatureBuilder.retype((SimpleFeature) link, linkFeatureType);
builder.append(OGC_LINKS_PROPERTY_NAME, linkFeature);
Set<SimpleFeature> links = new LinkedHashSet<>();
Set<SimpleFeature> layers = new LinkedHashSet<>();
for (; ; ) {
Object link = fi.getAttribute("link");
Object layer = fi.getAttribute("layer");

// handle joined layer if any
if (layer instanceof SimpleFeature) {
layers.add((SimpleFeature) layer);
}

if (link instanceof SimpleFeature) {
links.add((SimpleFeature) link);
}

// see if there are more links
if (it.hasNext()) {
SimpleFeature next = it.next();
// same feature?
if (next.getID().equals(fi.getID())) {
link = next.getAttribute("link");
} else {
if (!next.getID().equals(fi.getID())) {
// moved to the next feature, push it back,
// we're done for the current one
it.pushBack();
break;
} else {
fi = next;
}
} else {
break;
}
}

for (SimpleFeature layerFeature : layers) {
SimpleFeature retyped = retypeLayerFeature(layerFeature);
builder.append(LAYERS_PROPERTY_NAME, retyped);
}

for (SimpleFeature link : links) {
SimpleFeature linkFeature =
SimpleFeatureBuilder.retype((SimpleFeature) link, linkFeatureType);
builder.append(OGC_LINKS_PROPERTY_NAME, linkFeature);
}

//
Feature feature = builder.buildFeature(fi.getID());
return feature;
Expand Down Expand Up @@ -528,22 +555,10 @@ protected void mapPropertiesToComplex(ComplexFeatureBuilder builder, SimpleFeatu
Attribute attribute = ab.buildSimple(null, metadataFeature.getAttribute("metadata"));
builder.append(METADATA_PROPERTY_NAME, attribute);
}

// handle joined layer if any
Object layerValue = fi.getAttribute(OpenSearchAccess.LAYER);
if (layerValue instanceof SimpleFeature) {
SimpleFeature layerFeature = (SimpleFeature) layerValue;
SimpleFeature retyped = retypeLayerFeature(layerFeature);

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

private SimpleFeature retypeLayerFeature(SimpleFeature layerFeature) {
SimpleFeatureBuilder retypeBuilder = new SimpleFeatureBuilder(collectionLayerFeatureType);
SimpleFeatureBuilder retypeBuilder = new SimpleFeatureBuilder(collectionLayerSchema);
for (AttributeDescriptor att : layerFeature.getType().getAttributeDescriptors()) {
final Name attName = att.getName();
Object value = layerFeature.getAttribute(attName);
Expand Down Expand Up @@ -754,33 +769,43 @@ public void modifyFeatures(Name[] attributeNames, Object[] attributeValues, Filt
// this one done
continue;
}
if (LAYER_PROPERTY_NAME.equals(name)) {
if (LAYERS_PROPERTY_NAME.equals(name)) {
final String tableName = getCollectionLayerTable();
modifySecondaryTable(
mappedFilter,
value,
tableName,
id -> FF.id(FF.featureId(tableName + "." + id)),
(id, secondaryStore) -> {
id -> FF.equal(FF.property("cid"), FF.literal(id), false),
(id, layersStore) -> {
SimpleFeatureCollection layers = (SimpleFeatureCollection) value;
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[] array = (String[]) attributeValue;
attributeValue =
Arrays.stream(array).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);
new SimpleFeatureBuilder(layersStore.getSchema());

ListFeatureCollection mappedLayers =
new ListFeatureCollection(layersStore.getSchema());
layers.accepts(
f -> {
SimpleFeature sf = (SimpleFeature) f;
for (Property p : sf.getProperties()) {
String attributeName = p.getName().getLocalPart();
Object attributeValue = p.getValue();
if (("bands".equals(attributeName)
|| "browseBands".equals(attributeName))
&& attributeValue instanceof String[]) {
final String[] array = (String[]) attributeValue;
attributeValue =
Arrays.stream(array)
.collect(Collectors.joining(","));
}
fb.set(attributeName, attributeValue);
}
fb.set("cid", id);
SimpleFeature layerFeature =
fb.buildFeature(tableName + "." + id);
mappedLayers.add(layerFeature);
},
null);
return mappedLayers;
});

// this one done
Expand Down Expand Up @@ -871,6 +896,19 @@ protected boolean modifySecondaryAttribute(Name name, Object value, Filter mappe
return false;
}

/**
* Modifies the contents of a secondary table by removing the old values completely and adding
* the new mapped values as built by the feature build
*
* @param mainTypeFilter The filter to locate the main object
* @param value The value to be mapped and replaced
* @param tableName The secondary table name
* @param secondaryTableFilterSupplier A supplier going from the the main filter to the
* secondary table one
* @param featureBuilder Transforms the complex feature value in a feature collection for the
* secondary table, it will be inserted in place of the old values
* @throws IOException
*/
protected void modifySecondaryTable(
Filter mainTypeFilter,
Object value,
Expand Down Expand Up @@ -934,4 +972,12 @@ public Transaction getTransaction() {
return this.transaction;
}
}

public SimpleFeatureType getCollectionLayerSchema() {
return collectionLayerSchema;
}

public SimpleFeatureType getOGCLinksSchema() {
return linkFeatureType;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@
*/
package org.geoserver.opensearch.eo.store;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.opengis.feature.Feature;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;

public class CollectionLayer {

Expand All @@ -24,6 +30,8 @@ public class CollectionLayer {

String mosaicCRS;

boolean defaultLayer;

public CollectionLayer() {
super();
// TODO Auto-generated constructor stub
Expand Down Expand Up @@ -109,28 +117,36 @@ public String toString() {
}

/**
* Builds a CollectionLayer bean from the {@link OpenSearchAccess#LAYER} property of a
* Builds a CollectionLayer bean from the {@link OpenSearchAccess#LAYERS} property of a
* Collection feature.
*
* @param feature
* @return The layer, or null if the property was not found
*/
public static CollectionLayer buildCollectionLayerFromFeature(Feature feature) {
public static List<CollectionLayer> buildCollectionLayersFromFeature(Feature feature)
throws IOException {
// map to a single bean
CollectionLayer layer = null;
Property p = feature.getProperty(OpenSearchAccess.LAYER);
if (p != null && p instanceof Feature) {
Feature lf = (Feature) p;
layer = new CollectionLayer();
layer.setWorkspace((String) getAttribute(lf, "workspace"));
layer.setLayer((String) getAttribute(lf, "layer"));
layer.setSeparateBands(Boolean.TRUE.equals(getAttribute(lf, "separateBands")));
layer.setBands((String[]) getAttribute(lf, "bands"));
layer.setBrowseBands((String[]) getAttribute(lf, "browseBands"));
layer.setHeterogeneousCRS(Boolean.TRUE.equals(getAttribute(lf, "heterogeneousCRS")));
layer.setMosaicCRS((String) getAttribute(lf, "mosaicCRS"));
List<CollectionLayer> result = new ArrayList<>();
Collection<Property> layers = feature.getProperties(OpenSearchAccess.LAYERS);
if (layers != null) {
for (Property p : layers) {
SimpleFeature lf = (SimpleFeature) p;
CollectionLayer layer = new CollectionLayer();
layer.setWorkspace((String) getAttribute(lf, "workspace"));
layer.setLayer((String) getAttribute(lf, "layer"));
layer.setSeparateBands(Boolean.TRUE.equals(getAttribute(lf, "separateBands")));
layer.setBands((String[]) getAttribute(lf, "bands"));
layer.setBrowseBands((String[]) getAttribute(lf, "browseBands"));
layer.setHeterogeneousCRS(
Boolean.TRUE.equals(getAttribute(lf, "heterogeneousCRS")));
layer.setMosaicCRS((String) getAttribute(lf, "mosaicCRS"));
layer.setDefaultLayer(
Optional.ofNullable((Boolean) getAttribute(lf, "defaultLayer"))
.orElse(false));
result.add(layer);
}
}
return layer;
return result;
}

private static Object getAttribute(Feature sf, String name) {
Expand All @@ -141,4 +157,22 @@ private static Object getAttribute(Feature sf, String name) {
return null;
}
}

/**
* Returns the default layer property
*
* @return True is this is the default layer for the collection, false otherwise
*/
public boolean isDefaultLayer() {
return defaultLayer;
}

/**
* Sets the default layer property (only one should be the default)
*
* @param defaultLayer
*/
public void setDefaultLayer(boolean defaultLayer) {
this.defaultLayer = defaultLayer;
}
}

0 comments on commit 1b7154a

Please sign in to comment.