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

org.codehaus.enunciate.modules.spring_app.SpringAppDeploymentModule 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.spring_app;

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.contract.validation.Validator;
import org.codehaus.enunciate.main.Enunciate;
import org.codehaus.enunciate.main.webapp.BaseWebAppFragment;
import org.codehaus.enunciate.modules.FreemarkerDeploymentModule;
import org.codehaus.enunciate.modules.spring_app.config.GlobalServiceInterceptor;
import org.codehaus.enunciate.modules.spring_app.config.HandlerInterceptor;
import org.codehaus.enunciate.modules.spring_app.config.SpringAppRuleSet;
import org.codehaus.enunciate.modules.spring_app.config.SpringImport;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.*;

/**
 * 

Spring App Module

* *

The spring app deployment module produces the configuration files and application extensions needed to apply * the Spring container to the Web service application.

* * * *

Steps

* *

generate

* *

The "generate" step generates the Spring * configuration file and application extensions. Refer to configuration * to learn how to customize these things.

* *

The "generate" step is the only relevant step in the spring app deployment module.

* *

Configuration

* * * *

The configuration for the Spring App deployment module is specified by the "spring-app" child element under the "modules" element * of the enunciate configuration file.

* *

Structure

* *

The following example shows the structure of the configuration elements for this module. Note that this shows only the structure. * Some configuration elements don't make sense when used together.

* * * <enunciate> *   <modules> *     <spring-app contextLoaderListenerClass="..." *       applicationContextFilename="..." contextConfigLocation="..." *       springVersion="..."> * *       <springImport file="..." uri="..."/> *       <springImport file="..." uri="..."/> *       ... * *       <globalServiceInterceptor interceptorClass="..." beanName="..."/> *       <globalServiceInterceptor interceptorClass="..." beanName="..."/> *       ... * *       <handlerInterceptor interceptorClass="..." beanName="..."/> *       <handlerInterceptor interceptorClass="..." beanName="..."/> *       ... * *       <handlerMapping pattern="..." beanName="..."/> *       <handlerMapping pattern="..." beanName="..."/> *       ... * *     </spring-app> *   </modules> * </enunciate> * * *

attributes

* *
    *
  • The "contextLoaderListenerClass" attribute specifies that FQN of the class to use as the Spring context loader listener. The default is "org.springframework.web.context.ContextLoaderListener".
  • *
  • The "applicationContextFilename" attribute specifies the name of the Enunciate-generated application context file. The default is "applicationContext.xml".
  • *
  • The "contextConfigLocation" attribute specifies the value of the contextConfigLocation init parameter supplied to the Spring * ContextLoaderListener. The default is "/WEB-INF/" + applicationContextFilename.
  • *
  • The "springVersion" attribute specifies the spring version to use. If not set, an attempt will be made to autodetect it.
  • *
* *

The "springImport" element

* *

The "springImport" element is used to specify a spring configuration file that will be imported by the main * spring servlet config. It supports the following attributes:

* *
    *
  • The "file" attribute specifies the spring import file on the filesystem. It will be copied to the WEB-INF directory.
  • *
  • The "uri" attribute specifies the URI to the spring import file. The URI will not be resolved at compile-time, nor will anything be copied to the * WEB-INF directory. The value of this attribute will be used to reference the spring import file in the main config file. This attribute is useful * to specify an import file on the classpath, e.g. "classpath:com/myco/spring/config.xml".
  • *
* *

One use of specifying spring a import file is to wrap your endpoints with spring interceptors. This can be done * by simply declaring a bean that is an instance of your endpoint class, which can be advised as needed.

* *

It's important to note that the type on which the bean context will be searched is the type of the endpoint interface, and then only if it exists. * If there are more than one beans that are assignable to the endpoint interface, the bean that is named the name of the service will be used. Otherwise, * the deployment of your endpoint will fail.

* *

The same procedure can be used to specify the beans to use as REST endpoints. In this case, * the bean context will be searched for each REST interface that the endpoint implements. If there is a bean that implements that interface, it will * used instead of the default implementation. If there is more than one, the bean that is named the same as the REST endpoint will be used.

* *

There also exists a mechanism to add certain AOP interceptors to all service endpoint beans. Such interceptors are referred to as "global service * interceptors." This can be done by using the "globalServiceInterceptor" element (see below), or by simply creating an interceptor that implements * org.codehaus.enunciate.modules.spring_app.EnunciateServiceAdvice or org.codehaus.enunciate.modules.spring_app.EnunciateServiceAdvisor and declaring it in your * imported spring beans file.

* *

Each global interceptor has an order. The default order is 0 (zero). If a global service interceptor implements org.springframework.core.Ordered, the * order will be respected. As global service interceptors are added, it will be assigned a position in the chain according to it's order. Interceptors * of the same order will be ordered together according to their position in the config file, with priority to those declared by the "globalServiceInterceptor" * element, then to instances of org.codehaus.enunciate.modules.spring_app.EnunciateServiceAdvice, then to instances of * org.codehaus.enunciate.modules.spring_app.EnunciateServiceAdvisor.

* *

For more information on spring bean configuration and interceptor advice, see * the spring reference documentation.

* *

The "globalServiceInterceptor" element

* *

The "globalServiceInterceptor" element is used to specify a Spring interceptor (instance of org.aopalliance.aop.Advice or * org.springframework.aop.Advisor) that is to be injected on all service endpoint beans.

* *
    *
  • The "interceptorClass" attribute specified the class of the interceptor.

    *
  • The "beanName" attribute specifies the bean name of the interceptor.

    *
* *

The "handlerInterceptor" element

* *

The "handlerInterceptor" element is used to specify a Spring interceptor (instance of org.springframework.web.servlet.HandlerInterceptor) * that is to be injected on the handler mapping.

* *
    *
  • The "interceptorClass" attribute specifies the class of the interceptor.

    *
  • The "beanName" attribute specifies the bean name of the interceptor.

    *
* *

For more information on spring bean configuration and interceptor advice, see * the spring reference documentation.

* *

The "handlerMapping" element

* *

The "handlerMapping" element is used to specify a custom Spring handler mapping.

* *
    *
  • The "pattern" attribute specifies the pattern that maps to the handler.

    *
  • The "beanName" attribute specifies the bean name of the handler.

    *
* *

For more information on spring handler mappings, see * the spring reference documentation.

* *

Artifacts

* *

The spring app deployment module exports no artifacts.

* * @author Ryan Heaton * @docFileName module_spring_app.html */ public class SpringAppDeploymentModule extends FreemarkerDeploymentModule implements EnunciateClasspathListener { private final List springImports = new ArrayList(); private final List globalServiceInterceptors = new ArrayList(); private final List handlerInterceptors = new ArrayList(); private String applicationContextFilename = "applicationContext.xml"; private String contextConfigLocation = null; private String contextLoaderListenerClass = "org.springframework.web.context.ContextLoaderListener"; private boolean enableSecurity = false; private boolean factoryBeanFound = false; private boolean spring3 = false; /** * @return "spring-app" */ @Override public String getName() { return "spring-app"; } /** * @return The URL to "spring-servlet.fmt" */ protected URL getApplicationContextTemplateURL() { return SpringAppDeploymentModule.class.getResource("applicationContext.xml.fmt"); } public void onClassesFound(Set classes) { factoryBeanFound |= classes.contains("org.codehaus.enunciate.modules.spring_app.ServiceEndpointFactoryBean"); //we'll key off the Converter class since that's new in Spring 3. spring3 |= classes.contains("org.springframework.core.convert.converter.Converter"); } @Override public void init(Enunciate enunciate) throws EnunciateException { super.init(enunciate); if (!isDisabled() && isEnableSecurity()) { throw new EnunciateException("As of 1.23, enunciate-specific spring security configuration has been DEPRECATED and will be removed in a future release. Please see http://goo.gl/1S94J for more information."); } } @Override public void initModel(EnunciateFreemarkerModel model) { super.initModel(model); if (!isDisabled()) { if (!factoryBeanFound) { warn("The Spring module is enabled, but the Enunciate-Spring runtime classes weren't found on the Enunciate classpath. This could be fatal to the runtime application..."); } } } @Override public void doFreemarkerGenerate() throws IOException, TemplateException { if (!enunciate.isUpToDateWithSources(getWebInfDir())) { EnunciateFreemarkerModel model = getModel(); //standard spring configuration: model.put("springImports", getSpringImportURIs()); model.put("applicationContextFilename", getApplicationContextFilename()); model.put("spring3", this.spring3); Object docsDir = enunciate.getProperty("docs.webapp.dir"); if (docsDir == null) { docsDir = ""; } model.put("docsDir", docsDir); if (!globalServiceInterceptors.isEmpty()) { for (GlobalServiceInterceptor interceptor : this.globalServiceInterceptors) { if ((interceptor.getBeanName() == null) && (interceptor.getInterceptorClass() == null)) { throw new IllegalStateException("A global interceptor must have either a bean name or a class set."); } } model.put("globalServiceInterceptors", this.globalServiceInterceptors); } if (!handlerInterceptors.isEmpty()) { for (HandlerInterceptor interceptor : this.handlerInterceptors) { if ((interceptor.getBeanName() == null) && (interceptor.getInterceptorClass() == null)) { throw new IllegalStateException("A handler interceptor must have either a bean name or a class set."); } } model.put("handlerInterceptors", this.handlerInterceptors); } model.setFileOutputDirectory(getWebInfDir()); processTemplate(getApplicationContextTemplateURL(), model); copySpringConfig(); } else { info("Skipping generation of spring config files as everything appears up-to-date..."); } BaseWebAppFragment webAppFragment = new BaseWebAppFragment(getName()); webAppFragment.setBaseDir(getGenerateDir()); ArrayList servletListeners = new ArrayList(); servletListeners.add(getContextLoaderListenerClass()); servletListeners.add("org.codehaus.enunciate.modules.spring_app.SpringComponentPostProcessor"); webAppFragment.setListeners(servletListeners); Map contextParams = new HashMap(); String contextConfigLocation = getContextConfigLocation(); if (contextConfigLocation == null) { contextConfigLocation = "/WEB-INF/" + getApplicationContextFilename(); } contextParams.put("contextConfigLocation", contextConfigLocation); webAppFragment.setContextParameters(contextParams); getEnunciate().addWebAppFragment(webAppFragment); } /** * Copy the spring application context and servlet config from the build dir to the WEB-INF directory. */ protected void copySpringConfig() throws IOException { for (SpringImport springImport : springImports) { //copy the extra spring import files to the WEB-INF directory to be imported. if (springImport.getFile() != null) { File importFile = enunciate.resolvePath(springImport.getFile()); String name = importFile.getName(); name = resolveSpringImportFileName(name); enunciate.copyFile(importFile, new File(getWebInfDir(), name)); } } } /** * Get the string form of the spring imports that have been configured. * * @return The string form of the spring imports that have been configured. */ protected ArrayList getSpringImportURIs() { ArrayList springImportURIs = new ArrayList(this.springImports.size()); for (SpringImport springImport : springImports) { if (springImport.getFile() != null) { if (springImport.getUri() != null) { throw new IllegalStateException("A spring import configuration must specify a file or a URI, but not both."); } String fileName = new File(springImport.getFile()).getName(); fileName = resolveSpringImportFileName(fileName); springImportURIs.add(fileName); } else if (springImport.getUri() != null) { springImportURIs.add(springImport.getUri()); } else { throw new IllegalStateException("A spring import configuration must specify either a file or a URI."); } } return springImportURIs; } /** * Resolves the application context file name (in case there's a conflict). * * @param fileName The file name. * @return The resolved file name. */ protected String resolveSpringImportFileName(String fileName) { if (!"applicationContext.xml".equals(getApplicationContextFilename())) { //if we're not using the default applicationContext.xml filename, we'll assume the user knows what they're doing. return fileName; } if ("applicationContext.xml".equalsIgnoreCase(fileName)) { fileName = "applicationContext-" + getModel().getEnunciateConfig().getLabel() + ".xml"; } return fileName; } @Override public boolean isDisabled() { if (super.isDisabled()) { return true; } else if (getModelInternal() != null && 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; } /** * The list of spring imports. * * @return The list of spring imports. */ public List getSpringImports() { return springImports; } /** * Add a spring import. * * @param springImports The spring import to add. */ public void addSpringImport(SpringImport springImports) { this.springImports.add(springImports); } /** * Add a global service interceptor to the spring configuration. * * @param interceptorConfig The interceptor configuration. */ public void addGlobalServiceInterceptor(GlobalServiceInterceptor interceptorConfig) { this.globalServiceInterceptors.add(interceptorConfig); } /** * Add a handler interceptor to the spring configuration. * * @param interceptorConfig The interceptor configuration. */ public void addHandlerInterceptor(HandlerInterceptor interceptorConfig) { this.handlerInterceptors.add(interceptorConfig); } /** * The class to use as the context loader listener. * * @return The class to use as the context loader listener. */ public String getContextLoaderListenerClass() { return contextLoaderListenerClass; } /** * The class to use as the context loader listener. * * @param contextLoaderListenerClass The class to use as the context loader listener. */ public void setContextLoaderListenerClass(String contextLoaderListenerClass) { this.contextLoaderListenerClass = contextLoaderListenerClass; } /** * The name of the application context file. * * @return The name of the application context file. */ public String getApplicationContextFilename() { return applicationContextFilename; } /** * The name of the application context file. * * @param applicationContextFilename The name of the application context file. */ public void setApplicationContextFilename(String applicationContextFilename) { this.applicationContextFilename = applicationContextFilename; } /** * The context config location. * * @return The context config location. */ public String getContextConfigLocation() { return contextConfigLocation; } /** * The context config location. * * @param contextConfigLocation The context config location. */ public void setContextConfigLocation(String contextConfigLocation) { this.contextConfigLocation = contextConfigLocation; } /** * Whether to enable security. * * @return Whether to enable security. */ public boolean isEnableSecurity() { return enableSecurity; } /** * Whether to enable security. * * @param enableSecurity Whether to enable security. */ public void setEnableSecurity(boolean enableSecurity) { this.enableSecurity = enableSecurity; } /** * The spring version to use. * * @param version The spring version to use. */ public void setSpringVersion(String version) { this.spring3 = version.startsWith("3"); } /** * @return 200 */ @Override public int getOrder() { return 200; } @Override public RuleSet getConfigurationRules() { return new SpringAppRuleSet(); } @Override public Validator getValidator() { return null; } /** * The directory where the config files are generated. * * @return The directory where the config files are generated. */ protected File getWebInfDir() { return new File(getGenerateDir(), "WEB-INF"); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy