/** * Copyright (C) 2012 52°North Initiative for Geospatial Open Source Software GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.n52.sos.handler; import org.n52.ows.ExceptionReport; import org.n52.ows.InvalidParameterValueException; import org.n52.ows.MissingParameterValueException; import org.n52.oxf.valueDomains.time.ITime; import org.n52.oxf.valueDomains.time.ITimePeriod; import org.n52.oxf.valueDomains.time.ITimePosition; import org.n52.oxf.valueDomains.time.TimeFactory; import org.n52.sos.db.AccessGDB; import org.n52.util.logging.Logger; import com.esri.arcgis.server.json.JSONObject; /** * @author <a href="mailto:broering@52north.org">Arne Broering</a> */ public abstract class OGCOperationRequestHandler implements OperationRequestHandler { private static final String SERVICE_KEY = "service"; private static final String REQUEST_KEY = "request"; public static final String DEFAULT_RESPONSE_PROPERTIES = "{ \"Content-Disposition\":\"inline; filename=\\\"ogc-sos-response.xml\\\"\", \"Content-Type\":\"application/xml\" }"; protected static Logger LOGGER = Logger.getLogger(OGCOperationRequestHandler.class.getName()); protected static String SERVICE = "SOS"; protected static String VERSION = "2.0.0"; protected String sosUrlExtension; public OGCOperationRequestHandler() { } @Override public void initialize(String urlSosExtension) { this.sosUrlExtension = urlSosExtension; } public byte[] invokeOGCOperation(AccessGDB geoDB, JSONObject inputObject, String[] responseProperties) throws ExceptionReport { LOGGER.debug("Start " + getOperationName() + " query."); if (responseProperties == null || responseProperties.length == 0){ responseProperties = new String[1]; } responseProperties[0] = DEFAULT_RESPONSE_PROPERTIES; if (inputObject == null) { throw new MissingParameterValueException("Error, no parameters specified."); } // check 'service' parameter: checkMandatoryParameter(inputObject, SERVICE_KEY, SERVICE); // check 'request' parameter: checkMandatoryParameter(inputObject, REQUEST_KEY, getOperationName()); return null; } /** * checks whether a parameter with the given parameterName is presented and has the allowedValue. * * @throws IllegalArgumentException in case parameter is not given or value is not allowed. * * @return the value of the checked parameter. * @throws ExceptionReport */ public String checkMandatoryParameter(JSONObject inputObject, String parameterName, String allowedValue) throws ExceptionReport { String parameterValue = null; if (inputObject.has(parameterName)) { parameterValue = inputObject.getString(parameterName); if (! parameterValue.equalsIgnoreCase(allowedValue)) { throw new InvalidParameterValueException("Error, '" + parameterName + "' parameter != '"+ allowedValue +"'."); } } else { throw new MissingParameterValueException("Error, operation requires '" + parameterName + "' parameter with value '" + allowedValue + "'."); } return parameterValue; } /** * Converts a spatial filter that conforms to the SOS 2.0 standard [OGC * 10-037] to a spatial filter that conforms to ESRI's GeoServices REST API * specification. * * <br> * As spatial filter, the SOS uses a bounding box definition. The encoding * of the bounding box is a list of comma separated values. The first value * is the valueReference of the spatial property of the observations to * which this bounding box, as a spatial filter, is applied. * * <br> * This results in the following encoding: * <code>valueReference,lowerCornerLongitude,lowerCornerLatitude,upperCornerLongitude,upperCornerLatitude,crsURI</code> * * <br> * An example for an SOS conform spatial filter looks like this: * * <code>spatialFilter=om:featureOfInterest/*/sams:shape,0.0,40.0,2.0,43.0,urn:ogc:def:crs:EPSG::4326</code> * * <br> * An example for a ESRI GeoServices REST API conform spatial filter looks like this: * * <code>spatialFilter={xmin:0.0,ymin:40.0,xmax:2.0,ymax:43.0,spatialReference:{wkid:4326}}</code> * * @param spatialFilterOGC * @return a spatial filter that conforms to ESRI's GeoServices REST API (ArcGIS REST API) */ protected String convertSpatialFilterFromOGCtoArcGisREST(String spatialFilterOGC) { String[] spatialFilterOGCSubComponentArray = spatialFilterOGC.split(","); // check if array contains 6 members, otherwise throw exception if (spatialFilterOGCSubComponentArray.length != 6) { throw new IllegalArgumentException("Error while decoding spatialFilter: '" + spatialFilterOGC + "'. A split(',') should result in 6 member array."); } String valueReference = spatialFilterOGCSubComponentArray[0]; String crsURI = spatialFilterOGCSubComponentArray[5]; // check 'valueReference': if (!valueReference.equalsIgnoreCase("om:featureOfInterest/*/sams:shape")) { throw new IllegalArgumentException("Error, can only handle 'spatialFilter' with valueReference = 'om:featureOfInterest/*/sams:shape'. The valueReference '" + valueReference + "' is not supported."); } // check 'valueReference': if (!crsURI.equalsIgnoreCase("urn:ogc:def:crs:EPSG::4326")) { throw new IllegalArgumentException("Error, can only handle 'spatialFilter' with crsURI = 'urn:ogc:def:crs:EPSG::4326'. The crsURI '" + crsURI + "' is not supported."); } String lowerCornerLongitude = spatialFilterOGCSubComponentArray[1]; String lowerCornerLatitude = spatialFilterOGCSubComponentArray[2]; String upperCornerLongitude = spatialFilterOGCSubComponentArray[3]; String upperCornerLatitude = spatialFilterOGCSubComponentArray[4]; return "{xmin:"+ lowerCornerLongitude + ",ymin:"+ lowerCornerLatitude + ",xmax:"+ upperCornerLongitude + ",ymax:"+ upperCornerLatitude + ",spatialReference:{wkid:4326}}"; } /** * This method converts from OGC (ISO 8601) to ArcGIS REST API-style time filters. * * 1) * OGC: 2011-10-18T10:00/2011-10-19T10:00 * to * ArcGIS REST API: during:2011-10-18T10:00:00+00:00,2011-10-19T10:00:00+00:00 * * 2) * OGC: 2011-10-18T00:00 * to * ArcGIS REST API: equals:2011-10-18T00:00:00+00:00 * * @param temporalFilterOGC * @return * @throws InvalidParameterValueException */ protected static String convertTemporalFilterFromOGCtoArcGisREST(String temporalFilterOGC) { String result = ""; ITime timeObj = TimeFactory.createTime(temporalFilterOGC); if (timeObj instanceof ITimePosition) { result += "equals:"; result += timeObj.toISO8601Format(); } else if (timeObj instanceof ITimePeriod) { result += "during:"; ITimePeriod timePeriod = (ITimePeriod)timeObj; result += timePeriod.getStart().toISO8601Format() + "," + timePeriod.getEnd().toISO8601Format(); } return result; } @Override public boolean canHandle(String operationName) { return operationName.equalsIgnoreCase(getOperationName()); } protected abstract String getOperationName(); @Override public int compareTo(OperationRequestHandler o) { return this.getExecutionPriority() - o.getExecutionPriority(); } }