You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2013/12/13 14:03:03 UTC

svn commit: r1550718 - in /cxf/trunk: core/src/main/java/org/apache/cxf/common/util/ rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/spring/ rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spring/ rt/rs/client/src/main/resources/schemas/ sy...

Author: sergeyb
Date: Fri Dec 13 13:03:03 2013
New Revision: 1550718

URL: http://svn.apache.org/r1550718
Log:
[CXF-4199] Auto-discovery support for Spring jaxrs:client, patch from Andriy Redko applied

Modified:
    cxf/trunk/core/src/main/java/org/apache/cxf/common/util/ClasspathScanner.java
    cxf/trunk/core/src/main/java/org/apache/cxf/common/util/SpringClasspathScanner.java
    cxf/trunk/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/spring/JAXRSServerFactoryBeanDefinitionParser.java
    cxf/trunk/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spring/JAXRSClientFactoryBeanDefinitionParser.java
    cxf/trunk/rt/rs/client/src/main/resources/schemas/jaxrs-client.xsd
    cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/BookStore.java
    cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/JAXRSServerSpringDiscoveryTest.java

Modified: cxf/trunk/core/src/main/java/org/apache/cxf/common/util/ClasspathScanner.java
URL: http://svn.apache.org/viewvc/cxf/trunk/core/src/main/java/org/apache/cxf/common/util/ClasspathScanner.java?rev=1550718&r1=1550717&r2=1550718&view=diff
==============================================================================
--- cxf/trunk/core/src/main/java/org/apache/cxf/common/util/ClasspathScanner.java (original)
+++ cxf/trunk/core/src/main/java/org/apache/cxf/common/util/ClasspathScanner.java Fri Dec 13 13:03:03 2013
@@ -24,8 +24,10 @@ import java.net.URL;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 public class ClasspathScanner {
     public static final String ALL_FILES = "**/*";
@@ -124,6 +126,24 @@ public class ClasspathScanner {
         return HELPER.findResourcesInternal(basePackages, extension);
     }
     
+    
+    public static Set<String> parsePackages(final String packagesAsCsv) {        
+        final String[] values = StringUtils.split(packagesAsCsv, ",");
+        final Set<String> basePackages = new HashSet<String>(values.length);
+        for (final String value : values) {
+            final String trimmed = value.trim();
+            if (trimmed.equals(ClasspathScanner.ALL_PACKAGES)) {
+                basePackages.clear();
+                basePackages.add(trimmed);
+                break;
+            } else if (trimmed.length() > 0) {
+                basePackages.add(trimmed);
+            }
+        }
+        
+        return basePackages;
+    }
+    
     protected List<URL> findResourcesInternal(Collection<String> basePackages, String extension) 
         throws IOException {
         return Collections.emptyList();

Modified: cxf/trunk/core/src/main/java/org/apache/cxf/common/util/SpringClasspathScanner.java
URL: http://svn.apache.org/viewvc/cxf/trunk/core/src/main/java/org/apache/cxf/common/util/SpringClasspathScanner.java?rev=1550718&r1=1550717&r2=1550718&view=diff
==============================================================================
--- cxf/trunk/core/src/main/java/org/apache/cxf/common/util/SpringClasspathScanner.java (original)
+++ cxf/trunk/core/src/main/java/org/apache/cxf/common/util/SpringClasspathScanner.java Fri Dec 13 13:03:03 2013
@@ -38,12 +38,18 @@ import org.springframework.core.type.cla
 import org.springframework.util.ClassUtils;
 
 class SpringClasspathScanner extends ClasspathScanner {
-    private final ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
-    private final MetadataReaderFactory factory = new CachingMetadataReaderFactory(resolver);
+    SpringClasspathScanner() throws Exception {
+        Class.forName("org.springframework.core.io.support.PathMatchingResourcePatternResolver");
+        Class.forName("org.springframework.core.type.classreading.CachingMetadataReaderFactory");
+    }
+    
 
     protected Map< Class< ? extends Annotation >, Collection< Class< ? > > > findClassesInternal(
         Collection< String > basePackages, List<Class< ? extends Annotation > > annotations) 
         throws IOException, ClassNotFoundException {
+    
+        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
+        MetadataReaderFactory factory = new CachingMetadataReaderFactory(resolver);
         
         final Map< Class< ? extends Annotation >, Collection< Class< ? > > > classes = 
             new HashMap< Class< ? extends Annotation >, Collection< Class< ? > > >();
@@ -90,6 +96,9 @@ class SpringClasspathScanner extends Cla
         if (basePackages == null || basePackages.isEmpty()) {
             return resourceURLs;
         }
+        ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
+        
+        
         
         for (final String basePackage: basePackages) {
             final boolean scanAllPackages = basePackage.equals(ALL_PACKAGES);

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=1550718&r1=1550717&r2=1550718&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 Fri Dec 13 13:03:03 2013
@@ -22,10 +22,8 @@ import java.io.IOException;
 import java.lang.annotation.Annotation;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import javax.ws.rs.Path;
 import javax.ws.rs.ext.Provider;
@@ -76,20 +74,8 @@ 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(ClasspathScanner.ALL_PACKAGES)) {
-                    basePackages.clear();
-                    basePackages.add(trimmed);
-                    break;
-                } else if (trimmed.length() > 0) {
-                    basePackages.add(trimmed);
-                }
-            }
-            bean.addPropertyValue("basePackages", basePackages);
+        } else if ("base-packages".equals(name)) {            
+            bean.addPropertyValue("basePackages", ClasspathScanner.parsePackages(val));
         } else {
             mapToProperty(bean, name, val);
         }

Modified: cxf/trunk/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spring/JAXRSClientFactoryBeanDefinitionParser.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spring/JAXRSClientFactoryBeanDefinitionParser.java?rev=1550718&r1=1550717&r2=1550718&view=diff
==============================================================================
--- cxf/trunk/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spring/JAXRSClientFactoryBeanDefinitionParser.java (original)
+++ cxf/trunk/rt/rs/client/src/main/java/org/apache/cxf/jaxrs/client/spring/JAXRSClientFactoryBeanDefinitionParser.java Fri Dec 13 13:03:03 2013
@@ -18,19 +18,28 @@
  */
 package org.apache.cxf.jaxrs.client.spring;
 
+import java.io.IOException;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
+import javax.ws.rs.Path;
+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.util.ClasspathScanner;
 import org.apache.cxf.configuration.spring.AbstractFactoryBeanDefinitionParser;
 import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean;
 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.NoUniqueBeanDefinitionException;
 import org.springframework.beans.factory.support.BeanDefinitionBuilder;
 import org.springframework.beans.factory.xml.ParserContext;
 import org.springframework.context.ApplicationContext;
@@ -39,6 +48,7 @@ import org.springframework.context.Appli
 
 
 
+
 public class JAXRSClientFactoryBeanDefinitionParser extends AbstractFactoryBeanDefinitionParser {
     
     public JAXRSClientFactoryBeanDefinitionParser() {
@@ -66,9 +76,11 @@ public class JAXRSClientFactoryBeanDefin
         if ("serviceName".equals(name)) {
             QName q = parseQName(e, val);
             bean.addPropertyValue(name, q);
+        } else if ("base-packages".equals(name)) {
+            bean.addPropertyValue("basePackages", ClasspathScanner.parsePackages(val));
         } else { 
             mapToProperty(bean, name, val);
-        }
+        } 
     }
 
     @Override
@@ -99,11 +111,42 @@ public class JAXRSClientFactoryBeanDefin
     public static class JAXRSSpringClientFactoryBean extends JAXRSClientFactoryBean
         implements ApplicationContextAware {
     
+        private List<String> basePackages;
+        
         public JAXRSSpringClientFactoryBean() {
             super();
         }
+    
+        public void setBasePackages(List<String> basePackages) {
+            this.basePackages = basePackages;
+        }
         
         public void setApplicationContext(ApplicationContext ctx) throws BeansException {
+            try {
+                if (basePackages != null) {
+                    @SuppressWarnings("unchecked")
+                    final Map< Class< ? extends Annotation >, Collection< Class< ? > > > classes = 
+                        ClasspathScanner.findClasses(basePackages, Path.class, Provider.class);
+                    
+                    if (classes.get(Path.class).size() > 1) {
+                        throw new NoUniqueBeanDefinitionException(Path.class, classes.get(Path.class).size(), 
+                            "More than one service class (@Path) has been discovered");
+                    } else {                      
+                        for (final Class< ? > providerClass: classes.get(Provider.class)) {
+                            setProvider(ctx.getAutowireCapableBeanFactory().createBean(providerClass));
+                        }
+                        
+                        for (final Class< ? > serviceClass: classes.get(Path.class)) {                        
+                            setServiceClass(serviceClass);
+                        }
+                    }
+                }
+            } 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));
             }

Modified: cxf/trunk/rt/rs/client/src/main/resources/schemas/jaxrs-client.xsd
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/rs/client/src/main/resources/schemas/jaxrs-client.xsd?rev=1550718&r1=1550717&r2=1550718&view=diff
==============================================================================
--- cxf/trunk/rt/rs/client/src/main/resources/schemas/jaxrs-client.xsd (original)
+++ cxf/trunk/rt/rs/client/src/main/resources/schemas/jaxrs-client.xsd Fri Dec 13 13:03:03 2013
@@ -64,6 +64,7 @@
           <xsd:attribute name="password" type="xsd:string"/>
           <xsd:attribute name="serviceName" type="xsd:QName"/>
           <xsd:attribute name="threadSafe" type="xsd:boolean"/>
+          <xsd:attribute name="base-packages" type="xsd:string"/>
         </xsd:extension>
       </xsd:complexContent>
     </xsd:complexType>

Modified: 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=1550718&r1=1550717&r2=1550718&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/BookStore.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/BookStore.java Fri Dec 13 13:03:03 2013
@@ -21,8 +21,10 @@ package org.apache.cxf.systest.jaxrs.dis
 import javax.validation.Valid;
 import javax.validation.constraints.NotNull;
 import javax.ws.rs.FormParam;
+import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
 
 import org.apache.cxf.systest.jaxrs.validation.BookWithValidation;
 
@@ -35,4 +37,11 @@ public class BookStore {
             @FormParam("name") String name) {        
         return new BookWithValidation(name, id);
     }
+    
+    @GET
+    @Path("/book/{id}")
+    @Valid
+    public BookWithValidation getBook(@NotNull @PathParam("id") String id) {        
+        return new BookWithValidation("", id);
+    }
 }

Modified: 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=1550718&r1=1550717&r2=1550718&view=diff
==============================================================================
--- cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/JAXRSServerSpringDiscoveryTest.java (original)
+++ cxf/trunk/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/discovery/JAXRSServerSpringDiscoveryTest.java Fri Dec 13 13:03:03 2013
@@ -22,16 +22,19 @@ import javax.ws.rs.core.Form;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.Response.Status;
 
+import org.apache.cxf.jaxrs.client.JAXRSClientFactory;
+import org.apache.cxf.jaxrs.client.WebClient;
 import org.apache.cxf.jaxrs.model.AbstractResourceInfo;
 import org.apache.cxf.systest.jaxrs.AbstractSpringServer;
 import org.apache.cxf.systest.jaxrs.validation.AbstractJAXRSValidationTest;
-
+import org.apache.cxf.systest.jaxrs.validation.BookWithValidation;
+import org.apache.cxf.testutil.common.TestUtil;
 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);
+    public static final String PORT = TestUtil.getPortNumber("jaxrs-http");
     
     @Ignore
     public static class Server extends AbstractSpringServer {
@@ -71,6 +74,16 @@ public class JAXRSServerSpringDiscoveryT
         assertEquals(Status.BAD_REQUEST.getStatusCode(), r.getStatus());
     }
     
+    @Test
+    public void testThatClientDiscoversServiceProperly() throws Exception {
+        BookStore bs = JAXRSClientFactory.create("http://localhost:" + PORT, BookStore.class, 
+            "org/apache/cxf/systest/jaxrs/discovery/jaxrs-http-client.xml");
+        assertEquals("http://localhost:" + PORT, WebClient.client(bs).getBaseURI().toString());
+        
+        BookWithValidation book = bs.getBook("123");
+        assertEquals(book.getId(), "123");
+    }
+    
     @Override
     protected String getPort() {
         return PORT;