/** * Copyright © 2006-2016 Web Cohesion (info@webcohesion.com) * * 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 com.webcohesion.enunciate.modules.jaxrs.model; import com.webcohesion.enunciate.javac.decorations.element.DecoratedExecutableElement; import com.webcohesion.enunciate.javac.decorations.type.TypeMirrorUtils; import com.webcohesion.enunciate.modules.jaxrs.EnunciateJaxrsContext; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.TypeMirror; import javax.ws.rs.Path; import java.util.*; import static com.webcohesion.enunciate.modules.jaxrs.model.Resource.extractPathComponents; /** * A sub-resource locator. Invoked on a JAX-RS resource in order to locate a subresource. * * @author Ryan Heaton */ public class SubResourceLocator extends DecoratedExecutableElement implements PathContext { private final Path path; private final List<PathSegment> pathComponents; private final SubResource resource; private final Resource parent; private final List<ResourceParameter> resourceParameters; private final VariableElement entityParameter; private final EnunciateJaxrsContext context; public SubResourceLocator(ExecutableElement delegate, Resource parent, EnunciateJaxrsContext context) { super(delegate, context.getContext().getProcessingEnvironment()); this.context = context; this.parent = parent; this.path = delegate.getAnnotation(Path.class); if (this.path == null) { throw new IllegalArgumentException("A subresource locator must specify a path with the @javax.ws.rs.Path annotation."); } this.pathComponents = extractPathComponents(this.path.value()); SubResource resource; TypeMirror returnType = delegate.getReturnType(); if ((returnType instanceof DeclaredType) && ((DeclaredType) returnType).asElement() != null) { TypeElement declaration = (TypeElement) ((DeclaredType) returnType).asElement(); if (Class.class.getName().equals(declaration.getQualifiedName().toString())) { //subresource locators may return the class instead of the instance, so unwrap. List<? extends TypeMirror> classTypes = ((DeclaredType) returnType).getTypeArguments(); if (classTypes != null && classTypes.size() > 0) { returnType = classTypes.get(0); if ((returnType instanceof DeclaredType) && ((DeclaredType) returnType).asElement() != null) { declaration = (TypeElement) ((DeclaredType) returnType).asElement(); resource = findRecursiveSubResource(declaration, getPath()); resource = resource == null ? new SubResource(declaration, getPath(), this, context) : resource; } else { resource = new SubResource((TypeElement) TypeMirrorUtils.objectType(context.getContext().getProcessingEnvironment()).asElement(), getPath(), this, context); } } else { resource = new SubResource((TypeElement) TypeMirrorUtils.objectType(context.getContext().getProcessingEnvironment()).asElement(), getPath(), this, context); } } else { resource = findRecursiveSubResource(declaration, getPath()); resource = resource == null ? new SubResource(declaration, getPath(), this, context) : resource; } } else { resource = new SubResource((TypeElement) TypeMirrorUtils.objectType(context.getContext().getProcessingEnvironment()).asElement(), getPath(), this, context); } this.resource = resource; VariableElement entityParameter = null; List<ResourceParameter> resourceParameters = new ArrayList<ResourceParameter>(); for (VariableElement parameterDeclaration : delegate.getParameters()) { if (ResourceParameter.isResourceParameter(parameterDeclaration, context)) { resourceParameters.add(new ResourceParameter(parameterDeclaration, this)); } else { entityParameter = parameterDeclaration; } } this.entityParameter = entityParameter; this.resourceParameters = resourceParameters; } //fix for ENUNCIATE-574 private SubResource findRecursiveSubResource(TypeElement declaration, String path) { LinkedList<SubResource> ancestorResources = SubResource.ANCESTOR_DECLARATIONS.get(); for (SubResource ancestorResource : ancestorResources) { if (ancestorResource.getQualifiedName().equals(declaration.getQualifiedName()) && ancestorResource.getPath().equals(path)) { return ancestorResource; } } return null; } @Override public List<PathSegment> getPathComponents() { List<PathSegment> components = new ArrayList<PathSegment>(); Resource parent = getParent(); if (parent != null) { components.addAll(parent.getPathComponents()); } components.addAll(this.pathComponents); return components; } @Override public EnunciateJaxrsContext getContext() { return this.context; } /** * The path of the subresource. * * @return The path of the subresource. */ public String getPath() { return this.path.value(); } /** * The resource that this locates. * * @return The resource that this locates. */ public SubResource getResource() { return resource; } /** * The resource that hosts this locator. * * @return The resource that hosts this locator. */ public Resource getParent() { return parent; } /** * The list of resource parameters that this method requires to be invoked. * * @return The list of resource parameters that this method requires to be invoked. */ public Set<ResourceParameter> getResourceParameters() { TreeSet<ResourceParameter> resourceParams = new TreeSet<ResourceParameter>(this.resourceParameters); resourceParams.addAll(getParent().getResourceParameters()); return resourceParams; } /** * The entity parameter. * * @return The entity parameter, or null if none. */ public VariableElement getEntityParameter() { return entityParameter; } }