/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.everrest.core.wadl;
import org.everrest.core.Parameter;
import org.everrest.core.impl.resource.AbstractResourceDescriptor;
import org.everrest.core.resource.ResourceDescriptor;
import org.everrest.core.resource.ResourceMethodDescriptor;
import org.everrest.core.resource.SubResourceLocatorDescriptor;
import org.everrest.core.resource.SubResourceMethodDescriptor;
import org.everrest.core.uri.UriPattern;
import org.everrest.core.wadl.research.Application;
import org.everrest.core.wadl.research.Param;
import org.everrest.core.wadl.research.ParamStyle;
import org.everrest.core.wadl.research.RepresentationType;
import org.everrest.core.wadl.research.Resources;
import javax.ws.rs.core.MediaType;
import javax.xml.bind.JAXBElement;
import javax.xml.namespace.QName;
import java.net.URI;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* This class manages process of creation WADL document which describe {@link org.everrest.core.resource.ResourceDescriptor}.
*
* @author andrew00x
*/
public class WadlProcessor {
/** See {@link WadlGenerator}. */
private final WadlGenerator wadlGenerator;
/** Constructs new instance of WadlProcessor which use default WadlGenerator. */
public WadlProcessor() {
this.wadlGenerator = new BaseWadlGeneratorImpl();
}
/**
* Constructs new instance of WadlProcessor with specified WadlGenerator.
*
* @param wadlGenerator
* {@link WadlGenerator}
*/
public WadlProcessor(WadlGenerator wadlGenerator) {
this.wadlGenerator = wadlGenerator;
}
/**
* Process {@link org.everrest.core.resource.ResourceDescriptor} for build its WADL
* representation.
*
* @param resourceDescriptor
* see {@link org.everrest.core.resource.ResourceDescriptor}
* @param baseURI
* base URI of resource, e. g. servlet context
* @return {@link Application}
*/
public Application process(ResourceDescriptor resourceDescriptor, URI baseURI) {
// Root component of WADL representation
Application wadlApp = wadlGenerator.createApplication();
// Container for resources
Resources wadlResources = wadlGenerator.createResources();
if (baseURI != null) {
wadlResources.setBase(baseURI.toString());
}
org.everrest.core.wadl.research.Resource wadlResource = processResource(resourceDescriptor);
wadlResources.getResource().add(wadlResource);
wadlApp.setResources(wadlResources);
return wadlApp;
}
/**
* @param resourceDescriptor
* see {@link org.everrest.core.resource.ResourceDescriptor}
* @return see {@link WadlGenerator#createResponse()}
*/
private org.everrest.core.wadl.research.Resource processResource(ResourceDescriptor resourceDescriptor) {
org.everrest.core.wadl.research.Resource wadlResource = wadlGenerator.createResource(resourceDescriptor);
// Keeps common parameters for resource.
Map<String, Param> wadlResourceParams = new HashMap<String, Param>();
Map<String, List<ResourceMethodDescriptor>> resourceMethods = resourceDescriptor.getResourceMethods();
for (List<ResourceMethodDescriptor> l : resourceMethods.values()) {
for (ResourceMethodDescriptor rmd : l) {
org.everrest.core.wadl.research.Method wadlMethod = processMethod(rmd, wadlResourceParams);
if (wadlMethod == null) {
continue;
}
wadlResource.getMethodOrResource().add(wadlMethod);
}
}
// Add parameters to a resource
for (Param p : wadlResourceParams.values()) {
wadlResource.getParam().add(p);
}
processSubResourceMethods(wadlResource, resourceDescriptor);
processSubResourceLocators(wadlResource, resourceDescriptor);
return wadlResource;
}
/**
* Process sub-resource methods.
*
* @param wadlResource
* see {@link org.everrest.core.wadl.research.Resource}
* @param resourceDescriptor
* see {@link org.everrest.core.resource.ResourceDescriptor}
*/
private void processSubResourceMethods(org.everrest.core.wadl.research.Resource wadlResource,
ResourceDescriptor resourceDescriptor) {
// Keeps common parameter for sub-resource.
Map<String, Map<String, Param>> wadlCommonSubResourceParams = new HashMap<String, Map<String, Param>>();
// Mapping resource path to resource.
Map<String, org.everrest.core.wadl.research.Resource> wadlSubResources =
new HashMap<String, org.everrest.core.wadl.research.Resource>();
Map<UriPattern, Map<String, List<SubResourceMethodDescriptor>>> subresourceMethods = resourceDescriptor.getSubResourceMethods();
for (Map<String, List<SubResourceMethodDescriptor>> rmm : subresourceMethods.values()) {
for (List<SubResourceMethodDescriptor> l : rmm.values()) {
for (SubResourceMethodDescriptor srmd : l) {
String path = srmd.getPathValue().getPath();
org.everrest.core.wadl.research.Resource wadlSubResource = wadlSubResources.get(path);
// There is no any resource for 'path' yet.
if (wadlSubResource == null) {
wadlSubResource = wadlGenerator.createResource(path);
Map<String, Param> wadlResourceParams = new HashMap<String, Param>();
org.everrest.core.wadl.research.Method wadlMethod = processMethod(srmd, wadlResourceParams);
if (wadlMethod == null) {
continue;
}
wadlSubResource.getMethodOrResource().add(wadlMethod);
// Remember sub-resource and parameters.
wadlSubResources.put(path, wadlSubResource);
wadlCommonSubResourceParams.put(path, wadlResourceParams);
} else {
// Get parameters for sub-resource that was created by one of previous
// iteration.
Map<String, Param> wadlResourceParams = wadlCommonSubResourceParams.get(path);
// Add new method.
org.everrest.core.wadl.research.Method wadlMethod = processMethod(srmd, wadlResourceParams);
if (wadlMethod == null) {
continue;
}
wadlSubResource.getMethodOrResource().add(wadlMethod);
}
}
}
}
// Add sub-resources to the root resource.
for (Map.Entry<String, org.everrest.core.wadl.research.Resource> entry : wadlSubResources.entrySet()) {
String path = entry.getKey();
org.everrest.core.wadl.research.Resource wadlSubResource = entry.getValue();
for (Param wadlSubParam : wadlCommonSubResourceParams.get(path).values()) {
wadlSubResource.getParam().add(wadlSubParam);
}
wadlResource.getMethodOrResource().add(wadlSubResource);
}
}
/**
* Process sub-resource locators.
*
* @param wadlResource
* see {@link org.everrest.core.wadl.research.Resource}
* @param resourceDescriptor
* see {@link org.everrest.core.resource.ResourceDescriptor}
*/
private void processSubResourceLocators(org.everrest.core.wadl.research.Resource wadlResource,
ResourceDescriptor resourceDescriptor) {
for (SubResourceLocatorDescriptor srld : resourceDescriptor.getSubResourceLocators().values()) {
ResourceDescriptor subResourceDescriptor = new AbstractResourceDescriptor(srld.getMethod().getReturnType()) {
@Override
protected void processConstructors() {
}
@Override
protected void processFields() {
}
};
org.everrest.core.wadl.research.Resource wadlSubResource = processResource(subResourceDescriptor);
wadlSubResource.setPath(srld.getPathValue().getPath());
wadlResource.getMethodOrResource().add(wadlSubResource);
}
}
/**
* @param rmd
* see {@link ResourceMethodDescriptor}
* @param wadlResourceParams
* for adding parameters which must be in parent
* @return {@link org.everrest.core.wadl.research.Method}
*/
private org.everrest.core.wadl.research.Method processMethod(ResourceMethodDescriptor rmd,
Map<String, Param> wadlResourceParams) {
org.everrest.core.wadl.research.Method wadlMethod = wadlGenerator.createMethod(rmd);
// See description of this in
// BaseWadlGeneratorImpl.createMethod(ResourceMethodDescriptor)
if (wadlMethod == null) {
return null;
}
org.everrest.core.wadl.research.Request wadlRequest = processRequest(rmd, wadlResourceParams);
if (wadlRequest != null) {
wadlMethod.setRequest(wadlRequest);
}
org.everrest.core.wadl.research.Response wadlResponse = processResponse(rmd);
if (wadlResponse != null) {
wadlMethod.setResponse(wadlResponse);
}
return wadlMethod;
}
/**
* @param rmd
* see {@link ResourceMethodDescriptor}
* @param wadlResourceParams
* for adding parameters which must be in parent
* @return {@link org.everrest.core.wadl.research.Request}
*/
private org.everrest.core.wadl.research.Request processRequest(ResourceMethodDescriptor rmd,
Map<String, Param> wadlResourceParams) {
org.everrest.core.wadl.research.Request wadlRequest = wadlGenerator.createRequest();
for (Parameter methodParameter : rmd.getMethodParameters()) {
if (methodParameter.getAnnotation() == null) {
for (MediaType mediaType : rmd.consumes()) {
RepresentationType wadlRepresentation = wadlGenerator.createRequestRepresentation(mediaType);
wadlRequest.getRepresentation().add(wadlRepresentation);
}
}
Param wadlParam = processParam(methodParameter);
if (wadlParam != null) {
if (wadlParam.getStyle() == ParamStyle.QUERY || wadlParam.getStyle() == ParamStyle.HEADER
/* || wadlParam.getStyle() == ParamStyle.MATRIX */) {
wadlRequest.getParam().add(wadlParam);
} else {
// If matrix or path template parameter then add in map for add in
// parent element
wadlResourceParams.put(wadlParam.getName(), wadlParam);
}
}
}
// NOTE If there are no any representation and parameters then request is
// null.
return wadlRequest.getRepresentation().isEmpty() && wadlRequest.getParam().isEmpty() ? null : wadlRequest;
}
/**
* @param rmd
* see {@link ResourceMethodDescriptor}
* @return {@link org.everrest.core.wadl.research.Response}
*/
private org.everrest.core.wadl.research.Response processResponse(ResourceMethodDescriptor rmd) {
org.everrest.core.wadl.research.Response wadlResponse = null;
if (rmd.getResponseType() != void.class) {
wadlResponse = wadlGenerator.createResponse();
for (MediaType mediaType : rmd.produces()) {
RepresentationType wadlRepresentation = wadlGenerator.createResponseRepresentation(mediaType);
// Element can represent normal response or fault response
JAXBElement<RepresentationType> wadlRepresentationElement =
new JAXBElement<RepresentationType>(new QName("http://research.sun.com/wadl/2006/10", "representation"),
RepresentationType.class, wadlRepresentation);
wadlResponse.getRepresentationOrFault().add(wadlRepresentationElement);
}
}
return wadlResponse;
}
/**
* @param methodParameter
* see {@link Parameter}
* @return {@link Param}
*/
private Param processParam(Parameter methodParameter) {
Param wadlParam = null;
// Skip parameters without annotation (entity) and parameters with javax.ws.rs.core.Context.
// Context parameter dependent of environment and not used in WADL representation
if (methodParameter.getAnnotation() != null
&& methodParameter.getAnnotation().annotationType() != javax.ws.rs.core.Context.class) {
wadlParam = wadlGenerator.createParam(methodParameter);
}
return wadlParam;
}
}