Author: sergeyb
Date: Thu Dec  5 12:02:20 2013
New Revision: 1548103

URL: http://svn.apache.org/r1548103
Log:
[CXF-4199] Starting with the auto-discovery of service providers work, patch 
from Andriy Redko applied

Added:
    
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/
    
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/BookStore.java
   (with props)
    
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/JAXRSServerSpringDiscoveryTest.java
   (with props)
    cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/
    cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/
    
cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/beans.xml
   (with props)
    
cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/web.xml
   (with props)
Modified:
    
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/spring/JAXRSServerFactoryBeanDefinitionParser.java
    cxf/trunk/rt/frontend/jaxrs/src/main/resources/schemas/jaxrs.xsd

Modified: 
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/spring/JAXRSServerFactoryBeanDefinitionParser.java
URL: 
http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/spring/JAXRSServerFactoryBeanDefinitionParser.java?rev=1548103&r1=1548102&r2=1548103&view=diff
==============================================================================
--- 
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/spring/JAXRSServerFactoryBeanDefinitionParser.java
 (original)
+++ 
cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/spring/JAXRSServerFactoryBeanDefinitionParser.java
 Thu Dec  5 12:02:20 2013
@@ -18,15 +18,20 @@
  */
 package org.apache.cxf.jaxrs.spring;
 
+import java.io.IOException;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
+import javax.ws.rs.ext.Provider;
 import javax.xml.namespace.QName;
 
 import org.w3c.dom.Element;
 
 import org.apache.cxf.bus.spring.BusWiringBeanFactoryPostProcessor;
+import org.apache.cxf.common.classloader.ClassLoaderUtils;
 import org.apache.cxf.common.util.StringUtils;
 import org.apache.cxf.configuration.spring.AbstractBeanDefinitionParser;
 import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
@@ -35,17 +40,29 @@ import org.apache.cxf.jaxrs.lifecycle.Re
 import org.apache.cxf.jaxrs.model.UserResource;
 import org.apache.cxf.jaxrs.utils.ResourceUtils;
 import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.BeanCreationException;
 import org.springframework.beans.factory.BeanDefinitionStoreException;
 import org.springframework.beans.factory.support.AbstractBeanDefinition;
 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
 import org.springframework.beans.factory.xml.ParserContext;
 import org.springframework.context.ApplicationContext;
 import org.springframework.context.ApplicationContextAware;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.type.AnnotationMetadata;
+import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.util.ClassUtils;
+
+
 
 
 
 public class JAXRSServerFactoryBeanDefinitionParser extends 
AbstractBeanDefinitionParser {
     
+    
     public JAXRSServerFactoryBeanDefinitionParser() {
         super();
         setBeanClass(SpringJAXRSServerFactoryBean.class);
@@ -66,6 +83,20 @@ public class JAXRSServerFactoryBeanDefin
         } else if ("serviceName".equals(name)) {
             QName q = parseQName(e, val);
             bean.addPropertyValue(name, q);
+        } else if ("base-packages".equals(name)) {
+            final String[] values = StringUtils.split(val, ",");
+            final Set<String> basePackages = new 
HashSet<String>(values.length);
+            for (final String value : values) {
+                final String trimmed = value.trim();
+                if (trimmed.equals(SpringJAXRSServerFactoryBean.ALL_PACKAGES)) 
{
+                    basePackages.clear();
+                    basePackages.add(trimmed);
+                    break;
+                } else if (trimmed.length() > 0) {
+                    basePackages.add(trimmed);
+                }
+            }
+            bean.addPropertyValue("basePackages", basePackages);
         } else {
             mapToProperty(bean, name, val);
         }
@@ -136,7 +167,11 @@ public class JAXRSServerFactoryBeanDefin
     public static class SpringJAXRSServerFactoryBean extends 
JAXRSServerFactoryBean implements
         ApplicationContextAware {
         
+        private static final String ALL_CLASS_FILES = "**/*.class";
+        private static final String ALL_PACKAGES = "*";
+        
         private List<SpringResourceFactory> tempFactories;
+        private List<String> basePackages;
 
         public SpringJAXRSServerFactoryBean() {
             super();
@@ -146,10 +181,14 @@ public class JAXRSServerFactoryBeanDefin
             super(sf);
         }
         
+        public void setBasePackages(List<String> basePackages) {
+            this.basePackages = basePackages;
+        }
+        
         public void setTempResourceProviders(List<SpringResourceFactory> 
providers) {
             tempFactories = providers;
         }
-
+        
         public void setApplicationContext(ApplicationContext ctx) throws 
BeansException {
             if (tempFactories != null) {
                 List<ResourceProvider> factories = new 
ArrayList<ResourceProvider>(
@@ -162,9 +201,59 @@ public class JAXRSServerFactoryBeanDefin
                 tempFactories.clear();
                 super.setResourceProviders(factories);
             }
+            
+            try {
+                if (basePackages != null && !basePackages.isEmpty()) {
+                    final List< Object > providers = new ArrayList< Object >();
+                    
+                    // Reusing Spring's approach to classpath scanning. 
Because Java packages are
+                    // open, it's impossible to get all classes belonging to 
specific package.
+                    // Instead, the classpath is looked for *.class files 
under package's
+                    // path (f.e., package 'com.example' becomes a classpath 
'com/example/**/*.class'). 
+                    final ResourcePatternResolver resolver = new 
PathMatchingResourcePatternResolver();
+                    final MetadataReaderFactory factory = new 
CachingMetadataReaderFactory(resolver);
+
+                    for (final String basePackage: basePackages) {
+                        final boolean scanAllPackages = 
basePackage.equals(ALL_PACKAGES);
+                        
+                        final String packageSearchPath = 
ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX 
+                            + (scanAllPackages ? "" : 
ClassUtils.convertClassNameToResourcePath(basePackage)) 
+                            + ALL_CLASS_FILES;
+                        
+                        final Resource[] resources = 
resolver.getResources(packageSearchPath);                        
+                        for (final Resource resource: resources) {
+                            final MetadataReader reader = 
factory.getMetadataReader(resource);
+                            final AnnotationMetadata metadata = 
reader.getAnnotationMetadata();
+                            
+                            if (scanAllPackages && 
shouldSkip(metadata.getClassName())) {
+                                continue;
+                            }
+                            
+                            // Create a bean only if it's a provider 
(annotated)
+                            if 
(metadata.isAnnotated(Provider.class.getName())) {                              
  
+                                final Class<?> clazz = 
ClassLoaderUtils.loadClass(metadata.getClassName(), getClass());
+                                
providers.add(ctx.getAutowireCapableBeanFactory().createBean(clazz));
+                            }
+                        }                        
+                    }
+                    
+                    if (!providers.isEmpty()) {                        
+                        this.setProviders(providers);
+                    }
+                }
+            } catch (IOException ex) {
+                throw new BeanDefinitionStoreException("I/O failure during 
classpath scanning", ex);
+            } catch (ClassNotFoundException ex) {
+                throw new BeanCreationException("Failed to create bean from 
classfile", ex);
+            }
+            
             if (bus == null) {
                 setBus(BusWiringBeanFactoryPostProcessor.addDefaultBus(ctx));
             }
         }
+        
+        private boolean shouldSkip(final String classname) {
+            return classname.startsWith("org.apache.cxf");
+        }
     }
 }

Modified: cxf/trunk/rt/frontend/jaxrs/src/main/resources/schemas/jaxrs.xsd
URL: 
http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxrs/src/main/resources/schemas/jaxrs.xsd?rev=1548103&r1=1548102&r2=1548103&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxrs/src/main/resources/schemas/jaxrs.xsd (original)
+++ cxf/trunk/rt/frontend/jaxrs/src/main/resources/schemas/jaxrs.xsd Thu Dec  5 
12:02:20 2013
@@ -68,6 +68,7 @@
           <xsd:attribute name="serviceName" type="xsd:QName"/>
           <xsd:attribute name="docLocation" type="xsd:string"/>
           <xsd:attribute name="publishedEndpointUrl" type="xsd:string"/>
+          <xsd:attribute name="base-packages" type="xsd:string"/>
         </xsd:extension>
       </xsd:complexContent>
     </xsd:complexType>

Added: 
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/BookStore.java
URL: 
http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/BookStore.java?rev=1548103&view=auto
==============================================================================
--- 
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/BookStore.java
 (added)
+++ 
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/BookStore.java
 Thu Dec  5 12:02:20 2013
@@ -0,0 +1,38 @@
+/**
+ * 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.systest.jaxrs.discovery;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import javax.ws.rs.FormParam;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+
+import org.apache.cxf.systest.jaxrs.validation.BookWithValidation;
+
+@Path("/bookstore/")
+public class BookStore {
+    @POST
+    @Path("/books")
+    @Valid
+    public BookWithValidation addBook(@NotNull @FormParam("id") String id,
+            @FormParam("name") String name) {        
+        return new BookWithValidation(name, id);
+    }
+}

Propchange: 
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/BookStore.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/BookStore.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: 
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/JAXRSServerSpringDiscoveryTest.java
URL: 
http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/JAXRSServerSpringDiscoveryTest.java?rev=1548103&view=auto
==============================================================================
--- 
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/JAXRSServerSpringDiscoveryTest.java
 (added)
+++ 
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/JAXRSServerSpringDiscoveryTest.java
 Thu Dec  5 12:02:20 2013
@@ -0,0 +1,79 @@
+/**
+ * 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.systest.jaxrs.discovery;
+
+import javax.ws.rs.core.Form;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+
+import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
+import org.apache.cxf.systest.jaxrs.AbstractSpringServer;
+import org.apache.cxf.systest.jaxrs.validation.AbstractJAXRSValidationTest;
+
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+public class JAXRSServerSpringDiscoveryTest extends 
AbstractJAXRSValidationTest {
+    public static final String PORT = 
allocatePort(JAXRSServerSpringDiscoveryTest.class);
+    
+    @Ignore
+    public static class Server extends AbstractSpringServer {
+        public Server() {
+            super("/jaxrs_spring_discovery", Integer.parseInt(PORT));
+        }
+        
+        public static void main(String[] args) {
+            try {
+                Server s = new Server();
+                s.start();
+            } catch (Exception ex) {
+                ex.printStackTrace();
+                System.exit(-1);
+            } finally {
+                System.out.println("done!");
+            }
+        }
+    }
+    
+    @BeforeClass
+    public static void startServers() throws Exception {
+        AbstractResourceInfo.clearAllMaps();
+        //keep out of process due to stack traces testing failures
+        assertTrue("server did not launch correctly", 
launchServer(Server.class, true));
+    }
+    
+    @Test
+    public void testResponseValidationFailsIfNameIsNull()  {
+        final Response r = createWebClient("/bookstore/books").post(new 
Form().param("id", "1"));
+        assertEquals(Status.INTERNAL_SERVER_ERROR.getStatusCode(), 
r.getStatus());
+    }
+
+    @Test
+    public void testParameterValidationFailsIfIdIsNull()  {
+        final Response r = createWebClient("/bookstore/books").post(new 
Form().param("name", "aa"));
+        assertEquals(Status.BAD_REQUEST.getStatusCode(), r.getStatus());
+    }
+    
+    @Override
+    protected String getPort() {
+        return PORT;
+    }   
+}
+

Propchange: 
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/JAXRSServerSpringDiscoveryTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/JAXRSServerSpringDiscoveryTest.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Added: 
cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/beans.xml
URL: 
http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/beans.xml?rev=1548103&view=auto
==============================================================================
--- 
cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/beans.xml
 (added)
+++ 
cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/beans.xml
 Thu Dec  5 12:02:20 2013
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans";
+  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";
+  xmlns:jaxrs="http://cxf.apache.org/jaxrs";
+  xsi:schemaLocation="
+http://www.springframework.org/schema/beans 
+http://www.springframework.org/schema/beans/spring-beans.xsd
+http://cxf.apache.org/jaxrs
+http://cxf.apache.org/schemas/jaxrs.xsd";>
+       <import resource="classpath:/META-INF/cxf/cxf.xml"/>
+       <import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
+
+    <jaxrs:server address="/" base-packages="org.apache.cxf.jaxrs.validation">
+        <jaxrs:serviceBeans>
+            <ref bean="bookStore"/>
+        </jaxrs:serviceBeans>
+    </jaxrs:server>
+    
+    <bean id="bookStore" 
class="org.apache.cxf.systest.jaxrs.discovery.BookStore" />
+    
+</beans>

Propchange: 
cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/beans.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/beans.xml
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Propchange: 
cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/beans.xml
------------------------------------------------------------------------------
    svn:mime-type = text/xml

Added: 
cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/web.xml
URL: 
http://svn.apache.org/viewvc/cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/web.xml?rev=1548103&view=auto
==============================================================================
--- 
cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/web.xml
 (added)
+++ 
cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/web.xml
 Thu Dec  5 12:02:20 2013
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>
+
+<!DOCTYPE web-app
+    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+    "http://java.sun.com/dtd/web-app_2_3.dtd";>
+
+<!--
+       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.
+-->
+<!-- START SNIPPET: webxml -->
+<web-app>
+    <context-param>
+        <param-name>contextConfigLocation</param-name>
+        <param-value>WEB-INF/beans.xml</param-value>
+    </context-param>
+    
+    <listener>
+        <listener-class>
+                        org.springframework.web.context.ContextLoaderListener
+                </listener-class>
+    </listener>
+    
+       <servlet>
+               <servlet-name>CXFServlet</servlet-name>
+               <display-name>CXF Servlet</display-name>
+               
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>      
        
+               <load-on-startup>1</load-on-startup>
+       </servlet>
+   
+       <servlet-mapping>
+               <servlet-name>CXFServlet</servlet-name>
+               <url-pattern>/*</url-pattern>
+       </servlet-mapping>
+</web-app>
+<!-- END SNIPPET: webxml -->
\ No newline at end of file

Propchange: 
cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/web.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/web.xml
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Propchange: 
cxf/trunk/systests/jaxrs/src/test/resources/jaxrs_spring_discovery/WEB-INF/web.xml
------------------------------------------------------------------------------
    svn:mime-type = text/xml


Reply via email to