Package org.codehaus.enunciate.contract.jaxrs

Source Code of org.codehaus.enunciate.contract.jaxrs.Resource

/*
* Copyright 2006-2008 Web Cohesion
*
* 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.codehaus.enunciate.contract.jaxrs;

import com.sun.mirror.apt.AnnotationProcessorEnvironment;
import com.sun.mirror.declaration.*;
import com.sun.mirror.type.InterfaceType;
import com.sun.mirror.type.ClassType;
import com.sun.mirror.util.Declarations;
import net.sf.jelly.apt.Context;
import net.sf.jelly.apt.decorations.DeclarationDecorator;
import net.sf.jelly.apt.decorations.declaration.DecoratedDeclaration;
import net.sf.jelly.apt.decorations.declaration.DecoratedTypeDeclaration;
import net.sf.jelly.apt.decorations.declaration.PropertyDeclaration;
import org.codehaus.enunciate.contract.Facet;
import org.codehaus.enunciate.contract.HasFacets;

import javax.ws.rs.*;
import java.util.*;

/**
* A JAX-RS resource.
*
* @author Ryan Heaton
*/
public abstract class Resource extends DecoratedTypeDeclaration implements HasFacets {

  private final String path;
  private final Set<String> consumesMime;
  private final Set<String> producesMime;
  private final List<ResourceParameter> resourceParameters;
  private final List<ResourceMethod> resourceMethods;
  private final List<SubResourceLocator> resourceLocators;
  private final Set<Facet> facets = new TreeSet<Facet>();

  protected Resource(TypeDeclaration delegate, String path) {
    super(delegate);
    if (path == null) {
      throw new NullPointerException();
    }
    this.path = path;

    Set<String> consumes = new TreeSet<String>();
    Consumes consumesInfo = delegate.getAnnotation(Consumes.class);
    if (consumesInfo != null) {
      consumes.addAll(Arrays.asList(JAXRSUtils.value(consumesInfo)));
    }
    else {
      consumes.add("*/*");
    }
    this.consumesMime = Collections.unmodifiableSet(consumes);

    Set<String> produces = new TreeSet<String>();
    Produces producesInfo = delegate.getAnnotation(Produces.class);
    if (producesInfo != null) {
      produces.addAll(Arrays.asList(JAXRSUtils.value(producesInfo)));
    }
    else {
      produces.add("*/*");
    }
    this.producesMime = Collections.unmodifiableSet(produces);

    this.facets.addAll(Facet.gatherFacets(delegate));
    this.resourceParameters = Collections.unmodifiableList(getResourceParameters(delegate));
    this.resourceMethods = Collections.unmodifiableList(getResourceMethods(delegate));
    this.resourceLocators = Collections.unmodifiableList(getSubresourceLocators(delegate));
  }

  /**
   * Get the sub-resource locators for the specified type.
   *
   * @param delegate The type.
   * @return The sub-resource locators.
   */
  protected List<SubResourceLocator> getSubresourceLocators(TypeDeclaration delegate) {
    if (delegate == null || delegate.getQualifiedName().equals(Object.class.getName())) {
      return Collections.emptyList();
    }

    ArrayList<SubResourceLocator> resourceLocators = new ArrayList<SubResourceLocator>();
    METHOD_LOOP : for (MethodDeclaration methodDeclaration : delegate.getMethods()) {
      if (methodDeclaration.getAnnotation(Path.class) != null) { //sub-resource locators are annotated with @Path AND they have no resource method designator.
        for (AnnotationMirror annotation : methodDeclaration.getAnnotationMirrors()) {
          AnnotationTypeDeclaration annotationDeclaration = annotation.getAnnotationType().getDeclaration();
          if (annotationDeclaration != null) {
            if (annotationDeclaration.getAnnotation(HttpMethod.class) != null) {
              continue METHOD_LOOP;
            }
          }
        }

        resourceLocators.add(new SubResourceLocator(methodDeclaration, this));
      }
    }

    //some methods may be specified by a superclass and/or implemented interface.  But the annotations on the current class take precedence.
    for (InterfaceType interfaceType : delegate.getSuperinterfaces()) {
      List<SubResourceLocator> interfaceMethods = getSubresourceLocators(interfaceType.getDeclaration());
      for (SubResourceLocator interfaceMethod : interfaceMethods) {
        if (!isOverridden(interfaceMethod, resourceLocators)) {
          resourceLocators.add(interfaceMethod);
        }
      }
    }

    if (delegate instanceof ClassDeclaration) {
      ClassType superclass = ((ClassDeclaration) delegate).getSuperclass();
      if (superclass != null && superclass.getDeclaration() != null) {
        List<SubResourceLocator> superMethods = getSubresourceLocators(superclass.getDeclaration());
        for (SubResourceLocator superMethod : superMethods) {
          if (!isOverridden(superMethod, resourceLocators)) {
            resourceLocators.add(superMethod);
          }
        }
      }
    }

    return resourceLocators;
  }

  /**
   * Get all the resource methods for the specified type.
   *
   * @param delegate The type.
   * @return The resource methods.
   */
  protected List<ResourceMethod> getResourceMethods(final TypeDeclaration delegate) {
    if (delegate == null || delegate.getQualifiedName().equals(Object.class.getName())) {
      return Collections.emptyList();
    }

    ArrayList<ResourceMethod> resourceMethods = new ArrayList<ResourceMethod>();
    for (MethodDeclaration methodDeclaration : delegate.getMethods()) {
      if (methodDeclaration.getModifiers().contains(Modifier.PUBLIC)) {
        for (AnnotationMirror annotation : methodDeclaration.getAnnotationMirrors()) {
          AnnotationTypeDeclaration annotationDeclaration = annotation.getAnnotationType().getDeclaration();
          if (annotationDeclaration != null) {
            if (annotationDeclaration.getAnnotation(HttpMethod.class) != null) {
              resourceMethods.add(new ResourceMethod(methodDeclaration, this));
              break;
            }
          }
        }
      }
    }

    //some methods may be specified by a superclass and/or implemented interface.  But the annotations on the current class take precedence.
    for (InterfaceType interfaceType : delegate.getSuperinterfaces()) {
      List<ResourceMethod> interfaceMethods = getResourceMethods(interfaceType.getDeclaration());
      for (ResourceMethod interfaceMethod : interfaceMethods) {
        if (!isOverridden(interfaceMethod, resourceMethods)) {
          resourceMethods.add(interfaceMethod);
        }
      }
    }

    if (delegate instanceof ClassDeclaration) {
      ClassType superclass = ((ClassDeclaration) delegate).getSuperclass();
      if (superclass != null && superclass.getDeclaration() != null) {
        List<ResourceMethod> superMethods = getResourceMethods(superclass.getDeclaration());
        for (ResourceMethod superMethod : superMethods) {
          if (!isOverridden(superMethod, resourceMethods)) {
            resourceMethods.add(superMethod);
          }
        }
      }
    }

    return resourceMethods;
  }

  /**
   * Get the resource parameters for the specified delegate.
   *
   * @param delegate The delegate.
   * @return The resource parameters.
   */
  protected List<ResourceParameter> getResourceParameters(TypeDeclaration delegate) {
    if (delegate == null || delegate.getQualifiedName().equals(Object.class.getName())) {
      return Collections.emptyList();
    }

    List<ResourceParameter> resourceParameters = new ArrayList<ResourceParameter>();
    DecoratedTypeDeclaration decorated = (DecoratedTypeDeclaration) DeclarationDecorator.decorate(delegate);
    for (FieldDeclaration field : decorated.getFields()) {
      if (ResourceParameter.isResourceParameter(field)) {
        resourceParameters.add(new ResourceParameter(field));
      }
    }

    for (PropertyDeclaration property : decorated.getProperties()) {
      if (ResourceParameter.isResourceParameter(property)) {
        resourceParameters.add(new ResourceParameter(property));
      }
    }

    if (delegate instanceof ClassDeclaration) {
      List<ResourceParameter> superParams = getResourceParameters(((ClassDeclaration) delegate).getSuperclass().getDeclaration());
      for (ResourceParameter superParam : superParams) {
        if (!isHidden(superParam, resourceParameters)) {
          resourceParameters.add(superParam);
        }
      }
    }

    return resourceParameters;
  }

  /**
   * Whether the specified method is overridden by any of the methods in the specified list.
   *
   * @param method The method.
   * @param resourceMethods The method list.
   * @return If the methdo is overridden by any of the methods in the list.
   */
  protected boolean isOverridden(DecoratedDeclaration method, ArrayList<? extends DecoratedDeclaration> resourceMethods) {
    AnnotationProcessorEnvironment env = Context.getCurrentEnvironment();
    Declarations decls = env.getDeclarationUtils();

    Declaration unwrappedMethod = method.getDelegate();
    while (unwrappedMethod instanceof DecoratedDeclaration) {
      unwrappedMethod = ((DecoratedDeclaration) unwrappedMethod).getDelegate();
    }

    for (DecoratedDeclaration resourceMethod : resourceMethods) {
      Declaration candidate = resourceMethod.getDelegate();
      while (candidate instanceof DecoratedDeclaration) {
        //unwrap the candidate.
        candidate = ((DecoratedDeclaration) candidate).getDelegate();
      }

      if (decls.overrides((MethodDeclaration) candidate, (MethodDeclaration) unwrappedMethod)) {
        return true;
      }
    }

    return false;
  }

  /**
   * Whether the specified resource parameter is hidden by any of the parameters in the specified list.
   *
   * @param param The param to test.
   * @param resourceParameters The other parameters.
   * @return If the parameter is hidden by any of the parameters in the specified list.
   */
  private boolean isHidden(ResourceParameter param, List<ResourceParameter> resourceParameters) {
    AnnotationProcessorEnvironment env = Context.getCurrentEnvironment();
    Declarations decls = env.getDeclarationUtils();

    Declaration unwrappedParam = param.getDelegate();
    while (unwrappedParam instanceof DecoratedDeclaration) {
      unwrappedParam = ((DecoratedDeclaration) unwrappedParam).getDelegate();
    }

    for (ResourceParameter resourceParameter : resourceParameters) {
      Declaration candidate = resourceParameter.getDelegate();
      while (candidate instanceof DecoratedDeclaration) {
        //unwrap the candidate.
        candidate = ((DecoratedDeclaration) candidate).getDelegate();
      }

      if (decls.hides((MemberDeclaration) candidate, (MemberDeclaration) unwrappedParam)) {
        return true;
      }
    }

    return false;
  }

  /**
   * The path to this resource.
   *
   * @return The path to this resource.
   */
  public final String getPath() {
    return this.path;
  }

  /**
   * The parent resource.
   *
   * @return The parent resource, or null if this is a root resource.
   */
  public abstract Resource getParent();

  /**
   * The MIME types that the methods on this resource consumes (possibly overridden).
   *
   * @return The MIME types that the methods on this resource consumes.
   */
  public Set<String> getConsumesMime() {
    return consumesMime;
  }

  /**
   * The MIME types that the methods on this resource consumes (possibly overridden).
   *
   * @return The MIME types that the methods on this resource consumes.
   */
  public Set<String> getProducesMime() {
    return producesMime;
  }

  /**
   * The resource parameters.
   *
   * @return The resource parameters.
   */
  public List<ResourceParameter> getResourceParameters() {
    return resourceParameters;
  }

  /**
   * The resource methods.
   *
   * @return The resource methods.
   */
  public List<ResourceMethod> getResourceMethods() {
    return resourceMethods;
  }

  /**
   * The resource methods.
   *
   * @param loadDescendants Whether to include the resource methods of all sub-resources.
   * @return The resource methods.
   */
  public List<ResourceMethod> getResourceMethods(boolean loadDescendants) {
    if (!loadDescendants) {
      return resourceMethods;
    }
    else {
      List<ResourceMethod> resourceMethods = new ArrayList<ResourceMethod>();
      LinkedList<Resource> resources = new LinkedList<Resource>();
      Set<String> visited = new TreeSet<String>();
      resources.add(this);
      while (!resources.isEmpty()) {
        Resource resource = resources.pop();
        visited.add(resource.getQualifiedName());
        resourceMethods.addAll(resource.getResourceMethods());

        for (SubResourceLocator locator : resource.getResourceLocators()) {
          SubResource subresource = locator.getResource();
          if (!visited.contains(subresource.getQualifiedName())) {
            resources.add(subresource);
          }
        }
      }

      return resourceMethods;
    }
  }

  /**
   * The resource locators.
   *
   * @return The resource locators.
   */
  public List<SubResourceLocator> getResourceLocators() {
    return resourceLocators;
  }

  /**
   * The facets here applicable.
   *
   * @return The facets here applicable.
   */
  public Set<Facet> getFacets() {
    return facets;
  }

}
TOP

Related Classes of org.codehaus.enunciate.contract.jaxrs.Resource

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.