/* (c) 2014 Open Source Geospatial Foundation - all rights reserved
* (c) 2013 OpenPlans
* This code is licensed under the GPL 2.0 license, available at the root
* application directory.
*/
package org.geoserver.wms.eo;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.geoserver.catalog.Catalog;
import org.geoserver.catalog.LayerInfo;
import org.geoserver.catalog.MetadataMap;
import org.geoserver.platform.ServiceException;
import org.geoserver.wms.GetMapCallback;
import org.geoserver.wms.GetMapCallbackAdapter;
import org.geoserver.wms.GetMapRequest;
import org.geoserver.wms.WMSMapContent;
import org.geotools.gce.imagemosaic.ImageMosaicFormat;
import org.geotools.gce.imagemosaic.MergeBehavior;
import org.geotools.map.GridReaderLayer;
import org.geotools.map.Layer;
import org.geotools.map.RasterLayer;
import org.opengis.parameter.GeneralParameterValue;
import org.opengis.parameter.ParameterDescriptor;
import org.opengis.parameter.ParameterValue;
import org.opengis.referencing.ReferenceIdentifier;
/**
* This {@link GetMapCallback} is responsible for enforcing that an EO GetMap
* works as per the spec:
*
* -1- 1 or 3 Bands requested
* -2- Set the merge behavior for the underlying mosaic
*
* @author Simone Giannecchini, GeoSOlutions SAS
*/
public class EOGetMapChecker extends GetMapCallbackAdapter implements GetMapCallback {
/** BAND_COVERAGE_VALUE */
private static final String BAND_COVERAGE_VALUE = EoLayerType.BAND_COVERAGE.name();
Catalog catalog;
public EOGetMapChecker(Catalog catalog) {
this.catalog = catalog;
}
@SuppressWarnings("rawtypes")
@Override
public WMSMapContent beforeRender(WMSMapContent content) {
// is this WMS 1.3.0? If not move along
final GetMapRequest request = content.getRequest();
if(!"1.3.0".equalsIgnoreCase(request.getVersion())){
return super.beforeRender(content);
}
// === look for BANDS layer
final List<Layer> layers = content.layers();
RasterLayer layer=null;
for(Layer tempLayer:layers){
if(tempLayer instanceof RasterLayer){
String title = tempLayer.getTitle();
LayerInfo layerInfo = catalog.getLayerByName(title);
if(layerInfo!=null){
MetadataMap metadata= layerInfo.getMetadata();
if(metadata.containsKey(EoLayerType.KEY)&&metadata.get(EoLayerType.KEY).equals(BAND_COVERAGE_VALUE)){
layer=(RasterLayer) tempLayer;
break;
}
}
}
}
if(layer==null){
// there is no BAND layer, we move on as usual
return super.beforeRender(content);
}
// get the underlying grid reader
final GridReaderLayer readerLayer=(GridReaderLayer) layer;
final GeneralParameterValue[] params = readerLayer.getParams();
// get the read parameters for this reader
try {
final Set<ParameterDescriptor<List>> dynamicParameters = readerLayer.getReader().getDynamicParameters();
if(dynamicParameters.isEmpty()){
throw new IllegalStateException("Layer "+readerLayer.getTitle()+ " has no additional dimensions which are required for an EO BANDS layer");
}
final Set<ReferenceIdentifier> dynamicParametersNames= new HashSet<ReferenceIdentifier>();
for(ParameterDescriptor<List> param:dynamicParameters){
dynamicParametersNames.add(param.getName());
}
//looking for the readparams to control dimensions
// -1- control band stacking
// -2- check that a valid number of bands has been called
boolean foundMergeBehavior=false;
int foundCustomDimensions=0;
for(int i=0;i<params.length;i++){
final ParameterValue param = (ParameterValue) params[i];
final ParameterDescriptor descriptor = param.getDescriptor();
final ReferenceIdentifier name = descriptor.getName();
// MERGE_BEHAVIOR
if (name.equals(ImageMosaicFormat.MERGE_BEHAVIOR.getName())) {
foundMergeBehavior=true;
param.setValue(MergeBehavior.STACK.toString());
} else {
//Dynamic Parameters checks
// -1- only one can have multiple values with cardinality 3
if(dynamicParametersNames.contains(name)){
final List paramValues=(List) param.getValue();
final int size = paramValues.size();
if(size!=1&&size!=3){
throw new ServiceException(
"Wrong number of values provided to this GetMap for EO BANDS layer. Paremeter:"+name.getCode()+" #:"+size,
"InvalidDimensionValue");
}
foundCustomDimensions++;
}
}
}
// did we find all the custom dimensions
if(foundCustomDimensions!=dynamicParameters.size()){
throw new IllegalArgumentException("Not all the dimensions for this EO BANDS layer were requested. Please, check the GetMap request.");
}
// check if we found and set the merge behavior
if(!foundMergeBehavior){
// should not happen
throw new IllegalStateException("Unable to impose Stacking merge behavior!");
}
// move on as usual
return super.beforeRender(content);
} catch(IOException e) {
throw new ServiceException(e);
}
}
}