You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by bi...@apache.org on 2009/10/17 02:34:01 UTC
svn commit: r826144 - in /cxf/trunk: parent/ rt/frontend/jaxws/
rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spring/ systests/jaxws/
Author: bimargulies
Date: Sat Oct 17 00:34:01 2009
New Revision: 826144
URL: http://svn.apache.org/viewvc?rev=826144&view=rev
Log:
Initial cut at code to scan spring context for things with @WebServices.
Added:
cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spring/Jsr181HandlerMapping.java (with props)
cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spring/Messages.properties (with props)
Modified:
cxf/trunk/parent/pom.xml
cxf/trunk/rt/frontend/jaxws/pom.xml
cxf/trunk/systests/jaxws/pom.xml
Modified: cxf/trunk/parent/pom.xml
URL: http://svn.apache.org/viewvc/cxf/trunk/parent/pom.xml?rev=826144&r1=826143&r2=826144&view=diff
==============================================================================
--- cxf/trunk/parent/pom.xml (original)
+++ cxf/trunk/parent/pom.xml Sat Oct 17 00:34:01 2009
@@ -774,6 +774,52 @@
</exclusions>
</dependency>
<dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-webmvc</artifactId>
+ <version>${spring.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>logkit</groupId>
+ <artifactId>logkit</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>avalon-framework</groupId>
+ <artifactId>avalon-framework</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-aop</artifactId>
+ <version>${spring.version}</version>
+ <exclusions>
+ <exclusion>
+ <groupId>log4j</groupId>
+ <artifactId>log4j</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>logkit</groupId>
+ <artifactId>logkit</artifactId>
+ </exclusion>
+ <exclusion>
+ <groupId>avalon-framework</groupId>
+ <artifactId>avalon-framework</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1</version>
Modified: cxf/trunk/rt/frontend/jaxws/pom.xml
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxws/pom.xml?rev=826144&r1=826143&r2=826144&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxws/pom.xml (original)
+++ cxf/trunk/rt/frontend/jaxws/pom.xml Sat Oct 17 00:34:01 2009
@@ -118,7 +118,37 @@
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
- <scope>test</scope>
+ <scope>provided</scope>
+ <version>${spring.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-webmvc</artifactId>
+ <scope>provided</scope>
+ <version>${spring.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-aop</artifactId>
+ <scope>provided</scope>
+ <version>${spring.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-beans</artifactId>
+ <scope>provided</scope>
+ <version>${spring.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ <scope>provided</scope>
+ <version>${spring.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-core</artifactId>
+ <scope>provided</scope>
<version>${spring.version}</version>
</dependency>
<dependency>
Added: cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spring/Jsr181HandlerMapping.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spring/Jsr181HandlerMapping.java?rev=826144&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spring/Jsr181HandlerMapping.java (added)
+++ cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spring/Jsr181HandlerMapping.java Sat Oct 17 00:34:01 2009
@@ -0,0 +1,282 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.apache.cxf.jaxws.spring;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.logging.Logger;
+
+import javax.jws.WebService;
+import javax.servlet.Servlet;
+import javax.servlet.ServletConfig;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.common.classloader.ClassLoaderUtils;
+import org.apache.cxf.common.i18n.Message;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.databinding.DataBinding;
+import org.apache.cxf.frontend.ServerFactoryBean;
+import org.apache.cxf.jaxb.JAXBDataBinding;
+import org.apache.cxf.jaxws.support.JaxWsServiceFactoryBean;
+import org.apache.cxf.service.factory.ReflectionServiceFactoryBean;
+
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanFactory;
+import org.springframework.beans.factory.BeanFactoryAware;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.web.context.ServletConfigAware;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
+import org.springframework.web.servlet.mvc.Controller;
+
+// All tests for this are in systests, since there's no place else to assemble all the necessary dependencies.
+
+/**
+ * Bean to scan context for potential web services. This scans the beans for classes that
+ * are annotated with @WebService. Excepting those already declared via the JAX-WS Spring
+ * schema, it launches each as an endpoint.
+ *
+ * By default, it sets up a default JaxWsServiceFactory and JAX-B data binding,
+ * and then creates a URL under /services/ based on the service name. Properties of the bean
+ * permit you to configure this; if you set prototypeServiceFactoryBeanName, the code
+ * will fetch that bean. It must be a prototype, since service factory object can't be used
+ * for more than one endpoint. Similiarly, prototypeDataBindingBeanName can be used to
+ * control the data binding.
+ *
+ * Note that this class uses {@link org.apache.cxf.transport.servlet#CXFServlet} from the
+ * cxf-rt-transports-http-jetty library, which is not part of the standard dependencies of the JAX-WS front
+ * end.
+ *
+ */
+public class Jsr181HandlerMapping extends AbstractUrlHandlerMapping implements BeanPostProcessor,
+ ServletConfigAware, BeanFactoryAware {
+
+ private static final Logger LOG = LogUtils.getL7dLogger(Jsr181HandlerMapping.class);
+
+ private static final String CXF_SERVLET_CLASS_NAME = "org.apache.cxf.transport.servlet";
+ private static final String AOP_UTILS_CLASS_NAME = "org.springframework.aop.support.AopUtils";
+ private Class<?> servletClass;
+ private Method servletGetBusMethod;
+ private Method aopUtilsGetTargetClassMethod;
+
+ private String urlPrefix = "/services/";
+ private Servlet shadowCxfServlet;
+ private String prototypeDataBindingBeanName;
+ private String prototypeServiceFactoryBeanName;
+ private BeanFactory beanFactory;
+
+ public Jsr181HandlerMapping() throws SecurityException, NoSuchMethodException, ClassNotFoundException {
+ try {
+ servletClass = ClassLoaderUtils.loadClass(CXF_SERVLET_CLASS_NAME, getClass());
+ } catch (ClassNotFoundException e) {
+ Message message = new Message("SERVLET_CLASS_MISSING", LOG, CXF_SERVLET_CLASS_NAME);
+ LOG.severe(message.toString());
+ throw e;
+ }
+ servletGetBusMethod = servletClass.getMethod("getBus");
+ try {
+ Class<?> aopUtilsClass = ClassLoaderUtils.loadClass(AOP_UTILS_CLASS_NAME, getClass());
+ aopUtilsGetTargetClassMethod = aopUtilsClass.getMethod("getTargetClass", Object.class);
+ } catch (Exception e) {
+ Message message = new Message("AOP_GET_TARGET_CLASS_MISSING", LOG);
+ LOG.severe(message.toString());
+
+ }
+ }
+
+ private Bus getServletBus() {
+ try {
+ return (Bus) servletGetBusMethod.invoke(shadowCxfServlet);
+ } catch (Exception e) {
+ // CXF internally inconsistent?
+ throw new RuntimeException(e);
+ }
+ }
+
+
+ /**
+ * Set the prefix for the generated endpoint URLs.
+ * @param urlPrefix
+ */
+ public void setUrlPrefix(String urlPrefix) {
+ this.urlPrefix = urlPrefix;
+ }
+
+ public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
+ return bean;
+ }
+
+ private Class<?> aopUtilsGetTargetClass(Object possiblyProxiedObject) {
+ if (aopUtilsGetTargetClassMethod != null && possiblyProxiedObject != null) {
+ try {
+ return (Class<?>)aopUtilsGetTargetClassMethod.invoke(null, possiblyProxiedObject);
+ } catch (IllegalArgumentException e) {
+ return possiblyProxiedObject.getClass();
+ } catch (IllegalAccessException e) {
+ return possiblyProxiedObject.getClass();
+ } catch (InvocationTargetException e) {
+ return possiblyProxiedObject.getClass();
+ }
+ }
+ return possiblyProxiedObject.getClass();
+ }
+
+ public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+ Class<?> clazz = aopUtilsGetTargetClass(bean);
+
+ if (clazz.isAnnotationPresent(WebService.class)) {
+ WebService ws = (WebService)clazz.getAnnotation(WebService.class);
+ String url = urlPrefix + ws.serviceName();
+ Message message = new Message("SELECTED_SERVICE", LOG, beanName,
+ clazz.getName(),
+ url);
+ LOG.info(message.toString());
+
+ createAndPublishEndpoint(url, bean);
+ registerHandler(url, new ServletAdapter(shadowCxfServlet));
+ } else {
+ if (logger.isDebugEnabled()) {
+ Message message = new Message("REJECTED_NO_ANNOTATION", LOG, beanName,
+ clazz.getName());
+ LOG.fine(message.toString());
+ }
+ }
+
+ return bean;
+ }
+
+ private void createAndPublishEndpoint(String url, Object implementor) {
+ ReflectionServiceFactoryBean serviceFactory = null;
+ if (prototypeServiceFactoryBeanName != null) {
+ if (!beanFactory.isPrototype(prototypeServiceFactoryBeanName)) {
+ throw
+ new IllegalArgumentException(
+ "prototypeServiceFactoryBeanName must indicate a scope='prototype' bean");
+ }
+ serviceFactory = (ReflectionServiceFactoryBean)
+ beanFactory.getBean(prototypeServiceFactoryBeanName,
+ ReflectionServiceFactoryBean.class);
+ } else {
+ serviceFactory = new JaxWsServiceFactoryBean();
+ }
+
+ ServerFactoryBean serverFactoryBean = new ServerFactoryBean();
+ serverFactoryBean.setServiceBean(implementor);
+ serverFactoryBean.setServiceClass(aopUtilsGetTargetClass(implementor));
+ serverFactoryBean.setAddress(url);
+
+ DataBinding dataBinding = null;
+ if (prototypeDataBindingBeanName != null) {
+ if (!beanFactory.isPrototype(prototypeDataBindingBeanName)) {
+ throw
+ new IllegalArgumentException(
+ "prototypeDataBindingBeanName must indicate a scope='prototype' bean");
+ }
+ dataBinding = (DataBinding)
+ beanFactory.getBean(prototypeDataBindingBeanName,
+ DataBinding.class);
+ } else {
+ dataBinding = new JAXBDataBinding();
+ }
+
+ serverFactoryBean.setDataBinding(dataBinding);
+ serverFactoryBean.setServiceFactory(serviceFactory);
+ serverFactoryBean.setBus(getServletBus());
+ serverFactoryBean.create();
+ }
+
+ public void setServletConfig(ServletConfig servletConfig) {
+
+ try {
+ shadowCxfServlet = (Servlet)servletClass.newInstance();
+ } catch (InstantiationException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ try {
+ shadowCxfServlet.init(servletConfig);
+ } catch (ServletException ex) {
+ throw new RuntimeException(ex.getMessage(), ex);
+ }
+ }
+
+ public static class ServletAdapter implements Controller {
+
+ private Servlet controller;
+
+ public ServletAdapter(Servlet controller) {
+ this.controller = controller;
+ }
+
+ public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response)
+ throws Exception {
+ controller.service(request, response);
+ return null;
+ }
+ }
+
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
+ this.beanFactory = beanFactory;
+
+ }
+
+ public String getPrototypeServiceFactoryBeanName() {
+ return prototypeServiceFactoryBeanName;
+ }
+
+ /**
+ * Set the service factory for all services launched by this bean. This must be the name of a
+ * scope='prototype' bean that implements
+ * {@link org.apache.cxf.service.factory#ReflectionServiceFactoryBean}.
+ * @param prototypeServiceFactoryBeanName
+ */
+ public void setPrototypeServiceFactoryBeanName(String prototypeServiceFactoryBeanName) {
+ this.prototypeServiceFactoryBeanName = prototypeServiceFactoryBeanName;
+ }
+
+ public String getPrototypeDataBindingBeanName() {
+ return prototypeDataBindingBeanName;
+ }
+
+ /**
+ * Set the data binding for all services launched by this bean. This must be the name of a
+ * scope='prototype' bean that implements {@link org.apache.cxf.databinding#DataBinding}.
+ * @param prototypeDataBindingBeanName
+ */
+ public void setPrototypeDataBindingBeanName(String prototypeDataBindingBeanName) {
+ this.prototypeDataBindingBeanName = prototypeDataBindingBeanName;
+ }
+
+ /**
+ * For unit testing ONLY. Disable use of Spring-AOP method to unwrap target classes, to
+ * ensure that this code works when AOP is not there.
+ * @param b
+ */
+ public void setSimulateNoAopForUnitTest(boolean b) {
+ if (b) {
+ aopUtilsGetTargetClassMethod = null;
+ }
+ }
+
+}
Propchange: cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spring/Jsr181HandlerMapping.java
------------------------------------------------------------------------------
svn:eol-style = native
Added: cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spring/Messages.properties
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spring/Messages.properties?rev=826144&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spring/Messages.properties (added)
+++ cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spring/Messages.properties Sat Oct 17 00:34:01 2009
@@ -0,0 +1,24 @@
+#
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you 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.
+#
+#
+SERVLET_CLASS_MISSING=The CXF Servlet class {0} is not available in the classpath.
+AOP_GET_TARGET_CLASS_MISSING=The Spring method AopUtils.getTargetClass() is missing. Check Spring dependencies.
+SELECTED_SERVICE=Publishing bean {0} class {1} as a service at {1}.
+REJECTED_NO_ANNOTATION=Rejected bean {0} class {1}; no @WebService annotation.
Propchange: cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spring/Messages.properties
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/spring/Messages.properties
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified: cxf/trunk/systests/jaxws/pom.xml
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxws/pom.xml?rev=826144&r1=826143&r2=826144&view=diff
==============================================================================
--- cxf/trunk/systests/jaxws/pom.xml (original)
+++ cxf/trunk/systests/jaxws/pom.xml Sat Oct 17 00:34:01 2009
@@ -201,6 +201,43 @@
<artifactId>cxf-rt-testsupport</artifactId>
<version>${project.version}</version>
</dependency>
+
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-web</artifactId>
+ <scope>provided</scope>
+ <version>${spring.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-webmvc</artifactId>
+ <scope>provided</scope>
+ <version>${spring.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-aop</artifactId>
+ <scope>provided</scope>
+ <version>${spring.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-beans</artifactId>
+ <scope>provided</scope>
+ <version>${spring.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-context</artifactId>
+ <scope>provided</scope>
+ <version>${spring.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-core</artifactId>
+ <scope>provided</scope>
+ <version>${spring.version}</version>
+ </dependency>
</dependencies>
<properties>