You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tomee.apache.org by rm...@apache.org on 2012/05/25 17:47:24 UTC

svn commit: r1342699 - in /openejb/trunk/openejb: arquillian-tomee/arquillian-tomee-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/pathparam/ container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/ container/openejb-co...

Author: rmannibucau
Date: Fri May 25 15:47:24 2012
New Revision: 1342699

URL: http://svn.apache.org/viewvc?rev=1342699&view=rev
Log:
TOMEE-195 TOMEE-196 adding openejb.jaxrs.providers.auto to scan @Provider of jaxrs and openejb.cxf.rs.properties to set global cxf jaxrs properties (faultStackTraceEnabled=true is often useful)

Added:
    openejb/trunk/openejb/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/DiscoverCustomProviderTest.java
Modified:
    openejb/trunk/openejb/arquillian-tomee/arquillian-tomee-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/pathparam/Echo.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/AppInfo.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/WebAppInfo.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppInfoBuilder.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppModule.java
    openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/WebModule.java
    openejb/trunk/openejb/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
    openejb/trunk/openejb/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RESTService.java
    openejb/trunk/openejb/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RsHttpListener.java
    openejb/trunk/openejb/server/openejb-wink/src/main/java/org/apache/openejb/server/wink/WinkHttpListener.java
    openejb/trunk/openejb/tomee/tomee-jaxrs/src/main/java/org/apache/tomee/webservices/TomcatRsRegistry.java

Modified: openejb/trunk/openejb/arquillian-tomee/arquillian-tomee-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/pathparam/Echo.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/arquillian-tomee/arquillian-tomee-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/pathparam/Echo.java?rev=1342699&r1=1342698&r2=1342699&view=diff
==============================================================================
--- openejb/trunk/openejb/arquillian-tomee/arquillian-tomee-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/pathparam/Echo.java (original)
+++ openejb/trunk/openejb/arquillian-tomee/arquillian-tomee-tests/src/test/java/org/apache/openejb/arquillian/tests/jaxrs/pathparam/Echo.java Fri May 25 15:47:24 2012
@@ -17,6 +17,7 @@
 package org.apache.openejb.arquillian.tests.jaxrs.pathparam;
 
 import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/AppInfo.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/AppInfo.java?rev=1342699&r1=1342698&r2=1342699&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/AppInfo.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/AppInfo.java Fri May 25 15:47:24 2012
@@ -42,5 +42,6 @@ public class AppInfo extends InfoObject 
     public String cmpMappingsXml;
     public final Properties jmx = new Properties();
     public final Set<String> mbeans = new TreeSet<String>();
+    public final Set<String> jaxRsProviders = new TreeSet<String>();
     public boolean webAppAlone;
 }

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/WebAppInfo.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/WebAppInfo.java?rev=1342699&r1=1342698&r2=1342699&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/WebAppInfo.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/WebAppInfo.java Fri May 25 15:47:24 2012
@@ -40,4 +40,5 @@ public class WebAppInfo extends CommonIn
     public final JndiEncInfo jndiEnc = new JndiEncInfo();
     public final List<ServletInfo> servlets = new ArrayList<ServletInfo>();
     public final List<ClassListInfo> jsfAnnotatedClasses = new ArrayList<ClassListInfo>();
+    public final Set<String> jaxRsProviders = new TreeSet<String>();
 }

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java?rev=1342699&r1=1342698&r2=1342699&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AnnotationDeployer.java Fri May 25 15:47:24 2012
@@ -17,6 +17,7 @@
 package org.apache.openejb.config;
 
 import javax.ws.rs.ApplicationPath;
+import javax.ws.rs.ext.Provider;
 import org.apache.openejb.BeanContext;
 import org.apache.openejb.OpenEJBException;
 import org.apache.openejb.api.LocalClient;
@@ -1044,6 +1045,7 @@ public class AnnotationDeployer implemen
             */
             // get by annotations
             webModule.getRestClasses().addAll(findRestClasses(webModule, finder));
+            addJaxRsProviders(finder, webModule.getJaxrsProviders(), Provider.class);
 
             // Applications with a default constructor
             // findSubclasses will not work by default to gain a lot of time
@@ -1106,6 +1108,12 @@ public class AnnotationDeployer implemen
             return webModule;
         }
 
+        private void addJaxRsProviders(final IAnnotationFinder finder, final Collection<String> set, final Class<? extends Annotation> annotation) {
+            for (Annotated<Class<?>> provider : finder.findMetaAnnotatedClasses(annotation)) {
+                set.add(provider.get().getName());
+            }
+        }
+
         private static void addRestApplicationIfPossible(final WebModule webModule, final Class<? extends Application> app) {
             if (app.getConstructors().length == 0) {
                 webModule.getRestApplications().add(app.getName());
@@ -1428,6 +1436,10 @@ public class AnnotationDeployer implemen
                 }
             }
 
+            // ejb can be rest bean and only then in standalone so scan providers here too
+            // adding them to app since they should be in the app classloader
+            addJaxRsProviders(finder, ejbModule.getAppModule().getJaxRsProviders(), Provider.class);
+
             return ejbModule;
         }
 

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppInfoBuilder.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppInfoBuilder.java?rev=1342699&r1=1342698&r2=1342699&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppInfoBuilder.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppInfoBuilder.java Fri May 25 15:47:24 2012
@@ -104,6 +104,7 @@ class AppInfoBuilder {
         appInfo.standaloneModule = appModule.isStandaloneModule();
         appInfo.watchedResources.addAll(appModule.getWatchedResources());
         appInfo.mbeans.addAll(appModule.getAdditionalLibMbeans());
+        appInfo.jaxRsProviders.addAll(appModule.getJaxRsProviders());
 
         if (appInfo.appId == null) throw new IllegalArgumentException("AppInfo.appId cannot be null");
         if (appInfo.path == null) appInfo.path = appInfo.appId;
@@ -324,6 +325,7 @@ class AppInfoBuilder {
             webAppInfo.ejbWebServices.addAll(webModule.getEjbWebServices());
             webAppInfo.ejbRestServices.addAll(webModule.getEjbRestServices());
             webAppInfo.webAnnotatedClasses.addAll(webModule.getWebAnnotatedClasses());
+            webAppInfo.jaxRsProviders.addAll(webModule.getJaxrsProviders());
 
             for (Map.Entry<String, Set<String>> entry : webModule.getJsfAnnotatedClasses().entrySet()) {
                 final ClassListInfo info = new ClassListInfo();

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppModule.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppModule.java?rev=1342699&r1=1342698&r2=1342699&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppModule.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/AppModule.java Fri May 25 15:47:24 2012
@@ -55,6 +55,7 @@ public class AppModule implements Deploy
     private final Set<String> watchedResources = new TreeSet<String>();
     private final boolean standaloneModule;
     private final Set<String> additionalLibMbeans = new TreeSet<String>();
+    private Collection<String> jaxRsProviders = new TreeSet<String>();
 
     private ID id;
     private boolean webapp = false;
@@ -286,4 +287,8 @@ public class AppModule implements Deploy
     public boolean isWebapp() {
         return webapp;
     }
+
+    public Collection<String> getJaxRsProviders() {
+        return jaxRsProviders;
+    }
 }

Modified: openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/WebModule.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/WebModule.java?rev=1342699&r1=1342698&r2=1342699&view=diff
==============================================================================
--- openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/WebModule.java (original)
+++ openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/WebModule.java Fri May 25 15:47:24 2012
@@ -49,6 +49,7 @@ public class WebModule extends Module im
     private final Set<String> restClasses = new TreeSet<String>();
     private final Set<String> ejbWebServices = new TreeSet<String>();
     private final Set<String> ejbRestServices = new TreeSet<String>();
+    private final Set<String> jaxrsProviders = new TreeSet<String>();
     private final Set<String> restApplications = new TreeSet<String>();
     private final Map<String, Set<String>> jsfAnnotatedClasses = new HashMap<String, Set<String>>();
     private final Set<String> webAnnotatedClasses = new TreeSet<String>();
@@ -204,4 +205,8 @@ public class WebModule extends Module im
     public Set<String> getWebAnnotatedClasses() {
         return webAnnotatedClasses;
     }
+
+    public Set<String> getJaxrsProviders() {
+        return jaxrsProviders;
+    }
 }

Modified: openejb/trunk/openejb/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java?rev=1342699&r1=1342698&r2=1342699&view=diff
==============================================================================
--- openejb/trunk/openejb/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java (original)
+++ openejb/trunk/openejb/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java Fri May 25 15:47:24 2012
@@ -16,6 +16,15 @@
  */
 package org.apache.openejb.server.cxf.rs;
 
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.naming.Context;
+import javax.servlet.http.HttpServletRequestWrapper;
+import javax.ws.rs.core.Application;
+import javax.xml.bind.Marshaller;
 import org.apache.cxf.endpoint.Server;
 import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
 import org.apache.cxf.jaxrs.lifecycle.ResourceProvider;
@@ -34,19 +43,6 @@ import org.apache.openejb.server.httpd.H
 import org.apache.openejb.server.rest.RsHttpListener;
 import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
-
-import javax.naming.Context;
-import javax.servlet.http.HttpServletRequestWrapper;
-import javax.ws.rs.core.Application;
-import javax.xml.bind.Marshaller;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
 import org.apache.openejb.util.ObjectRecipeHelper;
 import org.apache.webbeans.config.WebBeansContext;
 
@@ -64,8 +60,10 @@ public class CxfRsHttpListener implement
     public static final String OPENEJB_CXF_JAXRS_PROVIDERS_KEY = "openejb.cxf.jax-rs.providers";
     public static final String OPENEJB_CXF_JAXRS_PROVIDERS_SUFFIX = ".providers";
     public static final String DEFAULT_CXF_JAXRS_PROVIDERS_KEY = "default";
+    public static final String OPENEJB_CXF_PROPERTIES = "openejb.cxf.rs.properties";
 
-    private static final List<?> PROVIDERS = createProviderList("", CxfRsHttpListener.class.getClassLoader());
+    private static final List<Object> PROVIDERS = createConfiguredProviderList("", CxfRsHttpListener.class.getClassLoader());
+    private static final Map<String, Object> cxfProperties = toMap(SystemInstance.get().getProperty(OPENEJB_CXF_PROPERTIES));
 
     private HTTPTransportFactory transportFactory;
     private AbstractHTTPDestination destination;
@@ -90,25 +88,37 @@ public class CxfRsHttpListener implement
         }, httpResponse);
     }
 
-    @Override public void deploySingleton(String fullContext, Object o, Application appInstance) {
-        deploy(o.getClass(), fullContext, new SingletonResourceProvider(o), o, appInstance, null);
+    @Override public void deploySingleton(String fullContext, Object o, Application appInstance, Collection<Class<?>> additionalProviders) {
+        deploy(o.getClass(), fullContext, new SingletonResourceProvider(o), o, appInstance, null, additionalProviders);
     }
 
-    @Override public void deployPojo(String fullContext, Class<?> loadedClazz, Application app, Collection<Injection> injections, Context context, WebBeansContext owbCtx) {
-        deploy(loadedClazz, fullContext, new OpenEJBPerRequestPojoResourceProvider(loadedClazz, injections, context, owbCtx), null, app, null);
+    @Override public void deployPojo(String fullContext, Class<?> loadedClazz, Application app, Collection<Injection> injections, Context context, WebBeansContext owbCtx, Collection<Class<?>> additionalProviders) {
+        deploy(loadedClazz, fullContext, new OpenEJBPerRequestPojoResourceProvider(loadedClazz, injections, context, owbCtx), null, app, null, additionalProviders);
     }
 
-    @Override public void deployEJB(String fullContext, BeanContext beanContext) {
-        deploy(beanContext.getBeanClass(), fullContext, null, null, null, new OpenEJBEJBInvoker(beanContext));
+    @Override public void deployEJB(String fullContext, BeanContext beanContext, Collection<Class<?>> additionalProviders) {
+        deploy(beanContext.getBeanClass(), fullContext, null, null, null, new OpenEJBEJBInvoker(beanContext), additionalProviders);
     }
 
-    private void deploy(Class<?> clazz, String address, ResourceProvider rp, Object serviceBean, Application app, Invoker invoker) {
-        JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
+    private void deploy(Class<?> clazz, String address, ResourceProvider rp, Object serviceBean, Application app, Invoker invoker, Collection<Class<?>> additionalProviders) {
+        final List<Object> providers = createConfiguredProviderList(nameForProviders(clazz), clazz.getClassLoader());
+        if (additionalProviders != null && !additionalProviders.isEmpty()) {
+            providers.addAll(instantiate(additionalProviders));
+        }
+
+        final JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
         factory.setResourceClasses(clazz);
         factory.setDestinationFactory(transportFactory);
         factory.setBus(transportFactory.getBus());
         factory.setAddress(address);
-        factory.setProviders(createProviderList(nameForProviders(clazz), clazz.getClassLoader()));
+        factory.setProviders(providers);
+        if (cxfProperties != null) {
+            if (factory.getProperties() == null) {
+                factory.setProperties(cxfProperties);
+            } else {
+                factory.getProperties().putAll(cxfProperties);
+            }
+        }
         if (rp != null) {
             factory.setResourceProvider(rp);
         }
@@ -128,6 +138,20 @@ public class CxfRsHttpListener implement
         destination = (AbstractHTTPDestination) server.getDestination();
     }
 
+    private Collection<Object> instantiate(final Collection<Class<?>> classes) {
+        final List<Object> instances = new ArrayList<Object>();
+        for (Class<?> clazz : classes) {
+            try {
+                instances.add(clazz.newInstance());
+            } catch (InstantiationException e) {
+                LOGGER.warning("can't instantiate '" + clazz.getName() + "'", e);
+            } catch (IllegalAccessException e) {
+                LOGGER.warning("can't access '" + clazz.getName() + "'", e);
+            }
+        }
+        return instances;
+    }
+
     private String nameForProviders(Class<?> clazz) {
         if (clazz == null) {
             return "default"; // whatever it is it will be overriden by default providers
@@ -139,7 +163,7 @@ public class CxfRsHttpListener implement
         server.stop();
     }
 
-    private static List<?> createProviderList(final String prefix, final ClassLoader loader) {
+    private static List<Object> createConfiguredProviderList(final String prefix, final ClassLoader loader) {
         final String key;
         final String systPropPrefix;
         if (prefix == null || prefix.trim().isEmpty()) {
@@ -149,9 +173,10 @@ public class CxfRsHttpListener implement
             key = prefix + OPENEJB_CXF_JAXRS_PROVIDERS_SUFFIX;
             systPropPrefix = prefix + ".";
         }
+
         String providersProperty = SystemInstance.get().getProperty(key);
         // if no overriding
-        if (providersProperty == null || providersProperty.trim().isEmpty() && PROVIDERS != null) {
+        if (PROVIDERS != null && (providersProperty == null || providersProperty.trim().isEmpty())) {
             return PROVIDERS;
         }
 
@@ -163,9 +188,9 @@ public class CxfRsHttpListener implement
         JSONProvider json = new JSONProvider();
         json.setSerializeAsArray(true);
 
+        List<Object> providerList = new ArrayList<Object>();
         if (providersProperty != null && !providersProperty.trim().isEmpty()) {
             String[] providers = providersProperty.split(",|;| ");
-            List<Object> providerList = new ArrayList<Object>();
             for (String provider : providers) {
                 if (DEFAULT_CXF_JAXRS_PROVIDERS_KEY.equals(provider)) {
                     providerList.add(json);
@@ -181,6 +206,25 @@ public class CxfRsHttpListener implement
             return providerList;
         }
 
-        return Arrays.asList(jaxb, json);
+        providerList.add(jaxb);
+        providerList.add(json);
+        return providerList;
+    }
+
+    private static Map<String, Object> toMap(String property) {
+        if (property == null || property.isEmpty()) {
+            return null;
+        }
+
+        final Map<String, Object> properties = new HashMap<String, Object>();
+        for (String str : property.split("|")) {
+            final String[] kv = str.split("=");
+            if (kv.length == 2) {
+                properties.put(kv[0], kv[1]);
+            } else {
+                properties.put(str, "");
+            }
+        }
+        return properties;
     }
 }

Added: openejb/trunk/openejb/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/DiscoverCustomProviderTest.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/DiscoverCustomProviderTest.java?rev=1342699&view=auto
==============================================================================
--- openejb/trunk/openejb/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/DiscoverCustomProviderTest.java (added)
+++ openejb/trunk/openejb/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/DiscoverCustomProviderTest.java Fri May 25 15:47:24 2012
@@ -0,0 +1,106 @@
+/**
+ * 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.openejb.server.cxf.rs;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Properties;
+import javax.ejb.Singleton;
+import javax.ejb.embeddable.EJBContainer;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+import org.apache.cxf.jaxrs.client.WebClient;
+import org.apache.openejb.OpenEjbContainer;
+import org.apache.openejb.server.rest.RESTService;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static junit.framework.Assert.assertEquals;
+
+public class DiscoverCustomProviderTest {
+    private static EJBContainer container;
+
+    @BeforeClass
+    public static void start() throws Exception {
+        final Properties properties = new Properties();
+        properties.setProperty(OpenEjbContainer.OPENEJB_EMBEDDED_REMOTABLE, "true");
+        properties.setProperty(RESTService.OPENEJB_JAXRS_PROVIDERS_AUTO_PROP, "true");
+        properties.setProperty("openejb.cxf.rs.properties", "faultStackTraceEnabled=true");
+        container = EJBContainer.createEJBContainer(properties);
+    }
+
+    @AfterClass
+    public static void close() throws Exception {
+        if (container != null) {
+            container.close();
+        }
+    }
+
+    @Test
+    public void customProvider() {
+        final String response = WebClient.create("http://localhost:4204/openejb-cxf-rs")
+                .accept("discover/reverse")
+                .path("the/service").get(String.class);
+        assertEquals("it rocks", response);
+    }
+
+    @Singleton
+    @Path("the")
+    public static class TheService {
+        @GET
+        @Path("service")
+        @Produces("discover/reverse")
+        public String go() {
+            return "skcor ti";
+        }
+    }
+
+    @Provider
+    @Produces("discover/reverse")
+    public static class ReverseProvider<T> implements MessageBodyWriter<T> {
+        private String reverse(String str) {
+            if (str == null) {
+                return "";
+            }
+            return new StringBuilder(str).reverse().toString();
+        }
+
+        @Override
+        public long getSize(T t, Class<?> rawType, Type genericType, Annotation[] annotations, MediaType mediaType) {
+            return -1;
+        }
+
+        @Override
+        public boolean isWriteable(Class<?> rawType, Type genericType, Annotation[] annotations, MediaType mediaType) {
+            return true;
+        }
+
+        @Override
+        public void writeTo(T t, Class<?> rawType, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream) throws IOException {
+            entityStream.write(reverse((String) t).getBytes());
+        }
+    }
+}

Modified: openejb/trunk/openejb/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RESTService.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RESTService.java?rev=1342699&r1=1342698&r2=1342699&view=diff
==============================================================================
--- openejb/trunk/openejb/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RESTService.java (original)
+++ openejb/trunk/openejb/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RESTService.java Fri May 25 15:47:24 2012
@@ -61,6 +61,7 @@ import org.apache.webbeans.config.WebBea
 public abstract class RESTService implements ServerService, SelfManaging, DeploymentListener {
     public static final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB_RS, RESTService.class);
     private static final boolean OLD_WEBSERVICE_DEPLOYMENT = SystemInstance.get().getOptions().get("openejb.webservice.old-deployment", false);
+    public static final String OPENEJB_JAXRS_PROVIDERS_AUTO_PROP = "openejb.jaxrs.providers.auto";
 
     private static final String IP = "n/a";
     private static final int PORT = -1;
@@ -95,6 +96,18 @@ public abstract class RESTService implem
             context = webContext.getAppContext().getAppJndiContext();
         }
 
+        final Collection<Class<?>> additionalProviders = new HashSet<Class<?>>();
+        if (useDiscoveredProviders()) {
+            for (String name : webApp.jaxRsProviders) {
+                try {
+                    additionalProviders.add(classLoader.loadClass(name));
+                } catch (ClassNotFoundException e) {
+                    LOGGER.warning("can't load '" + name + "'", e);
+                }
+            }
+            additionalProviders.addAll(appProviders(appInfo, classLoader));
+        }
+
         // The spec says:
         //
         // "The resources and providers that make up a JAX-RS application are configured via an application-supplied
@@ -142,17 +155,17 @@ public abstract class RESTService implem
 
                 if (restEjbs.containsKey(o.getClass().getName())) {
                     // no more a singleton if the ejb i not a singleton...but it is a weird case
-                    deployEJB(appPrefix, restEjbs.get(o.getClass().getName()).context);
+                    deployEJB(appPrefix, restEjbs.get(o.getClass().getName()).context, additionalProviders);
                 } else {
-                    deploySingleton(appPrefix, o, appInstance, classLoader);
+                    deploySingleton(appPrefix, o, appInstance, classLoader, additionalProviders);
                 }
             }
             Set<Class<?>> classes = appInstance.getClasses();
             for (Class<?> clazz : classes) {
                 if (restEjbs.containsKey(clazz.getName())) {
-                    deployEJB(appPrefix, restEjbs.get(clazz.getName()).context);
+                    deployEJB(appPrefix, restEjbs.get(clazz.getName()).context, additionalProviders);
                 } else {
-                    deployPojo(appPrefix, clazz, appInstance, classLoader, injections, context, owbCtx);
+                    deployPojo(appPrefix, clazz, appInstance, classLoader, injections, context, owbCtx, additionalProviders);
                 }
             }
 
@@ -166,11 +179,11 @@ public abstract class RESTService implem
 
             for (String clazz : restClasses) {
                 if (restEjbs.containsKey(clazz)) {
-                    deployEJB(appPrefix, restEjbs.get(clazz).context);
+                    deployEJB(appPrefix, restEjbs.get(clazz).context, additionalProviders);
                 } else {
                     try {
                         Class<?> loadedClazz = classLoader.loadClass(clazz);
-                        deployPojo(appPrefix, loadedClazz, null, classLoader, injections, context, owbCtx);
+                        deployPojo(appPrefix, loadedClazz, null, classLoader, injections, context, owbCtx, additionalProviders);
                     } catch (ClassNotFoundException e) {
                         throw new OpenEJBRestRuntimeException("can't find class " + clazz, e);
                     }
@@ -181,12 +194,35 @@ public abstract class RESTService implem
         restEjbs.clear();
     }
 
+    private boolean useDiscoveredProviders() {
+        return SystemInstance.get().getOptions().get(OPENEJB_JAXRS_PROVIDERS_AUTO_PROP, false);
+    }
+
+    private Collection<Class<?>> appProviders(final AppInfo appInfo, final ClassLoader classLoader) {
+        final Collection<Class<?>> additionalProviders = new HashSet<Class<?>>();
+        for (String name : appInfo.jaxRsProviders) {
+            try {
+                additionalProviders.add(classLoader.loadClass(name));
+            } catch (ClassNotFoundException e) {
+                LOGGER.warning("can't load '" + name + "'", e);
+            }
+        }
+        return additionalProviders;
+    }
+
     @Override public void afterApplicationCreated(final AppInfo appInfo) {
         if (deployedApplications.add(appInfo)) {
             if (appInfo.webApps.size() == 0) {
-                Map<String, EJBRestServiceInfo> restEjbs = getRestEjbs(appInfo);
+                final Map<String, EJBRestServiceInfo> restEjbs = getRestEjbs(appInfo);
+                final Collection<Class<?>> providers;
+                if (useDiscoveredProviders()) {
+                    providers = appProviders(appInfo, containerSystem.getAppContext(appInfo.appId).getClassLoader());
+                } else {
+                    providers = new ArrayList<Class<?>>();
+                }
+
                 for (Map.Entry<String, EJBRestServiceInfo> ejb : restEjbs.entrySet()) {
-                    deployEJB(ejb.getValue().path, ejb.getValue().context);
+                    deployEJB(ejb.getValue().path, ejb.getValue().context, providers);
                 }
                 restEjbs.clear();
             } else {
@@ -238,26 +274,18 @@ public abstract class RESTService implem
         return restEjbs;
     }
 
-    private void deploySingleton(String contextRoot, Object o, Application appInstance, ClassLoader classLoader) {
+    private void deploySingleton(String contextRoot, Object o, Application appInstance, ClassLoader classLoader, Collection<Class<?>> additionalProviders) {
         final String nopath = getAddress(contextRoot, o.getClass());
         final RsHttpListener listener = createHttpListener();
         final RsRegistry.AddressInfo address = rsRegistry.createRsHttpListener(contextRoot, listener, classLoader, nopath.substring(NOPATH_PREFIX.length() - 1), virtualHost);
 
         services.add(new DeployedService(address.complete, contextRoot, o.getClass().getName()));
-        listener.deploySingleton(getFullContext(address.base, contextRoot), o, appInstance);
+        listener.deploySingleton(getFullContext(address.base, contextRoot), o, appInstance, additionalProviders);
 
         LOGGER.info("deployed REST singleton: " + o);
     }
 
-    private static String baseAddress(final String address, final String contextRoot) {
-        if (contextRoot == null || contextRoot.isEmpty()) {
-            return address;
-        }
-        int idx = address.indexOf(contextRoot);
-        return address.substring(0, idx) + contextRoot;
-    }
-
-    private void deployPojo(String contextRoot, Class<?> loadedClazz, Application app, ClassLoader classLoader, Collection<Injection> injections, Context context, WebBeansContext owbCtx) {
+    private void deployPojo(String contextRoot, Class<?> loadedClazz, Application app, ClassLoader classLoader, Collection<Injection> injections, Context context, WebBeansContext owbCtx, Collection<Class<?>> additionalProviders) {
         if (loadedClazz.isInterface()) {
             return;
         }
@@ -267,18 +295,18 @@ public abstract class RESTService implem
         final RsRegistry.AddressInfo address = rsRegistry.createRsHttpListener(contextRoot, listener, classLoader, nopath.substring(NOPATH_PREFIX.length() - 1), virtualHost);
 
         services.add(new DeployedService(address.complete, contextRoot, loadedClazz.getName()));
-        listener.deployPojo(getFullContext(address.base, contextRoot), loadedClazz, app, injections, context, owbCtx);
+        listener.deployPojo(getFullContext(address.base, contextRoot), loadedClazz, app, injections, context, owbCtx, additionalProviders);
 
         LOGGER.info("REST Service: " + address.complete + "  -> Pojo " + loadedClazz.getName());
     }
 
-    private void deployEJB(String context, BeanContext beanContext) {
+    private void deployEJB(String context, BeanContext beanContext, Collection<Class<?>> additionalProviders) {
         final String nopath = getAddress(context, beanContext.getBeanClass());
         final RsHttpListener listener = createHttpListener();
         final RsRegistry.AddressInfo address = rsRegistry.createRsHttpListener(context, listener, beanContext.getClassLoader(), nopath.substring(NOPATH_PREFIX.length() - 1), virtualHost);
 
         services.add(new DeployedService(address.complete, context, beanContext.getBeanClass().getName()));
-        listener.deployEJB(getFullContext(address.base, context), beanContext);
+        listener.deployEJB(getFullContext(address.base, context), beanContext, additionalProviders);
 
         LOGGER.info("REST Service: " + address.complete + "  -> EJB " + beanContext.getEjbName());
     }

Modified: openejb/trunk/openejb/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RsHttpListener.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RsHttpListener.java?rev=1342699&r1=1342698&r2=1342699&view=diff
==============================================================================
--- openejb/trunk/openejb/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RsHttpListener.java (original)
+++ openejb/trunk/openejb/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RsHttpListener.java Fri May 25 15:47:24 2012
@@ -26,11 +26,11 @@ import org.apache.openejb.server.httpd.H
 import org.apache.webbeans.config.WebBeansContext;
 
 public interface RsHttpListener extends HttpListener {
-    void deploySingleton(String fullContext, Object o, Application appInstance);
+    void deploySingleton(String fullContext, Object o, Application appInstance, Collection<Class<?>> additionalProviders);
 
-    void deployPojo(String fullContext, Class<?> loadedClazz, Application app, Collection<Injection> injections, Context context, WebBeansContext owbCtx);
+    void deployPojo(String fullContext, Class<?> loadedClazz, Application app, Collection<Injection> injections, Context context, WebBeansContext owbCtx, Collection<Class<?>> additionalProviders);
 
-    void deployEJB(String fullContext, BeanContext beanContext);
+    void deployEJB(String fullContext, BeanContext beanContext, Collection<Class<?>> additionalProviders);
 
     void undeploy();
 }

Modified: openejb/trunk/openejb/server/openejb-wink/src/main/java/org/apache/openejb/server/wink/WinkHttpListener.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/server/openejb-wink/src/main/java/org/apache/openejb/server/wink/WinkHttpListener.java?rev=1342699&r1=1342698&r2=1342699&view=diff
==============================================================================
--- openejb/trunk/openejb/server/openejb-wink/src/main/java/org/apache/openejb/server/wink/WinkHttpListener.java (original)
+++ openejb/trunk/openejb/server/openejb-wink/src/main/java/org/apache/openejb/server/wink/WinkHttpListener.java Fri May 25 15:47:24 2012
@@ -36,24 +36,24 @@ import org.apache.wink.server.internal.D
 import org.apache.wink.server.internal.RequestProcessor;
 import org.apache.wink.server.utils.RegistrationUtils;
 
-// TODO: lifecycle (se cxf-rs invokers)
+// TODO: lifecycle, providers (se cxf-rs invokers)
 // TODO: see if using RestServlet is not more relevant = breaking our RsHttpListener
 public class WinkHttpListener implements RsHttpListener {
     private RequestProcessor processor;
     private ServletContext servletContext;
 
     @Override
-    public void deployEJB(final String fullContext, final BeanContext beanContext) {
-        deployPojo(fullContext, beanContext.getBeanClass(), null, null, null, null); // TODO
+    public void deployEJB(final String fullContext, final BeanContext beanContext, Collection<Class<?>> additionalProviders) {
+        deployPojo(fullContext, beanContext.getBeanClass(), null, null, null, null, additionalProviders); // TODO
     }
 
     @Override
-    public void deploySingleton(final String fullContext, final Object o, final Application appInstance) {
+    public void deploySingleton(final String fullContext, final Object o, final Application appInstance, Collection<Class<?>> additionalProviders) {
         RegistrationUtils.registerInstances(contexts(o.getClass().getClassLoader()), o);
     }
 
     @Override
-    public void deployPojo(final String fullContext, final Class<?> loadedClazz, final Application app, final Collection<Injection> injections, final Context context, final WebBeansContext owbCtx) {
+    public void deployPojo(final String fullContext, final Class<?> loadedClazz, final Application app, final Collection<Injection> injections, final Context context, final WebBeansContext owbCtx, Collection<Class<?>> additionalProviders) {
         RegistrationUtils.registerClasses(contexts(loadedClazz.getClassLoader()), loadedClazz);
     }
 

Modified: openejb/trunk/openejb/tomee/tomee-jaxrs/src/main/java/org/apache/tomee/webservices/TomcatRsRegistry.java
URL: http://svn.apache.org/viewvc/openejb/trunk/openejb/tomee/tomee-jaxrs/src/main/java/org/apache/tomee/webservices/TomcatRsRegistry.java?rev=1342699&r1=1342698&r2=1342699&view=diff
==============================================================================
--- openejb/trunk/openejb/tomee/tomee-jaxrs/src/main/java/org/apache/tomee/webservices/TomcatRsRegistry.java (original)
+++ openejb/trunk/openejb/tomee/tomee-jaxrs/src/main/java/org/apache/tomee/webservices/TomcatRsRegistry.java Fri May 25 15:47:24 2012
@@ -16,13 +16,16 @@
  */
 package org.apache.tomee.webservices;
 
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
 import org.apache.catalina.Container;
 import org.apache.catalina.Context;
 import org.apache.catalina.Engine;
-import org.apache.catalina.Host;
-import org.apache.catalina.Lifecycle;
-import org.apache.catalina.LifecycleEvent;
-import org.apache.catalina.LifecycleListener;
 import org.apache.catalina.Service;
 import org.apache.catalina.Wrapper;
 import org.apache.catalina.connector.Connector;
@@ -33,20 +36,8 @@ import org.apache.openejb.server.rest.Rs
 import org.apache.openejb.server.rest.RsServlet;
 import org.apache.openejb.util.LogCategory;
 import org.apache.openejb.util.Logger;
-import org.apache.tomee.catalina.TomEERuntimeException;
-import org.apache.tomee.catalina.TomcatWebAppBuilder;
 import org.apache.tomee.loader.TomcatHelper;
 
-import java.net.URI;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-import java.util.TreeMap;
-
-import static org.apache.tomee.catalina.TomcatWebAppBuilder.IGNORE_CONTEXT;
-
 public class TomcatRsRegistry implements RsRegistry {
     private static final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB_STARTUP, TomcatRsRegistry.class);