/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wcs2_0.eo.response;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.geoserver.catalog.CoverageInfo;
import org.geoserver.catalog.DimensionInfo;
import org.geoserver.catalog.ResourceInfo;
import org.geoserver.config.GeoServer;
import org.geoserver.wcs.WCSInfo;
import org.geoserver.wcs2_0.eo.EOCoverageResourceCodec;
import org.geoserver.wcs2_0.eo.WCSEOMetadata;
import org.geoserver.wcs2_0.eo.response.DescribeEOCoverageSetTransformer.CoverageGranules;
import org.geoserver.wcs2_0.exception.WCS20Exception;
import org.geoserver.wcs2_0.util.WCS20DescribeCoverageExtension;
import org.geotools.coverage.grid.io.DimensionDescriptor;
import org.geotools.coverage.grid.io.GranuleSource;
import org.geotools.coverage.grid.io.StructuredGridCoverage2DReader;
import org.geotools.data.Query;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.factory.GeoTools;
import org.geotools.util.logging.Logging;
import org.opengis.feature.simple.SimpleFeature;
/**
* Extension point implementing {@link WCS20DescribeCoverageExtension} that handles the granules for Structured Coverages
*
* @author Nicola Lagomarsini - GeoSolutions
*
*/
public class GranuleCoverageExtension implements WCS20DescribeCoverageExtension {
/** Constant used as separator for the granule definition */
private static final String GRANULE_SEPARATOR = "_granule_";
private static final Logger LOGGER = Logging.getLogger(GranuleCoverageExtension.class);
/** Parser used for decoding the coverageId parameter */
private EOCoverageResourceCodec codec;
/** GeoServer instance used for checking if the EO extension is enabled */
private GeoServer geoserver;
public GranuleCoverageExtension(GeoServer geoServer, EOCoverageResourceCodec codec) {
this.codec = codec;
this.geoserver = geoServer;
}
@Override
public String handleCoverageId(String coverageId) {
if (isEOEnabled()) {
CoverageInfo granuleCoverage = codec.getGranuleCoverage(coverageId);
if (granuleCoverage != null && codec.isValidDataset(granuleCoverage)) {
return getCoverageId(coverageId);
}
return coverageId;
}
return coverageId;
}
@Override
public String handleEncodedId(String encodedId, String coverageId) {
if (isEOEnabled()) {
CoverageInfo granuleCoverage = codec.getGranuleCoverage(coverageId);
if (granuleCoverage != null && codec.isValidDataset(granuleCoverage)) {
return codec.getGranuleId(granuleCoverage, getGranuleId(coverageId));
}
return coverageId;
}
return coverageId;
}
@Override
public CoverageInfo handleCoverageInfo(String coverageId, CoverageInfo ci) {
CoverageInfo info = null;
if (isEOEnabled()) {
if (codec.getGranuleCoverage(coverageId) != null && codec.isValidDataset(ci)) {
SimpleFeatureIterator it = null;
try {
// Getting the structured coverage reader
StructuredGridCoverage2DReader reader = (StructuredGridCoverage2DReader) ci
.getGridCoverageReader(null, GeoTools.getDefaultHints());
String name;
// Getting the coverage name
name = codec.getCoverageName(ci);
// Query the reader
GranuleSource source = reader.getGranules(name, true);
Query q = new Query();
SimpleFeatureCollection collection = source.getGranules(q);
// create a GranuleCoverageInfo object for the single granule
if (!collection.isEmpty()) {
List<DimensionDescriptor> descriptors = getActiveDimensionDescriptor(ci,
reader, name);
it = collection.features();
if (it.hasNext()) {
SimpleFeature feature = it.next();
info = new GranuleCoverageInfo(ci, feature, descriptors);
}
}
if (info == null) {
if (LOGGER.isLoggable(Level.FINE)) {
LOGGER.log(Level.FINE, "No granule found for the granuleId: "
+ getGranuleId(coverageId));
}
}
} catch (IOException e) {
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
throw new WCS20Exception(e);
} finally {
if (it != null) {
try {
it.close();
} catch (Exception e) {
if (LOGGER.isLoggable(Level.SEVERE)) {
LOGGER.log(Level.SEVERE, e.getMessage(), e);
}
}
}
}
}
}
if (info == null) {
info = ci;
}
return info;
}
/**
* CHecks if the EO extension is enabled globally
*
* @return true if the EO extension is enabled
*/
public boolean isEOEnabled() {
WCSInfo wcs = geoserver.getService(WCSInfo.class);
Boolean enabled = wcs.getMetadata().get(WCSEOMetadata.ENABLED.key, Boolean.class);
return Boolean.TRUE.equals(enabled);
}
/**
* Returns the coverage identifier related to the specified coverageId, or null if the syntax is incorrect
*
* @return the coverageId related to the following coverageId parameter (with the _granule_ extension)
*/
public String getCoverageId(String coverageId) {
// does it have the expected lexical structure?
if (!coverageId.contains(GRANULE_SEPARATOR)) {
return null;
}
String[] splitted = coverageId.split(GRANULE_SEPARATOR);
if (splitted.length != 2) {
return null;
} else {
return splitted[0];
}
}
/**
* Returns the coverage identifier related to the specified coverageId, or null if the syntax is incorrect
*
* @return the coverageId related to the following coverageId parameter (with the _granule_ extension)
*/
public String getGranuleId(String coverageId) {
// does it have the expected lexical structure?
if (!coverageId.contains(GRANULE_SEPARATOR)) {
return null;
}
String[] splitted = coverageId.split(GRANULE_SEPARATOR);
if (splitted.length != 2) {
return null;
} else {
return splitted[1];
}
}
/**
* This method returns the active dimensions
*/
private List<DimensionDescriptor> getActiveDimensionDescriptor(CoverageInfo ci,
StructuredGridCoverage2DReader reader, String name) throws IOException {
// map the source descriptors for easy retrieval
Map<String, DimensionDescriptor> sourceDescriptors = new HashMap<String, DimensionDescriptor>();
for (DimensionDescriptor dimensionDescriptor : reader.getDimensionDescriptors(name)) {
sourceDescriptors.put(dimensionDescriptor.getName().toUpperCase(), dimensionDescriptor);
}
// select only those that have been activated vai the GeoServer GUI
List<DimensionDescriptor> enabledDescriptors = new ArrayList<DimensionDescriptor>();
for (Entry<String, Serializable> entry : ci.getMetadata().entrySet()) {
if (entry.getValue() instanceof DimensionInfo) {
DimensionInfo di = (DimensionInfo) entry.getValue();
if (di.isEnabled()) {
String dimensionName = entry.getKey();
if (dimensionName.startsWith(ResourceInfo.CUSTOM_DIMENSION_PREFIX)) {
dimensionName = dimensionName
.substring(ResourceInfo.CUSTOM_DIMENSION_PREFIX.length());
}
DimensionDescriptor selected = sourceDescriptors.get(dimensionName
.toUpperCase());
if (selected != null) {
enabledDescriptors.add(selected);
}
}
}
}
return enabledDescriptors;
}
}