/**
* Copyright (C) 2012-2017 52°North Initiative for Geospatial Open Source
* Software GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
* If the program is linked with libraries which are licensed under one of
* the following licenses, the combination of the program with the linked
* library is not considered a "derivative work" of the program:
*
* - Apache License, version 2.0
* - Apache Software License, version 1.0
* - GNU Lesser General Public License, version 3
* - Mozilla Public License, versions 1.0, 1.1 and 2.0
* - Common Development and Distribution License (CDDL), version 1.0
*
* Therefore the distribution of the program linked with libraries licensed
* under the aforementioned licenses, is permitted by the copyright holders
* if the distribution is compliant with both the GNU General Public
* License version 2 and the aforementioned licenses.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*/
package org.n52.sos.binding.rest.encode;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import net.opengis.sosREST.x10.LinkType;
import net.opengis.sosREST.x10.ResourceCollectionType;
import org.apache.xmlbeans.XmlObject;
import org.apache.xmlbeans.XmlOptions;
import org.n52.sos.binding.rest.requests.RestResponse;
import org.n52.sos.exception.ows.concrete.EncoderResponseUnsupportedException;
import org.n52.sos.exception.ows.concrete.ErrorWhileSavingResponseToOutputStreamException;
import org.n52.sos.ogc.ows.OwsExceptionReport;
import org.n52.sos.response.ServiceResponse;
import org.n52.sos.util.XmlOptionsHelper;
import org.n52.sos.util.http.HTTPHeaders;
import org.n52.sos.util.http.HTTPMethods;
import org.n52.sos.util.http.HTTPStatus;
/**
* @author <a href="mailto:e.h.juerrens@52north.org">Eike Hinderk Jürrens</a>
*
*/
public abstract class ResourceEncoder extends RestEncoder {
public abstract ServiceResponse encodeRestResponse(RestResponse objectToEncode) throws OwsExceptionReport;
protected String createHrefForResourceType(String resourceType)
{
return bindingConstants.getServiceUrl()
.concat(bindingConstants.getUrlPattern())
.concat("/")
.concat(resourceType);
}
protected String createHrefForResourceAndIdentifier(String resourceType,
String identifier)
{
return createHrefForResourceType(resourceType)
.concat("/")
.concat(identifier);
}
protected String createHrefForResourceTypeAndQueryString(String resourceType, String queryString) {
return createHrefForResourceType(resourceType)
.concat("?")
.concat(queryString);
}
protected void setValuesOfLinkToDynamicResource(LinkType xb_RestLink, String resourceQueryString, String relation, String resourceTypeIdentifier)
{
setLinkValues(xb_RestLink,
createRelationWithNamespace(relation),
createHrefForResourceTypeAndQueryString(resourceTypeIdentifier, resourceQueryString),
bindingConstants.getContentTypeDefault().toString());
}
protected void setValuesOfLinkToGlobalResource(LinkType xb_Link,
String relationIdentifier,
String resourceType)
{
setLinkValues(xb_Link,
createRelationWithNamespace(relationIdentifier),
createHrefForResourceType(resourceType),
bindingConstants.getContentTypeDefault().toString());
}
protected void setValuesOfLinkToUniqueResource(LinkType xb_RestLink, String resourceId, String relation, String resourceType)
{
setLinkValues(xb_RestLink,
createRelationWithNamespace(relation),
createHrefForResourceAndIdentifier(resourceType, resourceId),
bindingConstants.getContentTypeDefault().toString());
}
protected void setLinkValues(LinkType xb_Link, String rel, String href, String type) {
xb_Link.setRel(rel);
xb_Link.setHref(href);
xb_Link.setType(type);
}
protected String createRelationWithNamespace(String relation)
{
return bindingConstants.getEncodingNamespace().concat("/").concat(relation);
}
protected void setOfferingLinks(XmlObject xb_AnyType,
List<String> offeringIdentifiers)
{
if (xb_AnyType instanceof net.opengis.sosREST.x10.CapabilitiesType || xb_AnyType instanceof ResourceCollectionType) {
LinkType xb_RestLink = null;
for (String offeringIdentifier : offeringIdentifiers) {
if (xb_AnyType instanceof net.opengis.sosREST.x10.CapabilitiesType) {
xb_RestLink = ((net.opengis.sosREST.x10.CapabilitiesType)xb_AnyType).addNewLink();
} else {
xb_RestLink = ((ResourceCollectionType)xb_AnyType).addNewLink();
}
setValuesOfLinkToUniqueResource(xb_RestLink,
offeringIdentifier,
bindingConstants.getResourceRelationOfferingGet(),
bindingConstants.getResourceOfferings());
}
}
}
protected ServiceResponse createServiceResponseFromXBDocument(XmlObject xb_RestDoc,
String resourceType,
HTTPStatus httpResponseCode,
boolean isResourceCollection,
boolean isGlobalResource) throws OwsExceptionReport
{
return createServiceResponseFromXBDocument(xb_RestDoc,
resourceType,
null,
httpResponseCode,
isResourceCollection,
isGlobalResource);
}
protected ServiceResponse createServiceResponseFromXBDocument(
XmlObject xb_RestDoc,
String resourceType,
Map<String, String> additionalHeaders,
HTTPStatus status,
boolean isResourceCollection,
boolean isGlobalResource) throws OwsExceptionReport {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
xb_RestDoc.save(baos, getDefaultXMLOptions());
} catch (IOException ex) {
throw new ErrorWhileSavingResponseToOutputStreamException(ex);
}
ServiceResponse response = new ServiceResponse(
baos,
bindingConstants.getContentTypeDefault(),
status);
setAllowHeadersForResourceType(response, resourceType, isResourceCollection, isGlobalResource);
if (additionalHeaders != null && additionalHeaders.size() > 0) {
for (String headerIdentifier : additionalHeaders.keySet()) {
if (headerIdentifier != null && !headerIdentifier.isEmpty()) {
String value = additionalHeaders.get(headerIdentifier);
if (value != null) {
response.setHeader(headerIdentifier, value);
}
}
}
}
return response;
}
private void setAllowHeadersForResourceType(ServiceResponse response,
String resourceType,
boolean isResourceCollection,
boolean isGlobalResource)
{
String allowedMethods = getAllowedHttpMethodsForResourceType(
resourceType, isResourceCollection, isGlobalResource);
response.setHeader(HTTPHeaders.ACCESS_CONTROL_ALLOW_METHODS, allowedMethods);
response.setHeader(HTTPHeaders.ALLOW, allowedMethods);
}
private String getAllowedHttpMethodsForResourceType(String bindingOperation,
boolean isResourceCollection,
boolean isGlobalResource)
{
StringBuffer allowedOperations = new StringBuffer("");
allowHttpGet(allowedOperations);
appendAllowHttpOptions(allowedOperations);
if (bindingOperation.equalsIgnoreCase(bindingConstants.getResourceObservations()))
{
if (isGlobalResource && !isResourceCollection)
{
appendAllowHttpPost(allowedOperations);
}
else if (!isGlobalResource && !isResourceCollection)
{
appendAllowHttpDelete(allowedOperations);
}
}
else if (bindingOperation.equalsIgnoreCase(bindingConstants.getResourceSensors()))
{
if (!isGlobalResource && !isResourceCollection)
{
appendAllowHttpPut(allowedOperations);
appendAllowHttpDelete(allowedOperations);
}
else if (isGlobalResource && isResourceCollection)
{
appendAllowHttpPost(allowedOperations);
}
}
return allowedOperations.toString();
}
private void appendAllowHttpDelete(StringBuffer allowedOperations) {
allowedOperations.append(", ").append(HTTPMethods.DELETE);
}
private void appendAllowHttpOptions(StringBuffer allowedOperations) {
allowedOperations.append(", ").append(HTTPMethods.OPTIONS);
}
private void appendAllowHttpPost(StringBuffer allowedOperations) {
allowedOperations.append(", ").append(HTTPMethods.POST);
}
private void appendAllowHttpPut(StringBuffer allowedOperations) {
allowedOperations.append(", ").append(HTTPMethods.PUT);
}
private void allowHttpGet(StringBuffer allowedOperations) {
allowedOperations.append(HTTPMethods.GET);
}
protected XmlOptions getDefaultXMLOptions()
{
XmlOptions bindingXmlOptions = new XmlOptions(XmlOptionsHelper.getInstance().getXmlOptions());
@SuppressWarnings("unchecked")
Map<String,String> prefixes =
(Map<String,String>) bindingXmlOptions.get(XmlOptions.SAVE_SUGGESTED_PREFIXES);
prefixes.put(bindingConstants.getEncodingNamespace(), bindingConstants.getEncodingPrefix());
bindingXmlOptions.setSaveSuggestedPrefixes(prefixes);
bindingXmlOptions.setSaveImplicitNamespaces(prefixes);
return bindingXmlOptions;
}
protected OwsExceptionReport createResponseNotSupportedException(String expectedClassString, Object receivedObject)
{
return new EncoderResponseUnsupportedException().
withMessage("Received RestResponse is not a '%s' but of type '%s'",
expectedClassString,
receivedObject!=null?receivedObject.getClass().getName():"null");
}
protected void addLocationHeader(ServiceResponse response,
String resourceType)
{
addLocationHeader(response, null, resourceType);
}
protected void addLocationHeader(ServiceResponse response,
String resourceId,
String resourceType)
{
final String location;
if (resourceId == null) {
location = createHrefForResourceType(resourceType);
} else {
location = createHrefForResourceAndIdentifier(resourceType,
resourceId);
}
response.setHeader(HTTPHeaders.LOCATION, location);
}
protected ServiceResponse createNoContentResponse(String resourceType,
boolean isResourceCollection,
boolean isGlobalResource)
{
return createContentlessResponse(resourceType, HTTPStatus.NO_CONTENT,isResourceCollection,isGlobalResource);
}
protected ServiceResponse createContentlessResponse(String resourceType,
HTTPStatus httpStatusCode,
boolean isResourceCollection,
boolean isGlobalResource)
{
ServiceResponse response = new ServiceResponse(bindingConstants.getContentTypeDefault(),httpStatusCode);
setAllowHeadersForResourceType(response, resourceType, isResourceCollection, isGlobalResource);
return response;
}
}