All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.webcohesion.enunciate.modules.jaxws.JaxwsModule Maven / Gradle / Ivy

There is a newer version: 2.18.1
Show newest version
/**
 * Copyright © 2006-2016 Web Cohesion ([email protected])
 *
 * 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.jaxws;

import com.webcohesion.enunciate.EnunciateContext;
import com.webcohesion.enunciate.EnunciateException;
import com.webcohesion.enunciate.api.ApiRegistry;
import com.webcohesion.enunciate.module.*;
import com.webcohesion.enunciate.modules.jaxb.JaxbModule;
import com.webcohesion.enunciate.modules.jaxb.model.ImplicitChildElement;
import com.webcohesion.enunciate.modules.jaxws.model.*;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.apache.commons.configuration.XMLConfiguration;
import org.reflections.adapters.MetadataAdapter;

import javax.jws.WebService;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.bind.annotation.XmlTransient;
import java.io.File;
import java.util.*;

/**
 * @author Ryan Heaton
 */
@SuppressWarnings ( "unchecked" )
public class JaxwsModule extends BasicProviderModule implements TypeDetectingModule, ApiRegistryProviderModule, ApiFeatureProviderModule, WebInfAwareModule {

  private JaxbModule jaxbModule;
  private DataTypeDetectionStrategy defaultDataTypeDetectionStrategy;
  private EnunciateJaxwsContext jaxwsContext;
  private File webInfDir;

  @Override
  public String getName() {
    return "jaxws";
  }

  @Override
  public List getDependencySpecifications() {
    return Arrays.asList((DependencySpec) new JaxbDependencySpec());
  }

  public EnunciateJaxwsContext getJaxwsContext() {
    return jaxwsContext;
  }

  @Override
  public ApiRegistry getApiRegistry() {
    return new JaxwsApiRegistry(this.jaxwsContext);
  }

  public DataTypeDetectionStrategy getDataTypeDetectionStrategy() {
    String dataTypeDetection = this.config.getString("[@datatype-detection]", null);

    if (dataTypeDetection != null) {
      try {
        return DataTypeDetectionStrategy.valueOf(dataTypeDetection);
      }
      catch (IllegalArgumentException e) {
        //fall through...
      }
    }

    if (this.defaultDataTypeDetectionStrategy != null) {
      return this.defaultDataTypeDetectionStrategy;
    }

    if (this.enunciate.getIncludePatterns().isEmpty()) {
      //if there are no configured include patterns, then we'll just stick with "local" detection so we don't include too much.
      return DataTypeDetectionStrategy.local;
    }
    else {
      //otherwise, we'll assume the user knows what (s)he's doing and aggressively include everything.
      return DataTypeDetectionStrategy.aggressive;
    }
  }

  public void setDefaultDataTypeDetectionStrategy(DataTypeDetectionStrategy strategy) {
    this.defaultDataTypeDetectionStrategy = strategy;
  }

  private boolean isUseSourceParameterNames() {
    return this.config.getBoolean("[@useSourceParameterNames]", false);
  }

  private boolean isAggressiveWebMethodExcludePolicy() {
    return this.config.getBoolean("[@aggressiveWebMethodExcludePolicy]", false);
  }

  @Override
  public void setWebInfDir(File webInfDir) {
    this.webInfDir = webInfDir;
  }

  public File getSunJaxwsXmlFile() {
    File sunJaxwsXmlFile = null;

    String configuredSunJaxwsXmlFile = this.config.getString("[@sun-jaxws-xml-file]", null);
    if (configuredSunJaxwsXmlFile != null) {
      sunJaxwsXmlFile = resolveFile(configuredSunJaxwsXmlFile);
    }
    else if (this.webInfDir != null) {
      sunJaxwsXmlFile = new File(this.webInfDir, "sun-jaxws.xml");
    }

    if (sunJaxwsXmlFile != null && sunJaxwsXmlFile.exists()) {
      return sunJaxwsXmlFile;
    }

    return null;
  }

  @Override
  public void call(EnunciateContext context) {
    jaxwsContext = new EnunciateJaxwsContext(this.jaxbModule.getJaxbContext(), isUseSourceParameterNames());
    boolean aggressiveWebMethodExcludePolicy = isAggressiveWebMethodExcludePolicy();

    Map eiPaths = new HashMap();
    File sunJaxwsXmlFile = getSunJaxwsXmlFile();
    if (sunJaxwsXmlFile != null) {
      XMLConfiguration config;
      try {
        config = new XMLConfiguration(sunJaxwsXmlFile);
      }
      catch (ConfigurationException e) {
        throw new EnunciateException(e);
      }

      List endpoints = config.configurationsAt("endpoint");
      for (HierarchicalConfiguration endpoint : endpoints) {
        String impl = endpoint.getString("[@implementation]", null);
        String urlPattern = endpoint.getString("[@url-pattern]", null);
        if (impl != null && urlPattern != null) {
          eiPaths.put(impl, urlPattern);
        }
      }
    }

    DataTypeDetectionStrategy detectionStrategy = getDataTypeDetectionStrategy();
    if (detectionStrategy != DataTypeDetectionStrategy.passive) {
      Set elements = detectionStrategy == DataTypeDetectionStrategy.local ? context.getLocalApiElements() : context.getApiElements();
      for (Element declaration : elements) {
        if (declaration instanceof TypeElement) {
          TypeElement element = (TypeElement) declaration;

          XmlRegistry registryMetadata = declaration.getAnnotation(XmlRegistry.class);
          if (registryMetadata != null) {
            this.jaxbModule.addPotentialJaxbElement(element, new LinkedList());
          }

          if (isEndpointInterface(element)) {
            EndpointInterface ei = new EndpointInterface(element, elements, aggressiveWebMethodExcludePolicy, jaxwsContext);
            for (EndpointImplementation implementation : ei.getEndpointImplementations()) {
              String urlPattern = eiPaths.get(implementation.getQualifiedName().toString());
              if (urlPattern != null) {
                if (!urlPattern.startsWith("/")) {
                  urlPattern = "/" + urlPattern;
                }

                if (urlPattern.endsWith("/*")) {
                  urlPattern = urlPattern.substring(0, urlPattern.length() - 2) + ei.getServiceName();
                }

                implementation.setPath(urlPattern);
              }
            }
            jaxwsContext.add(ei);
            addReferencedDataTypeDefinitions(ei);
          }
        }
      }
    }
  }

  protected void addReferencedDataTypeDefinitions(EndpointInterface ei) {
    LinkedList contextStack = new LinkedList();
    contextStack.push(ei);
    try {
      for (WebMethod webMethod : ei.getWebMethods()) {
        addReferencedTypeDefinitions(webMethod, contextStack);
      }
    }
    finally {
      contextStack.pop();
    }
  }

  protected void addReferencedTypeDefinitions(WebMethod webMethod, LinkedList contextStack) {
    contextStack.push(webMethod);
    try {
      WebResult result = webMethod.getWebResult();
      this.jaxbModule.getJaxbContext().addReferencedTypeDefinitions(result.isAdapted() ? result.getAdapterType() : result.getType(), contextStack);
      for (WebParam webParam : webMethod.getWebParameters()) {
        this.jaxbModule.getJaxbContext().addReferencedTypeDefinitions(webParam.isAdapted() ? webParam.getAdapterType() : webParam.getType(), contextStack);
      }
      for (WebFault webFault : webMethod.getWebFaults()) {
        addReferencedTypeDefinitions(webFault, contextStack);
      }
    }
    finally {
      contextStack.pop();
    }
  }

  protected void addReferencedTypeDefinitions(WebFault webFault, LinkedList contextStack) {
    contextStack.push(webFault);
    try {
      if (webFault.isImplicitSchemaElement()) {
        for (ImplicitChildElement childElement : webFault.getChildElements()) {
          WebFault.FaultBeanChildElement fbce = (WebFault.FaultBeanChildElement) childElement;
          this.jaxbModule.getJaxbContext().addReferencedTypeDefinitions(fbce.isAdapted() ? fbce.getAdapterType() : fbce.getType(), contextStack);
        }
      }
      else {
        DeclaredType faultBeanType = webFault.getExplicitFaultBeanType();
        if (faultBeanType != null) {
          this.jaxbModule.getJaxbContext().addReferencedTypeDefinitions(faultBeanType, contextStack);
        }
      }
    }
    finally {
      contextStack.pop();
    }
  }

  @Override
  public boolean typeDetected(Object type, MetadataAdapter metadata) {
    String classname = metadata.getClassName(type);
    if (classname.startsWith("com.sun.xml.ws")) {
      //don't accept jax-ws implementation-specific types
      return false;
    }

    List classAnnotations = metadata.getClassAnnotationNames(type);
    if (classAnnotations != null) {
      for (String classAnnotation : classAnnotations) {
        if (WebService.class.getName().equals(classAnnotation)) {
          return true;
        }
      }
    }
    return false;
  }

  /**
   * A quick check to see if a declaration is an endpoint interface.
   */
  public boolean isEndpointInterface(TypeElement declaration) {
    WebService ws = declaration.getAnnotation(WebService.class);
    return declaration.getAnnotation(XmlTransient.class) == null
      && ws != null
      && ((declaration.getKind() == ElementKind.INTERFACE)
      //if this is a class declaration, then it has an "implicit" endpoint interface if it doesn't reference another.
      || (ws.endpointInterface() == null) || ("".equals(ws.endpointInterface())));
  }

  public class JaxbDependencySpec implements DependencySpec {

    @Override
    public boolean accept(EnunciateModule module) {
      if (module instanceof JaxbModule) {
        jaxbModule = ((JaxbModule) module);
        jaxbModule.setDefaultDataTypeDetectionStrategy(DataTypeDetectionStrategy.passive);
        return true;
      }

      return false;
    }

    @Override
    public boolean isFulfilled() {
      return jaxbModule != null;
    }


    @Override
    public String toString() {
      return "jaxb";
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy