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

org.codehaus.enunciate.modules.jboss.JBossDeploymentModule Maven / Gradle / Ivy

/*
 * 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.modules.jboss;

import com.sun.mirror.declaration.TypeDeclaration;
import freemarker.template.TemplateException;
import org.apache.commons.digester.RuleSet;
import org.codehaus.enunciate.EnunciateException;
import org.codehaus.enunciate.apt.EnunciateClasspathListener;
import org.codehaus.enunciate.apt.EnunciateFreemarkerModel;
import org.codehaus.enunciate.config.EnunciateConfiguration;
import org.codehaus.enunciate.config.WsdlInfo;
import org.codehaus.enunciate.config.war.WebAppConfig;
import org.codehaus.enunciate.contract.jaxrs.ResourceMethod;
import org.codehaus.enunciate.contract.jaxrs.RootResource;
import org.codehaus.enunciate.contract.jaxws.EndpointInterface;
import org.codehaus.enunciate.contract.validation.ValidationException;
import org.codehaus.enunciate.contract.validation.Validator;
import org.codehaus.enunciate.jboss.EnunciateJBossHttpServletDispatcher;
import org.codehaus.enunciate.main.Enunciate;
import org.codehaus.enunciate.main.webapp.BaseWebAppFragment;
import org.codehaus.enunciate.main.webapp.WebAppComponent;
import org.codehaus.enunciate.modules.FreemarkerDeploymentModule;
import org.codehaus.enunciate.modules.SpecProviderModule;
import org.codehaus.enunciate.modules.jboss.config.JBossRuleSet;
import org.jboss.resteasy.plugins.server.servlet.ResteasyContextParameters;

import javax.ws.rs.core.MediaType;
import java.io.IOException;
import java.util.*;

/**
 * 

JBoss Module

* *

The JBoss module assembles a JBoss-based server-side application for hosting the WS endpoints.

* * * *

Steps

* *

generate

* *

The "generate" step generates the configuration files.

* *

Configuration

* *

Content Negotiation

* *

Enuncite provides content type negotiation (conneg) to Jersey that conforms to the content type negotiation of * the Enunciate REST module. This means that each resource is mounted from the REST subcontext (see above) but ALSO from a subcontext that conforms to the * id of each content type that the resource supports. So, if the content type id of the "application/xml" content type is "xml" then the resource at path * "mypath" will be mounted at both "/rest/mypath" and "/xml/mypath".

* *

The content types for each JAX-RS resource are declared by the @Produces annotation. The content type ids are customized with the * "enunciate/services/rest/content-types" element in the Enunciate configuration. Enunciate supplies providers for the "application/xml" and "application/json" * content types by default.

* *

The JBoss module supports the following configuration attributes:

* *
    *
  • The "useSubcontext" attribute is used to enable/disable mounting the JAX-RS resources at the rest subcontext. Default: "true".
  • *
  • The "usePathBasedConneg" attribute is used to enable/disable path-based conneg (see above). Default: "false".
  • *
  • The "enableJaxws" attribute (boolean) can be used to disable the JAX-WS support, leaving the JAX-WS support to another module if necessary. Default: true
  • *
  • The "enableJaxrs" attribute (boolean) can be used to disable the JAX-RS (RESTEasy) support, leaving the JAX-RS support to another module if necessary. Default: true
  • *
* *

The JBoss module also supports a list of option child elements that each support a 'name' and 'value' attribute. This can be used to configure the RESTEasy * mechanism, and the properties will be passed along as context parameters. * See the RESTEasy docs for details.

* *

Artifacts

* *

The JBoss deployment module exports no artifacts.

* * @author Ryan Heaton * @docFileName module_jboss.html */ public class JBossDeploymentModule extends FreemarkerDeploymentModule implements EnunciateClasspathListener, SpecProviderModule { private boolean enableJaxrs = true; private boolean enableJaxws = true; private boolean useSubcontext = true; private boolean jacksonAvailable = false; private boolean usePathBasedConneg = false; private final Map options = new TreeMap(); /** * @return "jboss" */ @Override public String getName() { return "jboss"; } // Inherited. public void onClassesFound(Set classes) { jacksonAvailable |= classes.contains("org.jboss.resteasy.plugins.providers.jackson.ResteasyJacksonProvider"); } // Inherited. @Override public void initModel(EnunciateFreemarkerModel model) { super.initModel(model); if (!isDisabled()) { if (enableJaxrs) { Map contentTypes2Ids = model.getContentTypesToIds(); if (getEnunciate().isModuleEnabled("amf")) { //if the amf module is enabled, we'll add amf rest endpoints. contentTypes2Ids.put("application/x-amf", "amf"); } else { debug("AMF module has been disabled, so it's assumed the REST endpoints won't be available in AMF format."); } if (jacksonAvailable) { contentTypes2Ids.put("application/json", "json"); //if we can load jackson, we've got json. } else { debug("Couldn't find Jackson on the classpath, so it's assumed the REST endpoints aren't available in JSON format."); } for (RootResource resource : model.getRootResources()) { for (ResourceMethod resourceMethod : resource.getResourceMethods(true)) { Map> subcontextsByContentType = new HashMap>(); String subcontext = this.useSubcontext ? getRestSubcontext() : ""; debug("Resource method %s of resource %s to be made accessible at subcontext \"%s\".", resourceMethod.getSimpleName(), resourceMethod.getParent().getQualifiedName(), subcontext); subcontextsByContentType.put(null, new TreeSet(Arrays.asList(subcontext))); resourceMethod.putMetaData("defaultSubcontext", subcontext); if (isUsePathBasedConneg()) { for (String producesMime : resourceMethod.getProducesMime()) { MediaType producesType = MediaType.valueOf(producesMime); for (Map.Entry contentTypeToId : contentTypes2Ids.entrySet()) { MediaType type = MediaType.valueOf(contentTypeToId.getKey()); if (producesType.isCompatible(type)) { String id = '/' + contentTypeToId.getValue(); String fullpath = resourceMethod.getFullpath(); if (fullpath.startsWith(id) || fullpath.startsWith(contentTypeToId.getValue())) { throw new ValidationException(resourceMethod.getPosition(), String.format("The path of this resource starts with \"%s\" and you've got path-based conneg enabled. So Enunciate can't tell whether a request for \"%s\" is a request for this resource or a request for the \"%s\" representation of resource \"%s\". You're going to have to either adjust the path of the resource or disable path-based conneg in the enunciate config (e.g. usePathBasedConneg=\"false\").", id, fullpath, id, fullpath.substring(fullpath.indexOf(contentTypeToId.getValue()) + contentTypeToId.getValue().length()))); } debug("Resource method %s of resource %s to be made accessible at subcontext \"%s\" because it produces %s/%s.", resourceMethod.getSimpleName(), resourceMethod.getParent().getQualifiedName(), id, producesType.getType(), producesType.getSubtype()); String contentTypeValue = String.format("%s/%s", type.getType(), type.getSubtype()); Set subcontextList = subcontextsByContentType.get(contentTypeValue); if (subcontextList == null) { subcontextList = new TreeSet(); subcontextsByContentType.put(contentTypeValue, subcontextList); } subcontextList.add(id); } } } } resourceMethod.putMetaData("subcontexts", subcontextsByContentType); } } } if (enableJaxws) { EnunciateConfiguration config = model.getEnunciateConfig(); for (WsdlInfo wsdlInfo : model.getNamespacesToWSDLs().values()) { for (EndpointInterface ei : wsdlInfo.getEndpointInterfaces()) { String path = "/soap/" + ei.getServiceName(); if (config != null) { path = config.getDefaultSoapSubcontext() + '/' + ei.getServiceName(); if (config.getSoapServices2Paths().containsKey(ei.getServiceName())) { path = config.getSoapServices2Paths().get(ei.getServiceName()); } } ei.putMetaData("soapPath", path); } } } } } @Override public void init(Enunciate enunciate) throws EnunciateException { super.init(enunciate); if (this.enableJaxws) { enunciate.getConfig().setForceJAXWSSpecCompliance(true); //make sure the WSDL and client code are JAX-WS-compliant. } } @Override public void doFreemarkerGenerate() throws IOException, TemplateException { WebAppConfig webAppConfig = enunciate.getConfig().getWebAppConfig(); if (webAppConfig == null) { webAppConfig = new WebAppConfig(); enunciate.getConfig().setWebAppConfig(webAppConfig); } webAppConfig.addWebXmlAttribute("version", "3.0"); webAppConfig.addWebXmlAttribute("xmlns", "http://java.sun.com/xml/ns/javaee"); webAppConfig.addWebXmlAttribute("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); webAppConfig.addWebXmlAttribute("xsi:schemaLocation", "http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"); } @Override protected void doBuild() throws EnunciateException, IOException { super.doBuild(); BaseWebAppFragment webappFragment = new BaseWebAppFragment(getName()); HashMap jbossContextParameters = new HashMap(); webappFragment.setContextParameters(jbossContextParameters); ArrayList servlets = new ArrayList(); if (this.enableJaxws) { for (WsdlInfo wsdlInfo : getModelInternal().getNamespacesToWSDLs().values()) { for (EndpointInterface ei : wsdlInfo.getEndpointInterfaces()) { String path = (String) ei.getMetaData().get("soapPath"); WebAppComponent wsComponent = new WebAppComponent(); wsComponent.setName(ei.getServiceName()); wsComponent.setClassname(ei.getEndpointImplementations().iterator().next().getQualifiedName()); wsComponent.setUrlMappings(new TreeSet(Arrays.asList(path))); servlets.add(wsComponent); } } } if (this.enableJaxrs) { WebAppComponent jaxrsServletComponent = new WebAppComponent(); jaxrsServletComponent.setName("resteasy-jaxrs"); jaxrsServletComponent.setClassname(EnunciateJBossHttpServletDispatcher.class.getName()); TreeSet jaxrsUrlMappings = new TreeSet(); StringBuilder resources = new StringBuilder(); for (RootResource rootResource : getModel().getRootResources()) { if (resources.length() > 0) { resources.append(','); } resources.append(rootResource.getQualifiedName()); for (ResourceMethod resourceMethod : rootResource.getResourceMethods(true)) { String resourceMethodPattern = resourceMethod.getServletPattern(); for (Set subcontextList : ((Map>) resourceMethod.getMetaData().get("subcontexts")).values()) { for (String subcontext : subcontextList) { String servletPattern; if ("".equals(subcontext)) { servletPattern = resourceMethodPattern; } else { servletPattern = subcontext + resourceMethodPattern; } if (jaxrsUrlMappings.add(servletPattern)) { debug("Resource method %s of resource %s to be made accessible by servlet pattern %s.", resourceMethod.getSimpleName(), resourceMethod.getParent().getQualifiedName(), servletPattern); } } } } } if (jaxrsUrlMappings.contains("/*")) { jaxrsUrlMappings.clear(); jaxrsUrlMappings.add("/*"); } else { Iterator iterator = jaxrsUrlMappings.iterator(); while (iterator.hasNext()) { String mapping = iterator.next(); if (!mapping.endsWith("/*") && jaxrsUrlMappings.contains(mapping + "/*")) { iterator.remove(); } } } StringBuilder providers = new StringBuilder(); for (TypeDeclaration provider : getModel().getJAXRSProviders()) { if (providers.length() > 0) { providers.append(','); } providers.append(provider.getQualifiedName()); } if (jacksonAvailable) { if (providers.length() > 0) { providers.append(','); } providers.append("org.codehaus.enunciate.jboss.ResteasyJacksonJaxbProvider"); } if (getEnunciate().isModuleEnabled("amf")) { if (providers.length() > 0) { providers.append(','); } providers.append("org.codehaus.enunciate.modules.amf.JAXRSProvider"); } jaxrsServletComponent.setUrlMappings(jaxrsUrlMappings); jbossContextParameters.put(ResteasyContextParameters.RESTEASY_RESOURCES, resources.toString()); jbossContextParameters.put(ResteasyContextParameters.RESTEASY_PROVIDERS, providers.toString()); String mappingPrefix = this.useSubcontext ? getRestSubcontext() : ""; if (!"".equals(mappingPrefix)) { jbossContextParameters.put("resteasy.servlet.mapping.prefix", mappingPrefix); jaxrsServletComponent.addInitParam("resteasy.servlet.mapping.prefix", mappingPrefix); } if (isUsePathBasedConneg()) { Map contentTypesToIds = getModelInternal().getContentTypesToIds(); if (contentTypesToIds != null && contentTypesToIds.size() > 0) { StringBuilder builder = new StringBuilder(); Iterator> contentTypeIt = contentTypesToIds.entrySet().iterator(); while (contentTypeIt.hasNext()) { Map.Entry contentTypeEntry = contentTypeIt.next(); builder.append(contentTypeEntry.getValue()).append(" : ").append(contentTypeEntry.getKey()); if (contentTypeIt.hasNext()) { builder.append(", "); } } jbossContextParameters.put(ResteasyContextParameters.RESTEASY_MEDIA_TYPE_MAPPINGS, builder.toString()); } } jbossContextParameters.put(ResteasyContextParameters.RESTEASY_SCAN_RESOURCES, Boolean.FALSE.toString()); servlets.add(jaxrsServletComponent); } webappFragment.setServlets(servlets); if (!this.options.isEmpty()) { webappFragment.setContextParameters(this.options); } getEnunciate().addWebAppFragment(webappFragment); } @Override public Validator getValidator() { return this.enableJaxws ? new JBossValidator() : super.getValidator(); } // Inherited. public boolean isJaxwsProvider() { return this.enableJaxws; } // Inherited. public boolean isJaxrsProvider() { return this.enableJaxrs; } public void setEnableJaxrs(boolean enableJaxrs) { this.enableJaxrs = enableJaxrs; } public void setEnableJaxws(boolean enableJaxws) { this.enableJaxws = enableJaxws; } /** * Whether to use path-based conneg. * * @return Whether to use path-based conneg. */ public boolean isUsePathBasedConneg() { return usePathBasedConneg; } /** * Whether to use path-based conneg. * * @param usePathBasedConneg Whether to use path-based conneg. */ public void setUsePathBasedConneg(boolean usePathBasedConneg) { this.usePathBasedConneg = usePathBasedConneg; } /** * Whether to use the REST subcontext. * * @param useSubcontext Whether to use the REST subcontext. */ public void setUseSubcontext(boolean useSubcontext) { this.useSubcontext = useSubcontext; } protected String getRestSubcontext() { String restSubcontext = getEnunciate().getConfig().getDefaultRestSubcontext(); //todo: override default rest subcontext? return restSubcontext; } public void addOption(String name, String value) { this.options.put(name, value); } @Override public RuleSet getConfigurationRules() { return new JBossRuleSet(); } // Inherited. @Override public boolean isDisabled() { if (super.isDisabled()) { return true; } else if (getModelInternal() != null) { if (getModelInternal().getRootResources().isEmpty()) { debug("CXF module is disabled because there are no root resources to process."); return true; } else if (getModelInternal().getEnunciateConfig() != null && getModelInternal().getEnunciateConfig().getWebAppConfig() != null && getModelInternal().getEnunciateConfig().getWebAppConfig().isDisabled()) { debug("Module '%s' is disabled because the web application processing has been disabled.", getName()); return true; } } return false; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy