This is an automated email from the ASF dual-hosted git repository.

rmannibucau pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/aries-jax-rs-whiteboard.git


The following commit(s) were added to refs/heads/master by this push:
     new 9bc35a6  [ARIES-2002] ensure proxies are unwrapped for jaxrs resources
9bc35a6 is described below

commit 9bc35a623ed0cf0c4a0e1f583d5be60027a23f49
Author: Romain Manni-Bucau <rmannibu...@gmail.com>
AuthorDate: Tue Sep 22 16:50:53 2020 +0200

    [ARIES-2002] ensure proxies are unwrapped for jaxrs resources
---
 .../internal/cxf/CxfJaxrsServiceRegistrator.java   | 85 ++++++++++++++++++++--
 .../internal/cxf/PromiseAwareJAXRSInvoker.java     | 12 +--
 .../internal/introspection/ClassIntrospector.java  | 12 ++-
 .../whiteboard/internal/introspection/Proxies.java | 31 ++++++++
 4 files changed, 129 insertions(+), 11 deletions(-)

diff --git 
a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/cxf/CxfJaxrsServiceRegistrator.java
 
b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/cxf/CxfJaxrsServiceRegistrator.java
index f1ba154..22dfc88 100644
--- 
a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/cxf/CxfJaxrsServiceRegistrator.java
+++ 
b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/cxf/CxfJaxrsServiceRegistrator.java
@@ -23,6 +23,7 @@ import static 
org.apache.aries.jax.rs.whiteboard.internal.Whiteboard.SUPPORTED_E
 import static 
org.apache.aries.jax.rs.whiteboard.internal.utils.Utils.canonicalize;
 import static 
org.apache.cxf.jaxrs.provider.ProviderFactory.DEFAULT_FILTER_NAME_BINDING;
 
+import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -34,16 +35,17 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
-import java.util.function.Supplier;
 import java.util.stream.Collectors;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 
+import javax.ws.rs.ApplicationPath;
 import javax.ws.rs.RuntimeType;
 import javax.ws.rs.container.DynamicFeature;
 import javax.ws.rs.core.Application;
 import javax.ws.rs.core.Feature;
 import javax.ws.rs.core.FeatureContext;
+import javax.ws.rs.ext.Provider;
 import javax.ws.rs.ext.RuntimeDelegate;
 
 import org.apache.aries.component.dsl.CachingServiceReference;
@@ -51,6 +53,7 @@ import org.apache.aries.component.dsl.OSGi;
 import org.apache.aries.jax.rs.whiteboard.ApplicationClasses;
 import org.apache.aries.jax.rs.whiteboard.internal.AriesJaxrsServiceRuntime;
 import org.apache.aries.jax.rs.whiteboard.internal.ServiceReferenceRegistry;
+import org.apache.aries.jax.rs.whiteboard.internal.introspection.Proxies;
 import org.apache.aries.jax.rs.whiteboard.internal.utils.ServiceTuple;
 import org.apache.cxf.Bus;
 import org.apache.cxf.common.util.ClassHelper;
@@ -61,7 +64,9 @@ import org.apache.cxf.jaxrs.JAXRSServiceFactoryBean;
 import org.apache.cxf.jaxrs.ext.ContextProvider;
 import org.apache.cxf.jaxrs.ext.ResourceContextProvider;
 import org.apache.cxf.jaxrs.impl.ConfigurableImpl;
+import org.apache.cxf.jaxrs.lifecycle.PerRequestResourceProvider;
 import org.apache.cxf.jaxrs.lifecycle.ResourceProvider;
+import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
 import org.apache.cxf.jaxrs.model.ApplicationInfo;
 import org.apache.cxf.jaxrs.model.ClassResourceInfo;
 import 
org.apache.cxf.jaxrs.provider.ProviderFactory.ProviderInfoClassComparator;
@@ -69,6 +74,7 @@ import 
org.apache.cxf.jaxrs.provider.ServerConfigurableFactory;
 import org.apache.cxf.jaxrs.sse.SseContextProvider;
 import org.apache.cxf.jaxrs.sse.SseEventSinkContextProvider;
 import org.apache.cxf.jaxrs.utils.AnnotationUtils;
+import org.apache.cxf.jaxrs.utils.ResourceUtils;
 import org.apache.cxf.message.Message;
 
 public class CxfJaxrsServiceRegistrator {
@@ -196,19 +202,88 @@ public class CxfJaxrsServiceRegistrator {
     }
 
     public <T> T createEndpoint(Application app, Class<T> endpointType) {
-        JAXRSServerFactoryBean bean =
-            RuntimeDelegate.getInstance().createEndpoint(
-                app, JAXRSServerFactoryBean.class);
+        // final JAXRSServerFactoryBean bean = 
ResourceUtils.createApplication(app, false, false, false, null);
+        final JAXRSServerFactoryBean bean = new JAXRSServerFactoryBean();
+        Set<Object> singletons = app.getSingletons();
+        if (!singletons.isEmpty() && 
singletons.stream().map(Object::getClass).count() < singletons.size()) {
+            throw new IllegalArgumentException("More than one instance of the 
same singleton class is available: " + singletons);
+        }
+
+        final List<Class<?>> resourceClasses = new ArrayList<>();
+        final List<Object> providers = new ArrayList<>();
+        final List<org.apache.cxf.feature.Feature> features = new 
ArrayList<>();
+        final Map<Class<?>, ResourceProvider> map = new HashMap<>();
+
+        // Note, app.getClasses() returns a list of per-request classes
+        // or singleton provider classes
+        for (Class<?> cls : app.getClasses()) {
+            if (!cls.isInterface() && 
!Modifier.isAbstract(cls.getModifiers())) {
+                if (isProvider(cls)) {
+                    providers.add(ResourceUtils.createProviderInstance(cls));
+                } else if 
(org.apache.cxf.feature.Feature.class.isAssignableFrom(cls)) {
+                    features.add(ResourceUtils.createFeatureInstance((Class<? 
extends org.apache.cxf.feature.Feature>) cls));
+                } else {
+                    resourceClasses.add(cls);
+                    /* todo: support singleton provider otherwise perfs can be 
a shame
+                    if (useSingletonResourceProvider) {
+                        map.put(cls, new 
SingletonResourceProvider(ResourceUtils.createProviderInstance(cls)));
+                    } else {
+                     */
+                    map.put(cls, new PerRequestResourceProvider(cls));
+                }
+            }
+        }
+
+        // we can get either a provider or resource class here
+        for (final Object o : singletons) {
+            if (isProvider(o.getClass())) {
+                providers.add(o);
+            } else if (o instanceof org.apache.cxf.feature.Feature) {
+                features.add((org.apache.cxf.feature.Feature) o);
+            } else {
+                final Class<?> unwrapped = Proxies.unwrap(o.getClass());
+                resourceClasses.add(unwrapped);
+                map.put(unwrapped, new SingletonResourceProvider(o));
+            }
+        }
+
+        String address = "/";
+        ApplicationPath appPath = 
ResourceUtils.locateApplicationPath(app.getClass());
+        if (appPath != null) {
+            address = appPath.value();
+        }
+        if (!address.startsWith("/")) {
+            address = "/" + address;
+        }
+        // todo resolve conflicts between @ApplicationPath and 
@JaxrsApplicationBase (if same  value -> use only one?)
+        bean.setAddress(address);
+        bean.setStaticSubresourceResolution(false);
+        bean.setResourceClasses(resourceClasses);
+        bean.setProviders(providers);
+        bean.getFeatures().addAll(features);
+        for (Map.Entry<Class<?>, ResourceProvider> entry : map.entrySet()) {
+            bean.setResourceProvider(entry.getKey(), entry.getValue());
+        }
+        Map<String, Object> appProps = app.getProperties();
+        if (appProps != null) {
+            bean.getProperties(true).putAll(appProps);
+        }
+        bean.setApplication(app);
 
         if (JAXRSServerFactoryBean.class.isAssignableFrom(endpointType)) {
             return endpointType.cast(bean);
         }
+
         bean.setApplication(app);
         bean.setStart(false);
-        Server server = bean.create();
+        final Server server = bean.create();
         return endpointType.cast(server);
     }
 
+    private boolean isProvider(Class<?> cls) {
+        return cls.isAnnotationPresent(Provider.class) || 
SUPPORTED_EXTENSION_INTERFACES.values().stream().anyMatch(it -> 
it.isAssignableFrom(cls));
+    }
+
     public Bus getBus() {
         return _bus;
     }
diff --git 
a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/cxf/PromiseAwareJAXRSInvoker.java
 
b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/cxf/PromiseAwareJAXRSInvoker.java
index e71c2c0..0115ddf 100644
--- 
a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/cxf/PromiseAwareJAXRSInvoker.java
+++ 
b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/cxf/PromiseAwareJAXRSInvoker.java
@@ -17,6 +17,8 @@
 package org.apache.aries.jax.rs.whiteboard.internal.cxf;
 
 import java.util.Arrays;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
 
 import org.apache.cxf.jaxrs.JAXRSInvoker;
 import org.apache.cxf.jaxrs.impl.AsyncResponseImpl;
@@ -24,6 +26,7 @@ import org.apache.cxf.message.Message;
 import org.osgi.util.promise.Promise;
 
 public class PromiseAwareJAXRSInvoker extends JAXRSInvoker {
+    private final ConcurrentMap<Class<?>, Boolean> promises = new 
ConcurrentHashMap<>();
     
     /**
      * OSGi promises are a great way to do asynchronous work, and should be 
handled
@@ -40,11 +43,10 @@ public class PromiseAwareJAXRSInvoker extends JAXRSInvoker {
         } 
         
         // Slower check, is it a Promise?
-        Class<?> clazz = result.getClass();
-        if(Arrays.stream(clazz.getInterfaces())
-            .map(Class::getName)
-            .anyMatch(n -> "org.osgi.util.promise.Promise".equals(n))) {
-            
+        final Class<?> clazz = result.getClass();
+        if (promises.computeIfAbsent(clazz, type -> 
Arrays.stream(type.getInterfaces())
+                .map(Class::getName)
+                .anyMatch("org.osgi.util.promise.Promise"::equals))) {
             return handlePromiseFromAnotherClassSpace(inMessage, result, 
clazz);
         }
         
diff --git 
a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/introspection/ClassIntrospector.java
 
b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/introspection/ClassIntrospector.java
index 07877de..941a399 100644
--- 
a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/introspection/ClassIntrospector.java
+++ 
b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/introspection/ClassIntrospector.java
@@ -18,6 +18,7 @@
 package org.apache.aries.jax.rs.whiteboard.internal.introspection;
 
 import org.apache.cxf.Bus;
+import org.apache.cxf.common.util.ClassUnwrapper;
 import org.apache.cxf.jaxrs.model.ClassResourceInfo;
 import org.apache.cxf.jaxrs.model.MethodDispatcher;
 import org.apache.cxf.jaxrs.model.OperationResourceInfo;
@@ -45,9 +46,10 @@ public class ClassIntrospector {
     public static Collection<ResourceMethodInfoDTO> getResourceMethodInfos(
         Class<?> clazz, Bus bus) {
 
+        final Class<?> realClass = unwrap(clazz, bus);
         ClassResourceInfo classResourceInfo =
             ResourceUtils.createClassResourceInfo(
-                clazz, clazz, true, true, bus);
+                    realClass, realClass, true, true, bus);
 
         Stream<ResourceMethodInfoDTO> convert = convert(
             new HashSet<>(), "/", null, null, null, null,
@@ -56,6 +58,14 @@ public class ClassIntrospector {
         return convert.collect(Collectors.toList());
     }
 
+    private static Class<?> unwrap(final Class<?> clazz, final Bus bus) {
+        final ClassUnwrapper unwrapper = bus == null ? null : 
bus.getExtension(ClassUnwrapper.class);
+        if (unwrapper != null) {
+            return unwrapper.getRealClassFromClass(clazz);
+        }
+        return Proxies.unwrap(clazz);
+    }
+
     private static Stream<ResourceMethodInfoDTO> convert(
         Set<ClassResourceInfo> visited,
         String parentPath, String defaultHttpMethod,
diff --git 
a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/introspection/Proxies.java
 
b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/introspection/Proxies.java
new file mode 100644
index 0000000..415e7e7
--- /dev/null
+++ 
b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/introspection/Proxies.java
@@ -0,0 +1,31 @@
+/*
+ * 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.aries.jax.rs.whiteboard.internal.introspection;
+
+public final class Proxies {
+    private Proxies() {
+        // no-op
+    }
+
+    public static Class<?> unwrap(final Class<?> aClass) {
+        Class<?> current = aClass;
+        while (current != null && current != Object.class && 
current.getName().contains("$$")) {
+            current = current.getSuperclass();
+        }
+        return current == null ? aClass : current;
+    }
+}

Reply via email to