From ea17ab76d5ec68b344ba87acbee265e8ad3e9ac1 Mon Sep 17 00:00:00 2001 From: Alessio Soldano Date: Fri, 1 Mar 2019 01:00:32 +0100 Subject: [PATCH] [RESTEASY-2174][RESTEASY-2175] ResteasyProviderFactory refactoring / optimization (#1879) * TCCL-based cache of initial client ResteasyProviderFactory * Get rid of exceptionMapper in RPF (use sortedExceptionMappers) * Reduce number of objects created for each new RPF instance * RPF refactoring to split the class into some smaller / more readable ones and to allow reducing memory allocation in case the RPF is needed only on client or server side * Minor cleanup of MediaTypeMap * Adding MediaType cache * Replacing Class#newInstance method usage in RPF (deprecated in JDK9) * Some reasonable sizing of ConcurrentHashMaps in RPF (based on the number of existing implementations in RESTEasy for the various keys) * Adding MediaType -> String (reverse) map * Simple bench test to measure performance of RPF usage on client side --- .../jaxrs/internal/ClientConfiguration.java | 5 +- .../LocalResteasyProviderFactory.java | 11 +- .../internal/ResteasyClientBuilderImpl.java | 14 +- .../resteasy/spi/ResteasyProviderFactory.java | 4 +- .../jboss/resteasy/core/ExceptionHandler.java | 7 +- .../resteasy/core/InjectorFactoryImpl.java | 2 + .../org/jboss/resteasy/core/MediaTypeMap.java | 15 +- .../resteasy/core/ResourceMethodInvoker.java | 21 +- .../ThreadLocalResteasyProviderFactory.java | 7 +- .../jaxrs/ServerReaderInterceptorContext.java | 2 +- .../jaxrs/ServerWriterInterceptorContext.java | 2 +- .../core/providerfactory/ClientHelper.java | 530 +++++++ .../core/providerfactory/ExtSortedKey.java | 34 + .../providerfactory/NOOPClientHelper.java | 138 ++ .../providerfactory/NOOPServerHelper.java | 120 ++ .../ResteasyProviderFactoryImpl.java | 1314 +++-------------- .../core/providerfactory/ServerHelper.java | 537 +++++++ .../core/providerfactory/SortedKey.java | 77 + .../resteasy/core/providerfactory/Utils.java | 164 ++ .../resteasy/mock/MockDispatcherFactory.java | 2 +- .../delegates/CacheControlDelegate.java | 2 + .../delegates/CookieHeaderDelegate.java | 2 +- .../plugins/delegates/DateDelegate.java | 2 + .../plugins/delegates/EntityTagDelegate.java | 2 + .../plugins/delegates/LinkDelegate.java | 2 + .../plugins/delegates/LinkHeaderDelegate.java | 2 + .../plugins/delegates/LocaleDelegate.java | 2 + .../delegates/MediaTypeHeaderDelegate.java | 41 + .../delegates/NewCookieHeaderDelegate.java | 1 + .../plugins/delegates/UriHeaderDelegate.java | 2 + .../plugins/providers/RegisterBuiltin.java | 54 +- .../providers/sse/InboundSseEventImpl.java | 4 +- .../services/javax.ws.rs.ext.RuntimeDelegate | 2 +- .../test/i18n/TestMessagesAbstract.java | 2 +- .../jboss/resteasy/jwt/JsonSerialization.java | 2 +- .../client/InContainerClientBenchTest.java | 107 ++ .../resource/InContainerClientResource.java | 30 + .../client/ConfigurationInheritanceTest.java | 2 +- .../test/providers/HeaderDelegateTest.java | 2 +- .../providers/MultipurtContainsJsonTest.java | 4 +- .../test/providers/PriorityEqualityTest.java | 6 +- 41 files changed, 2129 insertions(+), 1150 deletions(-) create mode 100644 resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/ClientHelper.java create mode 100644 resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/ExtSortedKey.java create mode 100644 resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/NOOPClientHelper.java create mode 100644 resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/NOOPServerHelper.java rename resteasy-core/src/main/java/org/jboss/resteasy/core/{ => providerfactory}/ResteasyProviderFactoryImpl.java (52%) create mode 100644 resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/ServerHelper.java create mode 100644 resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/SortedKey.java create mode 100644 resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/Utils.java create mode 100644 testsuite/integration-tests/src/test/java/org/jboss/resteasy/test/client/InContainerClientBenchTest.java create mode 100644 testsuite/integration-tests/src/test/java/org/jboss/resteasy/test/client/resource/InContainerClientResource.java diff --git a/resteasy-client/src/main/java/org/jboss/resteasy/client/jaxrs/internal/ClientConfiguration.java b/resteasy-client/src/main/java/org/jboss/resteasy/client/jaxrs/internal/ClientConfiguration.java index 3c8a0f86c93..ee7f0d521df 100755 --- a/resteasy-client/src/main/java/org/jboss/resteasy/client/jaxrs/internal/ClientConfiguration.java +++ b/resteasy-client/src/main/java/org/jboss/resteasy/client/jaxrs/internal/ClientConfiguration.java @@ -57,7 +57,10 @@ public ClientConfiguration(final ClientConfiguration parent) public void setProperties(Map newProps) { - providerFactory.setProperties(newProps); + if (newProps != null && !newProps.isEmpty()) + { + providerFactory.setProperties(newProps); + } } protected ResteasyProviderFactory getProviderFactory() diff --git a/resteasy-client/src/main/java/org/jboss/resteasy/client/jaxrs/internal/LocalResteasyProviderFactory.java b/resteasy-client/src/main/java/org/jboss/resteasy/client/jaxrs/internal/LocalResteasyProviderFactory.java index 7eff79c3b59..3f357d38139 100644 --- a/resteasy-client/src/main/java/org/jboss/resteasy/client/jaxrs/internal/LocalResteasyProviderFactory.java +++ b/resteasy-client/src/main/java/org/jboss/resteasy/client/jaxrs/internal/LocalResteasyProviderFactory.java @@ -2,7 +2,9 @@ import javax.ws.rs.RuntimeType; -import org.jboss.resteasy.core.ResteasyProviderFactoryImpl; +import org.jboss.resteasy.core.providerfactory.ClientHelper; +import org.jboss.resteasy.core.providerfactory.NOOPServerHelper; +import org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl; import org.jboss.resteasy.spi.ResteasyProviderFactory; /** @@ -26,4 +28,11 @@ public RuntimeType getRuntimeType() { return RuntimeType.CLIENT; } + + @Override + protected void initializeUtils() + { + clientHelper = new ClientHelper(this); + serverHelper = NOOPServerHelper.INSTANCE; + } } diff --git a/resteasy-client/src/main/java/org/jboss/resteasy/client/jaxrs/internal/ResteasyClientBuilderImpl.java b/resteasy-client/src/main/java/org/jboss/resteasy/client/jaxrs/internal/ResteasyClientBuilderImpl.java index 74b5c319b2d..948ccad5ecb 100755 --- a/resteasy-client/src/main/java/org/jboss/resteasy/client/jaxrs/internal/ResteasyClientBuilderImpl.java +++ b/resteasy-client/src/main/java/org/jboss/resteasy/client/jaxrs/internal/ResteasyClientBuilderImpl.java @@ -9,12 +9,13 @@ import org.jboss.resteasy.client.jaxrs.engines.ClientHttpEngineBuilder43; import org.jboss.resteasy.client.jaxrs.i18n.LogMessages; import org.jboss.resteasy.client.jaxrs.i18n.Messages; -import org.jboss.resteasy.core.ResteasyProviderFactoryImpl; +import org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl; import org.jboss.resteasy.plugins.providers.RegisterBuiltin; import org.jboss.resteasy.spi.ResteasyProviderFactory; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; +import javax.ws.rs.RuntimeType; import javax.ws.rs.core.Configuration; import java.security.KeyStore; @@ -316,8 +317,7 @@ public ResteasyProviderFactory getProviderFactory() if (providerFactory == null) { // create a new one - providerFactory = new LocalResteasyProviderFactory(ResteasyProviderFactory.newInstance()); - RegisterBuiltin.register(providerFactory); + providerFactory = new LocalResteasyProviderFactory(RegisterBuiltin.getClientInitializedResteasyProviderFactory(Thread.currentThread().getContextClassLoader())); if (ResteasyProviderFactory.peekInstance() != null) { @@ -451,7 +451,13 @@ public ResteasyClientBuilderImpl register(Object component, Map, Intege @Override public ResteasyClientBuilderImpl withConfig(Configuration config) { - providerFactory = new LocalResteasyProviderFactory(new ResteasyProviderFactoryImpl()); + providerFactory = new ResteasyProviderFactoryImpl() { + @Override + public RuntimeType getRuntimeType() + { + return RuntimeType.CLIENT; + } + }; providerFactory.setProperties(config.getProperties()); for (Class clazz : config.getClasses()) { diff --git a/resteasy-core-spi/src/main/java/org/jboss/resteasy/spi/ResteasyProviderFactory.java b/resteasy-core-spi/src/main/java/org/jboss/resteasy/spi/ResteasyProviderFactory.java index 59d17cc22bf..0021d5cf881 100755 --- a/resteasy-core-spi/src/main/java/org/jboss/resteasy/spi/ResteasyProviderFactory.java +++ b/resteasy-core-spi/src/main/java/org/jboss/resteasy/spi/ResteasyProviderFactory.java @@ -133,9 +133,9 @@ public static ResteasyProviderFactory newInstance() try { return (ResteasyProviderFactory) Thread.currentThread().getContextClassLoader() - .loadClass("org.jboss.resteasy.core.ResteasyProviderFactoryImpl").newInstance(); + .loadClass("org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl").getDeclaredConstructor().newInstance(); } - catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) + catch (Exception e) { throw new RuntimeException(e); } diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/core/ExceptionHandler.java b/resteasy-core/src/main/java/org/jboss/resteasy/core/ExceptionHandler.java index 1bf0c3df1ac..1f7b90c43b8 100755 --- a/resteasy-core/src/main/java/org/jboss/resteasy/core/ExceptionHandler.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/core/ExceptionHandler.java @@ -1,5 +1,6 @@ package org.jboss.resteasy.core; +import org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl; import org.jboss.resteasy.resteasy_jaxrs.i18n.LogMessages; import org.jboss.resteasy.spi.ApplicationException; import org.jboss.resteasy.spi.Failure; @@ -55,7 +56,7 @@ protected Response executeExactExceptionMapper(Throwable exception, RESTEasyTrac if (logger == null) logger = RESTEasyTracingLogger.empty(); - ExceptionMapper mapper = providerFactory.getExceptionMappers().get(exception.getClass()); + ExceptionMapper mapper = providerFactory.getExceptionMapperForClass(exception.getClass()); if (mapper == null) return null; mapperExecuted = true; long timestamp = logger.timestamp("EXCEPTION_MAPPING"); @@ -75,7 +76,7 @@ protected Response executeExceptionMapperForClass(Throwable exception, Class cla { if (logger == null) logger = RESTEasyTracingLogger.empty(); - ExceptionMapper mapper = providerFactory.getExceptionMappers().get(clazz); + ExceptionMapper mapper = providerFactory.getExceptionMapperForClass(clazz); if (mapper == null) return null; mapperExecuted = true; long timestamp = logger.timestamp("EXCEPTION_MAPPING"); @@ -123,7 +124,7 @@ protected Response executeExceptionMapper(Throwable exception, RESTEasyTracingLo Class causeClass = exception.getClass(); while (mapper == null) { if (causeClass == null) break; - mapper = providerFactory.getExceptionMappers().get(causeClass); + mapper = providerFactory.getExceptionMapperForClass(causeClass); if (mapper == null) causeClass = causeClass.getSuperclass(); } diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/core/InjectorFactoryImpl.java b/resteasy-core/src/main/java/org/jboss/resteasy/core/InjectorFactoryImpl.java index c8e8b0cb717..8ba3f982bc3 100644 --- a/resteasy-core/src/main/java/org/jboss/resteasy/core/InjectorFactoryImpl.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/core/InjectorFactoryImpl.java @@ -42,6 +42,8 @@ @SuppressWarnings({"unchecked", "rawtypes"}) public class InjectorFactoryImpl implements InjectorFactory { + public static final InjectorFactoryImpl INSTANCE = new InjectorFactoryImpl(); + @Override public ConstructorInjector createConstructor(Constructor constructor, ResteasyProviderFactory providerFactory) { diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/core/MediaTypeMap.java b/resteasy-core/src/main/java/org/jboss/resteasy/core/MediaTypeMap.java index 45fc513af6e..69486a242ac 100755 --- a/resteasy-core/src/main/java/org/jboss/resteasy/core/MediaTypeMap.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/core/MediaTypeMap.java @@ -115,14 +115,14 @@ public int compareTo(Entry entry) } } - private static Pattern COMPOSITE_PATTERN = Pattern.compile("([^\\+]+)\\+(.+)"); + private static final Pattern COMPOSITE_PATTERN = Pattern.compile("([^\\+]+)\\+(.+)"); // Composite subtypes are of the pattern *+subtype i.e. *+xml, *+json - public static Pattern COMPOSITE_SUBTYPE_WILDCARD_PATTERN = Pattern.compile("\\*\\+(.+)"); + public static final Pattern COMPOSITE_SUBTYPE_WILDCARD_PATTERN = Pattern.compile("\\*\\+(.+)"); // This composite is subtype+* i.e. atom+* rss+* - public static Pattern WILD_SUBTYPE_COMPOSITE_PATTERN = Pattern.compile("([^\\+]+)\\+\\*"); + public static final Pattern WILD_SUBTYPE_COMPOSITE_PATTERN = Pattern.compile("([^\\+]+)\\+\\*"); private static class SubtypeMap { @@ -252,14 +252,7 @@ public MediaTypeMap clone() return clone; } - public Map> getClassCache() - { - return classCache; - } - - - - public static class CachedMediaTypeAndClass + private static class CachedMediaTypeAndClass { // we need a weak reference because of possible hot deployment // Although, these reference should get cleared up with any add() invocation diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/core/ResourceMethodInvoker.java b/resteasy-core/src/main/java/org/jboss/resteasy/core/ResourceMethodInvoker.java index c807d4c1afe..18a5eb56a64 100755 --- a/resteasy-core/src/main/java/org/jboss/resteasy/core/ResourceMethodInvoker.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/core/ResourceMethodInvoker.java @@ -2,6 +2,9 @@ import org.jboss.resteasy.annotations.Stream; import org.jboss.resteasy.core.interception.jaxrs.PostMatchContainerRequestContext; +import org.jboss.resteasy.core.providerfactory.NOOPClientHelper; +import org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl; +import org.jboss.resteasy.core.providerfactory.ServerHelper; import org.jboss.resteasy.core.registry.SegmentNode; import org.jboss.resteasy.plugins.server.resourcefactory.SingletonResource; import org.jboss.resteasy.resteasy_jaxrs.i18n.LogMessages; @@ -108,7 +111,14 @@ public Class getResourceClass() } }; - this.resourceMethodProviderFactory = new ResteasyProviderFactoryImpl(providerFactory); + this.resourceMethodProviderFactory = new ResteasyProviderFactoryImpl(providerFactory) { + @Override + protected void initializeUtils() + { + clientHelper = NOOPClientHelper.INSTANCE; + serverHelper = new ServerHelper(this); + } + }; for (DynamicFeature feature : providerFactory.getServerDynamicFeatures()) { feature.configure(resourceInfo, new DynamicFeatureContextDelegate(resourceMethodProviderFactory)); @@ -224,7 +234,14 @@ public void cleanup() public void registryUpdated(JaxrsInterceptorRegistry registry) { - this.resourceMethodProviderFactory = new ResteasyProviderFactoryImpl(parentProviderFactory); + this.resourceMethodProviderFactory = new ResteasyProviderFactoryImpl(parentProviderFactory) { + @Override + protected void initializeUtils() + { + clientHelper = NOOPClientHelper.INSTANCE; + serverHelper = new ServerHelper(this); + } + }; for (DynamicFeature feature : parentProviderFactory.getServerDynamicFeatures()) { feature.configure(resourceInfo, new FeatureContextDelegate(resourceMethodProviderFactory)); diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/core/ThreadLocalResteasyProviderFactory.java b/resteasy-core/src/main/java/org/jboss/resteasy/core/ThreadLocalResteasyProviderFactory.java index 9addfed0b06..23e79ab0021 100755 --- a/resteasy-core/src/main/java/org/jboss/resteasy/core/ThreadLocalResteasyProviderFactory.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/core/ThreadLocalResteasyProviderFactory.java @@ -29,6 +29,7 @@ import javax.ws.rs.ext.ReaderInterceptor; import javax.ws.rs.ext.WriterInterceptor; +import org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl; import org.jboss.resteasy.resteasy_jaxrs.i18n.LogMessages; import org.jboss.resteasy.spi.AsyncResponseProvider; import org.jboss.resteasy.spi.AsyncStreamProvider; @@ -504,12 +505,6 @@ public ExceptionMapper getExceptionMapper(Class type return getDelegate().getExceptionMapper(type); } - @Override - public Map, ExceptionMapper> getExceptionMappers() - { - return ((ResteasyProviderFactoryImpl)getDelegate()).getExceptionMappers(); - } - @Override public AsyncResponseProvider getAsyncResponseProvider(Class type) { diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/core/interception/jaxrs/ServerReaderInterceptorContext.java b/resteasy-core/src/main/java/org/jboss/resteasy/core/interception/jaxrs/ServerReaderInterceptorContext.java index 14f26bebbb4..cfc6709275f 100755 --- a/resteasy-core/src/main/java/org/jboss/resteasy/core/interception/jaxrs/ServerReaderInterceptorContext.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/core/interception/jaxrs/ServerReaderInterceptorContext.java @@ -1,6 +1,6 @@ package org.jboss.resteasy.core.interception.jaxrs; -import org.jboss.resteasy.core.ResteasyProviderFactoryImpl; +import org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl; import org.jboss.resteasy.resteasy_jaxrs.i18n.Messages; import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.ResteasyProviderFactory; diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/core/interception/jaxrs/ServerWriterInterceptorContext.java b/resteasy-core/src/main/java/org/jboss/resteasy/core/interception/jaxrs/ServerWriterInterceptorContext.java index 7ae3c054213..45fe87f27a5 100755 --- a/resteasy-core/src/main/java/org/jboss/resteasy/core/interception/jaxrs/ServerWriterInterceptorContext.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/core/interception/jaxrs/ServerWriterInterceptorContext.java @@ -1,7 +1,7 @@ package org.jboss.resteasy.core.interception.jaxrs; import org.jboss.resteasy.core.NoMessageBodyWriterFoundFailure; -import org.jboss.resteasy.core.ResteasyProviderFactoryImpl; +import org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl; import org.jboss.resteasy.spi.HttpRequest; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.jboss.resteasy.tracing.RESTEasyTracingLogger; diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/ClientHelper.java b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/ClientHelper.java new file mode 100644 index 00000000000..e0c3e7cfc84 --- /dev/null +++ b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/ClientHelper.java @@ -0,0 +1,530 @@ +package org.jboss.resteasy.core.providerfactory; + +import java.lang.reflect.Type; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; + +import javax.ws.rs.ConstrainedTo; +import javax.ws.rs.Consumes; +import javax.ws.rs.Produces; +import javax.ws.rs.RuntimeType; +import javax.ws.rs.client.ClientRequestFilter; +import javax.ws.rs.client.ClientResponseFilter; +import javax.ws.rs.client.RxInvoker; +import javax.ws.rs.client.RxInvokerProvider; +import javax.ws.rs.container.DynamicFeature; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.ext.MessageBodyReader; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.ReaderInterceptor; +import javax.ws.rs.ext.WriterInterceptor; + +import org.jboss.resteasy.core.MediaTypeMap; +import org.jboss.resteasy.core.interception.jaxrs.ClientRequestFilterRegistryImpl; +import org.jboss.resteasy.core.interception.jaxrs.ClientResponseFilterRegistryImpl; +import org.jboss.resteasy.core.interception.jaxrs.ReaderInterceptorRegistryImpl; +import org.jboss.resteasy.core.interception.jaxrs.WriterInterceptorRegistryImpl; +import org.jboss.resteasy.resteasy_jaxrs.i18n.Messages; +import org.jboss.resteasy.spi.AsyncClientResponseProvider; +import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.jboss.resteasy.spi.interception.JaxrsInterceptorRegistry; +import org.jboss.resteasy.spi.util.Types; + +/** + * + */ +@SuppressWarnings({"rawtypes", "unchecked"}) +public class ClientHelper +{ + private final ResteasyProviderFactoryImpl rpf; + private MediaTypeMap> clientMessageBodyReaders; + private MediaTypeMap> clientMessageBodyWriters; + private JaxrsInterceptorRegistry clientRequestFilterRegistry; + private JaxrsInterceptorRegistry clientResponseFilters; + private JaxrsInterceptorRegistry clientReaderInterceptorRegistry; + private JaxrsInterceptorRegistry clientWriterInterceptorRegistry; + private Set clientDynamicFeatures; + private Map, AsyncClientResponseProvider> asyncClientResponseProviders; + private Map, Class>> reactiveClasses; + + public ClientHelper(final ResteasyProviderFactoryImpl rpf) + { + this.rpf = rpf; + } + + protected void initializeDefault() + { + reactiveClasses = new ConcurrentHashMap<>(); + } + + protected void initialize(ResteasyProviderFactoryImpl parent) + { + clientMessageBodyReaders = parent == null ? new MediaTypeMap<>() : parent.getClientMessageBodyReaders().clone(); + clientMessageBodyWriters = parent == null ? new MediaTypeMap<>() : parent.getClientMessageBodyWriters().clone(); + clientRequestFilterRegistry = parent == null ? new ClientRequestFilterRegistryImpl(rpf) : parent.getClientRequestFilterRegistry().clone(rpf); + clientResponseFilters = parent == null ? new ClientResponseFilterRegistryImpl(rpf) : parent.getClientResponseFilters().clone(rpf); + clientReaderInterceptorRegistry = parent == null ? new ReaderInterceptorRegistryImpl(rpf) : parent.getClientReaderInterceptorRegistry().clone(rpf); + clientWriterInterceptorRegistry = parent == null ? new WriterInterceptorRegistryImpl(rpf) : parent.getClientWriterInterceptorRegistry().clone(rpf); + + clientDynamicFeatures = parent == null ? new CopyOnWriteArraySet<>() : new CopyOnWriteArraySet<>(parent.getClientDynamicFeatures()); + asyncClientResponseProviders = parent == null ? new ConcurrentHashMap<>(1) : new ConcurrentHashMap<>(parent.getAsyncClientResponseProviders()); + reactiveClasses = parent == null ? new ConcurrentHashMap<>(8) : new ConcurrentHashMap<>(parent.clientHelper.reactiveClasses); + } + + protected void initializeClientProviders(ResteasyProviderFactory factory) + { + clientRequestFilterRegistry = factory == null ? new ClientRequestFilterRegistryImpl(rpf) : factory.getClientRequestFilterRegistry().clone(rpf); + clientResponseFilters = factory == null ? new ClientResponseFilterRegistryImpl(rpf) : factory.getClientResponseFilters().clone(rpf); + } + + protected JaxrsInterceptorRegistry getClientReaderInterceptorRegistry(ResteasyProviderFactory parent) + { + if (clientReaderInterceptorRegistry == null && parent != null) + return parent.getClientReaderInterceptorRegistry(); + return clientReaderInterceptorRegistry; + } + + protected JaxrsInterceptorRegistry getClientWriterInterceptorRegistry(ResteasyProviderFactory parent) + { + if (clientWriterInterceptorRegistry == null && parent != null) + return parent.getClientWriterInterceptorRegistry(); + return clientWriterInterceptorRegistry; + } + + protected JaxrsInterceptorRegistry getClientRequestFilterRegistry(ResteasyProviderFactory parent) + { + if (clientRequestFilterRegistry == null && parent != null) + return parent.getClientRequestFilterRegistry(); + return clientRequestFilterRegistry; + } + + protected JaxrsInterceptorRegistry getClientResponseFilters(ResteasyProviderFactory parent) + { + if (clientResponseFilters == null && parent != null) + return parent.getClientResponseFilters(); + return clientResponseFilters; + } + + protected Set getClientDynamicFeatures(ResteasyProviderFactory parent) + { + if (clientDynamicFeatures == null && parent != null) + return parent.getClientDynamicFeatures(); + return clientDynamicFeatures; + } + + protected Map, AsyncClientResponseProvider> getAsyncClientResponseProviders(ResteasyProviderFactory parent) + { + if (asyncClientResponseProviders == null && parent != null) + return parent.getAsyncClientResponseProviders(); + return asyncClientResponseProviders; + } + + protected RxInvokerProvider getRxInvokerProviderFromReactiveClass(Class clazz) + { + Class rxInvokerProviderClass = reactiveClasses.get(clazz); + if (rxInvokerProviderClass != null) + { + return rpf.createProviderInstance(rxInvokerProviderClass); + } + return null; + } + + protected boolean isReactive(Class clazz) + { + return reactiveClasses.keySet().contains(clazz); + } + + protected void processProviderContracts(Class provider, Integer priorityOverride, boolean isBuiltin, + Map, Integer> contracts, Map, Integer> newContracts, ResteasyProviderFactoryImpl parent) + { + if (Utils.isA(provider, MessageBodyReader.class, contracts)) + { + try + { + int priority = Utils.getPriority(priorityOverride, contracts, MessageBodyReader.class, provider); + addMessageBodyReader(Utils.createProviderInstance(rpf, (Class) provider), provider, + priority, isBuiltin, parent); + newContracts.put(MessageBodyReader.class, priority); + } + catch (Exception e) + { + throw new RuntimeException(Messages.MESSAGES.unableToInstantiateMessageBodyReader(), e); + } + } + if (Utils.isA(provider, MessageBodyWriter.class, contracts)) + { + try + { + int priority = Utils.getPriority(priorityOverride, contracts, MessageBodyWriter.class, provider); + addMessageBodyWriter(Utils.createProviderInstance(rpf, (Class) provider), provider, + priority, isBuiltin, parent); + newContracts.put(MessageBodyWriter.class, priority); + } + catch (Exception e) + { + throw new RuntimeException(Messages.MESSAGES.unableToInstantiateMessageBodyWriter(), e); + } + } + if (Utils.isA(provider, ClientRequestFilter.class, contracts)) + { + if (clientRequestFilterRegistry == null) + { + clientRequestFilterRegistry = parent.getClientRequestFilterRegistry().clone(rpf); + } + int priority = Utils.getPriority(priorityOverride, contracts, ClientRequestFilter.class, provider); + clientRequestFilterRegistry.registerClass(provider, priority); + newContracts.put(ClientRequestFilter.class, priority); + } + if (Utils.isA(provider, ClientResponseFilter.class, contracts)) + { + if (clientResponseFilters == null) + { + clientResponseFilters = parent.getClientResponseFilters().clone(rpf); + } + int priority = Utils.getPriority(priorityOverride, contracts, ClientResponseFilter.class, provider); + clientResponseFilters.registerClass(provider, priority); + newContracts.put(ClientResponseFilter.class, priority); + } + if (Utils.isA(provider, ReaderInterceptor.class, contracts)) + { + ConstrainedTo constrainedTo = (ConstrainedTo) provider.getAnnotation(ConstrainedTo.class); + int priority = Utils.getPriority(priorityOverride, contracts, ReaderInterceptor.class, provider); + if (constrainedTo != null && constrainedTo.value() == RuntimeType.CLIENT) + { + if (clientReaderInterceptorRegistry == null) + { + clientReaderInterceptorRegistry = parent.getClientReaderInterceptorRegistry().clone(rpf); + } + clientReaderInterceptorRegistry.registerClass(provider, priority); + } + if (constrainedTo == null) + { + if (clientReaderInterceptorRegistry == null) + { + clientReaderInterceptorRegistry = parent.getClientReaderInterceptorRegistry().clone(rpf); + } + clientReaderInterceptorRegistry.registerClass(provider, priority); + } + newContracts.put(ReaderInterceptor.class, priority); + } + if (Utils.isA(provider, WriterInterceptor.class, contracts)) + { + ConstrainedTo constrainedTo = (ConstrainedTo) provider.getAnnotation(ConstrainedTo.class); + int priority = Utils.getPriority(priorityOverride, contracts, WriterInterceptor.class, provider); + if (constrainedTo != null && constrainedTo.value() == RuntimeType.CLIENT) + { + if (clientWriterInterceptorRegistry == null) + { + clientWriterInterceptorRegistry = parent.getClientWriterInterceptorRegistry().clone(rpf); + } + clientWriterInterceptorRegistry.registerClass(provider, priority); + } + if (constrainedTo == null) + { + if (clientWriterInterceptorRegistry == null) + { + clientWriterInterceptorRegistry = parent.getClientWriterInterceptorRegistry().clone(rpf); + } + clientWriterInterceptorRegistry.registerClass(provider, priority); + } + newContracts.put(WriterInterceptor.class, priority); + } + if (Utils.isA(provider, DynamicFeature.class, contracts)) + { + ConstrainedTo constrainedTo = (ConstrainedTo) provider.getAnnotation(ConstrainedTo.class); + int priority = Utils.getPriority(priorityOverride, contracts, DynamicFeature.class, provider); + if (constrainedTo != null && constrainedTo.value() == RuntimeType.CLIENT) + { + if (clientDynamicFeatures == null) + { + clientDynamicFeatures = new CopyOnWriteArraySet(parent.getClientDynamicFeatures()); + } + clientDynamicFeatures.add((DynamicFeature) rpf.injectedInstance(provider)); + } + if (constrainedTo == null) + { + if (clientDynamicFeatures == null) + { + clientDynamicFeatures = new CopyOnWriteArraySet(parent.getClientDynamicFeatures()); + } + clientDynamicFeatures.add((DynamicFeature) rpf.injectedInstance(provider)); + } + newContracts.put(DynamicFeature.class, priority); + } + if (Utils.isA(provider, AsyncClientResponseProvider.class, contracts)) + { + try + { + addAsyncClientResponseProvider( + rpf.createProviderInstance((Class) provider), provider, parent); + newContracts.put(AsyncClientResponseProvider.class, + Utils.getPriority(priorityOverride, contracts, AsyncClientResponseProvider.class, provider)); + } + catch (Exception e) + { + throw new RuntimeException(Messages.MESSAGES.unableToInstantiateAsyncClientResponseProvider(), e); + } + } + if (Utils.isA(provider, RxInvokerProvider.class, contracts)) + { + int priority = Utils.getPriority(priorityOverride, contracts, RxInvokerProvider.class, provider); + newContracts.put(RxInvokerProvider.class, priority); + Class clazz = Types.getTemplateParameterOfInterface(provider, RxInvokerProvider.class); + clazz = Types.getTemplateParameterOfInterface(clazz, RxInvoker.class); + if (clazz != null) + { + reactiveClasses.put(clazz, provider); + } + } + } + + protected void processProviderInstanceContracts(Object provider, Map, Integer> contracts, + Integer priorityOverride, boolean builtIn, Map, Integer> newContracts, ResteasyProviderFactoryImpl parent) + { + if (Utils.isA(provider, MessageBodyReader.class, contracts)) + { + try + { + int priority = Utils.getPriority(priorityOverride, contracts, MessageBodyReader.class, provider.getClass()); + addMessageBodyReader((MessageBodyReader) provider, provider.getClass(), priority, builtIn, parent); + newContracts.put(MessageBodyReader.class, priority); + } + catch (Exception e) + { + throw new RuntimeException(Messages.MESSAGES.unableToInstantiateMessageBodyReader(), e); + } + } + if (Utils.isA(provider, MessageBodyWriter.class, contracts)) + { + try + { + int priority = Utils.getPriority(priorityOverride, contracts, MessageBodyWriter.class, provider.getClass()); + addMessageBodyWriter((MessageBodyWriter) provider, provider.getClass(), priority, builtIn, parent); + newContracts.put(MessageBodyWriter.class, priority); + } + catch (Exception e) + { + throw new RuntimeException(Messages.MESSAGES.unableToInstantiateMessageBodyWriter(), e); + } + } + if (Utils.isA(provider, ClientRequestFilter.class, contracts)) + { + if (clientRequestFilterRegistry == null) + { + clientRequestFilterRegistry = parent.getClientRequestFilterRegistry().clone(rpf); + } + int priority = Utils.getPriority(priorityOverride, contracts, ClientRequestFilter.class, provider.getClass()); + clientRequestFilterRegistry.registerSingleton((ClientRequestFilter) provider, priority); + newContracts.put(ClientRequestFilter.class, priority); + } + if (Utils.isA(provider, ClientResponseFilter.class, contracts)) + { + if (clientResponseFilters == null) + { + clientResponseFilters = parent.getClientResponseFilters().clone(rpf); + } + int priority = Utils.getPriority(priorityOverride, contracts, ClientResponseFilter.class, provider.getClass()); + clientResponseFilters.registerSingleton((ClientResponseFilter) provider, priority); + newContracts.put(ClientResponseFilter.class, priority); + } + if (Utils.isA(provider, ReaderInterceptor.class, contracts)) + { + ConstrainedTo constrainedTo = (ConstrainedTo) provider.getClass().getAnnotation(ConstrainedTo.class); + int priority = Utils.getPriority(priorityOverride, contracts, ReaderInterceptor.class, provider.getClass()); + if (constrainedTo != null && constrainedTo.value() == RuntimeType.CLIENT) + { + if (clientReaderInterceptorRegistry == null) + { + clientReaderInterceptorRegistry = parent.getClientReaderInterceptorRegistry().clone(rpf); + } + clientReaderInterceptorRegistry.registerSingleton((ReaderInterceptor) provider, priority); + } + if (constrainedTo == null) + { + if (clientReaderInterceptorRegistry == null) + { + clientReaderInterceptorRegistry = parent.getClientReaderInterceptorRegistry().clone(rpf); + } + clientReaderInterceptorRegistry.registerSingleton((ReaderInterceptor) provider, priority); + } + newContracts.put(ReaderInterceptor.class, priority); + } + if (Utils.isA(provider, WriterInterceptor.class, contracts)) + { + ConstrainedTo constrainedTo = (ConstrainedTo) provider.getClass().getAnnotation(ConstrainedTo.class); + int priority = Utils.getPriority(priorityOverride, contracts, WriterInterceptor.class, provider.getClass()); + if (constrainedTo != null && constrainedTo.value() == RuntimeType.CLIENT) + { + if (clientWriterInterceptorRegistry == null) + { + clientWriterInterceptorRegistry = parent.getClientWriterInterceptorRegistry().clone(rpf); + } + clientWriterInterceptorRegistry.registerSingleton((WriterInterceptor) provider, priority); + } + if (constrainedTo == null) + { + if (clientWriterInterceptorRegistry == null) + { + clientWriterInterceptorRegistry = parent.getClientWriterInterceptorRegistry().clone(rpf); + } + clientWriterInterceptorRegistry.registerSingleton((WriterInterceptor) provider, priority); + } + newContracts.put(WriterInterceptor.class, priority); + } + if (Utils.isA(provider, DynamicFeature.class, contracts)) + { + ConstrainedTo constrainedTo = (ConstrainedTo) provider.getClass().getAnnotation(ConstrainedTo.class); + int priority = Utils.getPriority(priorityOverride, contracts, DynamicFeature.class, provider.getClass()); + if (constrainedTo != null && constrainedTo.value() == RuntimeType.CLIENT) + { + if (clientDynamicFeatures == null) + { + clientDynamicFeatures = new CopyOnWriteArraySet(parent.getClientDynamicFeatures()); + } + clientDynamicFeatures.add((DynamicFeature) provider); + } + if (constrainedTo == null) + { + if (clientDynamicFeatures == null) + { + clientDynamicFeatures = new CopyOnWriteArraySet(parent.getClientDynamicFeatures()); + } + clientDynamicFeatures.add((DynamicFeature) provider); + } + newContracts.put(DynamicFeature.class, priority); + } + if (Utils.isA(provider, AsyncClientResponseProvider.class, contracts)) + { + try + { + addAsyncClientResponseProvider((AsyncClientResponseProvider) provider, provider.getClass(), parent); + int priority = Utils.getPriority(priorityOverride, contracts, AsyncClientResponseProvider.class, + provider.getClass()); + newContracts.put(AsyncClientResponseProvider.class, priority); + } + catch (Exception e) + { + throw new RuntimeException(Messages.MESSAGES.unableToInstantiateAsyncClientResponseProvider(), e); + } + } + } + + protected MediaTypeMap> getClientMessageBodyReaders(ResteasyProviderFactoryImpl parent) + { + if (clientMessageBodyReaders == null && parent != null) + return parent.getClientMessageBodyReaders(); + return clientMessageBodyReaders; + } + + protected MediaTypeMap> getClientMessageBodyWriters(ResteasyProviderFactoryImpl parent) + { + if (clientMessageBodyWriters == null && parent != null) + return parent.getClientMessageBodyWriters(); + return clientMessageBodyWriters; + } + + protected void addMessageBodyReader(MessageBodyReader provider, Class providerClass, int priority, + boolean isBuiltin, ResteasyProviderFactoryImpl parent) + { + SortedKey key = new SortedKey(MessageBodyReader.class, provider, + providerClass, priority, isBuiltin); + Utils.injectProperties(rpf, providerClass, provider); + Consumes consumeMime = provider.getClass().getAnnotation(Consumes.class); + RuntimeType type = null; + ConstrainedTo constrainedTo = providerClass.getAnnotation(ConstrainedTo.class); + if (constrainedTo != null) + type = constrainedTo.value(); + + if ((type == null || type == RuntimeType.CLIENT) && clientMessageBodyReaders == null) + { + clientMessageBodyReaders = parent.getClientMessageBodyReaders().clone(); + } + if (consumeMime != null) + { + for (String consume : consumeMime.value()) + { + if (type == null) + { + clientMessageBodyReaders.add(MediaType.valueOf(consume), key); + } + else if (type == RuntimeType.CLIENT) + { + clientMessageBodyReaders.add(MediaType.valueOf(consume), key); + } + } + } + else + { + if (type == null) + { + clientMessageBodyReaders.add(new MediaType("*", "*"), key); + } + else if (type == RuntimeType.CLIENT) + { + clientMessageBodyReaders.add(new MediaType("*", "*"), key); + } + } + } + + protected void addMessageBodyWriter(MessageBodyWriter provider, Class providerClass, int priority, + boolean isBuiltin, ResteasyProviderFactoryImpl parent) + { + Utils.injectProperties(rpf, providerClass, provider); + Produces consumeMime = provider.getClass().getAnnotation(Produces.class); + SortedKey key = new SortedKey(MessageBodyWriter.class, provider, + providerClass, priority, isBuiltin); + RuntimeType type = null; + ConstrainedTo constrainedTo = providerClass.getAnnotation(ConstrainedTo.class); + if (constrainedTo != null) + type = constrainedTo.value(); + + if ((type == null || type == RuntimeType.CLIENT) && clientMessageBodyWriters == null) + { + clientMessageBodyWriters = parent.getClientMessageBodyWriters().clone(); + } + if (consumeMime != null) + { + for (String consume : consumeMime.value()) + { + //logger.info(">>> Adding provider: " + provider.getClass().getName() + " with mime type of: " + mime); + if (type == null) + { + clientMessageBodyWriters.add(MediaType.valueOf(consume), key); + } + else if (type == RuntimeType.CLIENT) + { + clientMessageBodyWriters.add(MediaType.valueOf(consume), key); + } + } + } + else + { + //logger.info(">>> Adding provider: " + provider.getClass().getName() + " with mime type of: default */*"); + if (type == null) + { + clientMessageBodyWriters.add(new MediaType("*", "*"), key); + } + else if (type == RuntimeType.CLIENT) + { + clientMessageBodyWriters.add(new MediaType("*", "*"), key); + } + } + } + + private void addAsyncClientResponseProvider(AsyncClientResponseProvider provider, Class providerClass, ResteasyProviderFactory parent) + { + Type asyncType = Types.getActualTypeArgumentsOfAnInterface(providerClass, AsyncClientResponseProvider.class)[0]; + Utils.injectProperties(rpf, provider.getClass(), provider); + + Class asyncClass = Types.getRawType(asyncType); + if (asyncClientResponseProviders == null) + { + asyncClientResponseProviders = new ConcurrentHashMap, AsyncClientResponseProvider>(); + asyncClientResponseProviders.putAll(parent.getAsyncClientResponseProviders()); + } + asyncClientResponseProviders.put(asyncClass, provider); + } + +} diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/ExtSortedKey.java b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/ExtSortedKey.java new file mode 100644 index 00000000000..52add0299ea --- /dev/null +++ b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/ExtSortedKey.java @@ -0,0 +1,34 @@ +package org.jboss.resteasy.core.providerfactory; + +public final class ExtSortedKey extends SortedKey +{ + public ExtSortedKey(final Class intf, final T reader, final Class readerClass, final int priority, final boolean isBuiltin) + { + super(intf, reader, readerClass, priority, isBuiltin); + } + + public ExtSortedKey(final Class intf, final T reader, final Class readerClass, final boolean isBuiltin) + { + super(intf, reader, readerClass, isBuiltin); + } + + public ExtSortedKey(final Class intf, final T reader, final Class readerClass) + { + super(intf, reader, readerClass); + } + + @Override + public int compareTo(SortedKey tMessageBodyKey) + { + int c = super.compareTo(tMessageBodyKey); + if (c != 0) + { + return c; + } + if (this.getObj() == tMessageBodyKey.getObj()) + { + return 0; + } + return -1; + } +} \ No newline at end of file diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/NOOPClientHelper.java b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/NOOPClientHelper.java new file mode 100644 index 00000000000..f9a75681e66 --- /dev/null +++ b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/NOOPClientHelper.java @@ -0,0 +1,138 @@ +package org.jboss.resteasy.core.providerfactory; + +import java.util.Map; +import java.util.Set; + +import javax.ws.rs.client.ClientRequestFilter; +import javax.ws.rs.client.ClientResponseFilter; +import javax.ws.rs.client.RxInvokerProvider; +import javax.ws.rs.container.DynamicFeature; +import javax.ws.rs.ext.MessageBodyReader; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.ReaderInterceptor; +import javax.ws.rs.ext.WriterInterceptor; + +import org.jboss.resteasy.core.MediaTypeMap; +import org.jboss.resteasy.spi.AsyncClientResponseProvider; +import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.jboss.resteasy.spi.interception.JaxrsInterceptorRegistry; + +/** + * A ClientHelper that does nothing, useful to save memory when creating a ResteasyProviderFactory for server side only + */ +@SuppressWarnings("rawtypes") +public final class NOOPClientHelper extends ClientHelper +{ + public static final NOOPClientHelper INSTANCE = new NOOPClientHelper(null); + + public NOOPClientHelper(final ResteasyProviderFactoryImpl rpf) + { + super(rpf); + } + + @Override + protected void initializeDefault() + { + //NOOP + } + + @Override + protected void initialize(ResteasyProviderFactoryImpl parent) + { + //NOOP + } + + @Override + protected void initializeClientProviders(ResteasyProviderFactory factory) + { + //NOOP + } + + @Override + protected JaxrsInterceptorRegistry getClientReaderInterceptorRegistry(ResteasyProviderFactory parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected JaxrsInterceptorRegistry getClientWriterInterceptorRegistry(ResteasyProviderFactory parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected JaxrsInterceptorRegistry getClientRequestFilterRegistry(ResteasyProviderFactory parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected JaxrsInterceptorRegistry getClientResponseFilters(ResteasyProviderFactory parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected Set getClientDynamicFeatures(ResteasyProviderFactory parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected Map, AsyncClientResponseProvider> getAsyncClientResponseProviders(ResteasyProviderFactory parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected RxInvokerProvider getRxInvokerProviderFromReactiveClass(Class clazz) + { + throw new UnsupportedOperationException(); + } + + @Override + protected boolean isReactive(Class clazz) + { + throw new UnsupportedOperationException(); + } + + @Override + protected void processProviderContracts(Class provider, Integer priorityOverride, boolean isBuiltin, + Map, Integer> contracts, Map, Integer> newContracts, ResteasyProviderFactoryImpl parent) + { + //NOOP + } + + @Override + protected void processProviderInstanceContracts(Object provider, Map, Integer> contracts, + Integer priorityOverride, boolean builtIn, Map, Integer> newContracts, ResteasyProviderFactoryImpl parent) + { + //NOOP + } + + @Override + protected MediaTypeMap> getClientMessageBodyReaders(ResteasyProviderFactoryImpl parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected MediaTypeMap> getClientMessageBodyWriters(ResteasyProviderFactoryImpl parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected void addMessageBodyReader(MessageBodyReader provider, Class providerClass, int priority, + boolean isBuiltin, ResteasyProviderFactoryImpl parent) + { + //NOOP + } + + @Override + protected void addMessageBodyWriter(MessageBodyWriter provider, Class providerClass, int priority, + boolean isBuiltin, ResteasyProviderFactoryImpl parent) + { + //NOOP + } +} diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/NOOPServerHelper.java b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/NOOPServerHelper.java new file mode 100644 index 00000000000..1e280929398 --- /dev/null +++ b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/NOOPServerHelper.java @@ -0,0 +1,120 @@ +package org.jboss.resteasy.core.providerfactory; + +import java.util.Map; +import java.util.Set; + +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.container.DynamicFeature; +import javax.ws.rs.ext.MessageBodyReader; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.ReaderInterceptor; +import javax.ws.rs.ext.WriterInterceptor; + +import org.jboss.resteasy.core.MediaTypeMap; +import org.jboss.resteasy.spi.AsyncResponseProvider; +import org.jboss.resteasy.spi.AsyncStreamProvider; +import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.jboss.resteasy.spi.interception.JaxrsInterceptorRegistry; + +/** + * A ServerHelper that does nothing, useful to save memory when creating a ResteasyProviderFactory for client side only + */ +@SuppressWarnings("rawtypes") +public final class NOOPServerHelper extends ServerHelper +{ + public static final NOOPServerHelper INSTANCE = new NOOPServerHelper(null); + + private NOOPServerHelper(final ResteasyProviderFactoryImpl rpf) + { + super(rpf); + } + + @Override + protected void initialize(ResteasyProviderFactoryImpl parent) + { + //NOOP + } + + @Override + protected JaxrsInterceptorRegistry getServerReaderInterceptorRegistry(ResteasyProviderFactory parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected JaxrsInterceptorRegistry getServerWriterInterceptorRegistry(ResteasyProviderFactory parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected JaxrsInterceptorRegistry getContainerRequestFilterRegistry(ResteasyProviderFactory parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected JaxrsInterceptorRegistry getContainerResponseFilterRegistry(ResteasyProviderFactory parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected Set getServerDynamicFeatures(ResteasyProviderFactory parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected Map, AsyncResponseProvider> getAsyncResponseProviders(ResteasyProviderFactory parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected Map, AsyncStreamProvider> getAsyncStreamProviders(ResteasyProviderFactory parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected void processProviderContracts(Class provider, Integer priorityOverride, boolean isBuiltin, + Map, Integer> contracts, Map, Integer> newContracts, ResteasyProviderFactoryImpl parent) + { + //NOOP + } + + @Override + protected void processProviderInstanceContracts(Object provider, Map, Integer> contracts, + Integer priorityOverride, boolean builtIn, Map, Integer> newContracts, ResteasyProviderFactoryImpl parent) + { + //NOOP + } + + @Override + protected MediaTypeMap> getServerMessageBodyReaders(ResteasyProviderFactoryImpl parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected MediaTypeMap> getServerMessageBodyWriters(ResteasyProviderFactoryImpl parent) + { + throw new UnsupportedOperationException(); + } + + @Override + protected void addMessageBodyReader(MessageBodyReader provider, Class providerClass, int priority, + boolean isBuiltin, ResteasyProviderFactoryImpl parent) + { + //NOOP + } + + @Override + protected void addMessageBodyWriter(MessageBodyWriter provider, Class providerClass, int priority, + boolean isBuiltin, ResteasyProviderFactoryImpl parent) + { + //NOOP + } +} diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/core/ResteasyProviderFactoryImpl.java b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/ResteasyProviderFactoryImpl.java similarity index 52% rename from resteasy-core/src/main/java/org/jboss/resteasy/core/ResteasyProviderFactoryImpl.java rename to resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/ResteasyProviderFactoryImpl.java index 1d7f284836e..835cc67af0b 100644 --- a/resteasy-core/src/main/java/org/jboss/resteasy/core/ResteasyProviderFactoryImpl.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/ResteasyProviderFactoryImpl.java @@ -1,52 +1,28 @@ -package org.jboss.resteasy.core; - -import org.jboss.resteasy.core.interception.jaxrs.ClientRequestFilterRegistryImpl; -import org.jboss.resteasy.core.interception.jaxrs.ClientResponseFilterRegistryImpl; -import org.jboss.resteasy.core.interception.jaxrs.ContainerRequestFilterRegistryImpl; -import org.jboss.resteasy.core.interception.jaxrs.ContainerResponseFilterRegistryImpl; -import org.jboss.resteasy.core.interception.jaxrs.ReaderInterceptorRegistryImpl; -import org.jboss.resteasy.core.interception.jaxrs.WriterInterceptorRegistryImpl; -import org.jboss.resteasy.plugins.delegates.CacheControlDelegate; -import org.jboss.resteasy.plugins.delegates.CookieHeaderDelegate; -import org.jboss.resteasy.plugins.delegates.DateDelegate; -import org.jboss.resteasy.plugins.delegates.EntityTagDelegate; -import org.jboss.resteasy.plugins.delegates.LinkDelegate; -import org.jboss.resteasy.plugins.delegates.LinkHeaderDelegate; -import org.jboss.resteasy.plugins.delegates.LocaleDelegate; -import org.jboss.resteasy.plugins.delegates.MediaTypeHeaderDelegate; -import org.jboss.resteasy.plugins.delegates.NewCookieHeaderDelegate; -import org.jboss.resteasy.plugins.delegates.UriHeaderDelegate; -import org.jboss.resteasy.plugins.providers.RegisterBuiltin; -import org.jboss.resteasy.resteasy_jaxrs.i18n.LogMessages; -import org.jboss.resteasy.resteasy_jaxrs.i18n.Messages; -import org.jboss.resteasy.specimpl.LinkBuilderImpl; -import org.jboss.resteasy.specimpl.ResponseBuilderImpl; -import org.jboss.resteasy.specimpl.ResteasyUriBuilderImpl; -import org.jboss.resteasy.specimpl.VariantListBuilderImpl; -import org.jboss.resteasy.spi.AsyncClientResponseProvider; -import org.jboss.resteasy.spi.AsyncResponseProvider; -import org.jboss.resteasy.spi.AsyncStreamProvider; -import org.jboss.resteasy.spi.ConstructorInjector; -import org.jboss.resteasy.spi.ContextInjector; -import org.jboss.resteasy.spi.HeaderValueProcessor; -import org.jboss.resteasy.spi.HttpRequest; -import org.jboss.resteasy.spi.HttpResponse; -import org.jboss.resteasy.spi.InjectorFactory; -import org.jboss.resteasy.spi.LinkHeader; -import org.jboss.resteasy.spi.PropertyInjector; -import org.jboss.resteasy.spi.ResteasyProviderFactory; -import org.jboss.resteasy.spi.StringParameterUnmarshaller; -import org.jboss.resteasy.spi.interception.JaxrsInterceptorRegistry; -import org.jboss.resteasy.spi.metadata.ResourceBuilder; -import org.jboss.resteasy.spi.metadata.ResourceClassProcessor; -import org.jboss.resteasy.spi.util.PickConstructor; -import org.jboss.resteasy.spi.util.Types; -import org.jboss.resteasy.tracing.RESTEasyTracingLogger; -import org.jboss.resteasy.util.FeatureContextDelegate; +package org.jboss.resteasy.core.providerfactory; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Constructor; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.net.URI; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; -import javax.annotation.Priority; import javax.ws.rs.ConstrainedTo; -import javax.ws.rs.Consumes; import javax.ws.rs.Priorities; import javax.ws.rs.Produces; import javax.ws.rs.RuntimeType; @@ -81,28 +57,42 @@ import javax.ws.rs.ext.RuntimeDelegate; import javax.ws.rs.ext.WriterInterceptor; -import java.lang.annotation.Annotation; -import java.lang.reflect.Constructor; -import java.lang.reflect.ParameterizedType; -import java.lang.reflect.Type; -import java.net.URI; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Map.Entry; - -import java.util.Objects; -import java.util.Set; -import java.util.TreeSet; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.CopyOnWriteArraySet; +import org.jboss.resteasy.core.InjectorFactoryImpl; +import org.jboss.resteasy.core.MediaTypeMap; +import org.jboss.resteasy.core.ResteasyContext; +import org.jboss.resteasy.plugins.delegates.CacheControlDelegate; +import org.jboss.resteasy.plugins.delegates.CookieHeaderDelegate; +import org.jboss.resteasy.plugins.delegates.DateDelegate; +import org.jboss.resteasy.plugins.delegates.EntityTagDelegate; +import org.jboss.resteasy.plugins.delegates.LinkDelegate; +import org.jboss.resteasy.plugins.delegates.LinkHeaderDelegate; +import org.jboss.resteasy.plugins.delegates.LocaleDelegate; +import org.jboss.resteasy.plugins.delegates.MediaTypeHeaderDelegate; +import org.jboss.resteasy.plugins.delegates.NewCookieHeaderDelegate; +import org.jboss.resteasy.plugins.delegates.UriHeaderDelegate; +import org.jboss.resteasy.plugins.providers.RegisterBuiltin; +import org.jboss.resteasy.resteasy_jaxrs.i18n.LogMessages; +import org.jboss.resteasy.resteasy_jaxrs.i18n.Messages; +import org.jboss.resteasy.spi.AsyncClientResponseProvider; +import org.jboss.resteasy.spi.AsyncResponseProvider; +import org.jboss.resteasy.spi.AsyncStreamProvider; +import org.jboss.resteasy.spi.ConstructorInjector; +import org.jboss.resteasy.spi.ContextInjector; +import org.jboss.resteasy.spi.HeaderValueProcessor; +import org.jboss.resteasy.spi.HttpRequest; +import org.jboss.resteasy.spi.HttpResponse; +import org.jboss.resteasy.spi.InjectorFactory; +import org.jboss.resteasy.spi.LinkHeader; +import org.jboss.resteasy.spi.PropertyInjector; +import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.jboss.resteasy.spi.StringParameterUnmarshaller; +import org.jboss.resteasy.spi.interception.JaxrsInterceptorRegistry; +import org.jboss.resteasy.spi.metadata.ResourceBuilder; +import org.jboss.resteasy.spi.metadata.ResourceClassProcessor; +import org.jboss.resteasy.spi.util.PickConstructor; +import org.jboss.resteasy.spi.util.Types; +import org.jboss.resteasy.tracing.RESTEasyTracingLogger; +import org.jboss.resteasy.util.FeatureContextDelegate; /** * @author Bill Burke @@ -111,149 +101,29 @@ @SuppressWarnings({"unchecked", "rawtypes"}) public class ResteasyProviderFactoryImpl extends ResteasyProviderFactory implements Providers, HeaderValueProcessor, Configurable, Configuration { - /** - * Allow us to sort message body implementations that are more specific for their types - * i.e. MessageBodyWriter<Object> is less specific than MessageBodyWriter<String>. - *

- * This helps out a lot when the desired media type is a wildcard and to weed out all the possible - * default mappings. - */ - private static class SortedKey implements Comparable>, MediaTypeMap.Typed - { - private final T obj; - private final boolean isBuiltin; - private final Class template; - private final int priority; - - protected SortedKey(final Class intf, final T reader, final Class readerClass, final int priority, final boolean isBuiltin) - { - this.obj = reader; - // check the super class for the generic type 1st - Class t = Types.getTemplateParameterOfInterface(readerClass, intf); - template = (t != null) ? t : Object.class; - this.priority = priority; - this.isBuiltin = isBuiltin; - } - - protected SortedKey(final Class intf, final T reader, final Class readerClass, final boolean isBuiltin) - { - this(intf, reader, readerClass, Priorities.USER, isBuiltin); - } - - protected SortedKey(final Class intf, final T reader, final Class readerClass) - { - this(intf, reader, readerClass, Priorities.USER, false); - } - - public int compareTo(SortedKey tMessageBodyKey) - { - // Sort user provider before builtins - if (this == tMessageBodyKey) - return 0; - if (isBuiltin == tMessageBodyKey.isBuiltin) - { - if (this.priority < tMessageBodyKey.priority) - { - return -1; - } - if (this.priority == tMessageBodyKey.priority) - { - return 0; - } - if (this.priority > tMessageBodyKey.priority) - { - return 1; - } - } - if (isBuiltin) - return 1; - else - return -1; - } - - public Class getType() - { - return template; - } - - public T getObj() - { - return obj; - } - } - - private static class ExtSortedKey extends SortedKey - { - protected ExtSortedKey(final Class intf, final T reader, final Class readerClass, final int priority, final boolean isBuiltin) - { - super(intf, reader, readerClass, priority, isBuiltin); - } - - protected ExtSortedKey(final Class intf, final T reader, final Class readerClass, final boolean isBuiltin) - { - super(intf, reader, readerClass, isBuiltin); - } - - protected ExtSortedKey(final Class intf, final T reader, final Class readerClass) - { - super(intf, reader, readerClass); - } - - @Override - public int compareTo(SortedKey tMessageBodyKey) - { - int c = super.compareTo(tMessageBodyKey); - if (c != 0) - { - return c; - } - if (this.getObj() == tMessageBodyKey.getObj()) - { - return 0; - } - return -1; - } - } - - private MediaTypeMap> serverMessageBodyReaders; - private MediaTypeMap> serverMessageBodyWriters; - private MediaTypeMap> clientMessageBodyReaders; - private MediaTypeMap> clientMessageBodyWriters; + protected ClientHelper clientHelper; + protected ServerHelper serverHelper; + private Map, HeaderDelegate> headerDelegates; private Map, SortedKey> sortedExceptionMappers; - private Map, ExceptionMapper> exceptionMappers; - private Map, AsyncResponseProvider> asyncResponseProviders; - private Map, AsyncClientResponseProvider> asyncClientResponseProviders; - private Map, AsyncStreamProvider> asyncStreamProviders; private Map, MediaTypeMap>> contextResolvers; private Map contextInjectors; private Map asyncContextInjectors; private Set> sortedParamConverterProviders; private Map, Class> stringParameterUnmarshallers; - protected Map, Map, Integer>> classContracts; - private Map, HeaderDelegate> headerDelegates; - private JaxrsInterceptorRegistry serverReaderInterceptorRegistry; - private JaxrsInterceptorRegistry serverWriterInterceptorRegistry; - private JaxrsInterceptorRegistry containerRequestFilterRegistry; - private JaxrsInterceptorRegistry containerResponseFilterRegistry; - private JaxrsInterceptorRegistry clientRequestFilterRegistry; - private JaxrsInterceptorRegistry clientResponseFilters; - private JaxrsInterceptorRegistry clientReaderInterceptorRegistry; - private JaxrsInterceptorRegistry clientWriterInterceptorRegistry; + private Map, Map, Integer>> classContracts; private boolean builtinsRegistered = false; private boolean registerBuiltins = true; private InjectorFactory injectorFactory; private ResteasyProviderFactoryImpl parent; - private Set serverDynamicFeatures; - private Set clientDynamicFeatures; private Map properties; - private Map, Class>> reactiveClasses; private ResourceBuilder resourceBuilder; - protected Set enabledFeatures; - protected Set> providerClasses; - protected Set providerInstances; + private Set enabledFeatures; + private Set> providerClasses; + private Set providerInstances; public ResteasyProviderFactoryImpl() { + initializeUtils(); // NOTE!!! It is important to put all initialization into initialize() as ThreadLocalResteasyProviderFactory // subclasses and delegates to this class. initialize(); @@ -278,6 +148,7 @@ public ResteasyProviderFactoryImpl(final ResteasyProviderFactory parent) */ public ResteasyProviderFactoryImpl(final ResteasyProviderFactory parent, final boolean local) { + initializeUtils(); if (local || parent == null) { // Parent MUST not be referenced after current object is created @@ -287,12 +158,12 @@ public ResteasyProviderFactoryImpl(final ResteasyProviderFactory parent, final b else { this.parent = (ResteasyProviderFactoryImpl) parent; + clientHelper.initializeDefault(); providerClasses = new CopyOnWriteArraySet<>(); providerInstances = new CopyOnWriteArraySet<>(); properties = new ConcurrentHashMap<>(); properties.putAll(parent.getProperties()); enabledFeatures = new CopyOnWriteArraySet<>(); - reactiveClasses = new ConcurrentHashMap<>(); resourceBuilder = new ResourceBuilder(); } } @@ -307,23 +178,20 @@ protected void initialize() initialize(null); } + protected void initializeUtils() + { + clientHelper = new ClientHelper(this); + serverHelper = new ServerHelper(this); + } + protected void initialize(ResteasyProviderFactoryImpl parent) { - serverDynamicFeatures = parent == null ? new CopyOnWriteArraySet<>() : new CopyOnWriteArraySet<>(parent.getServerDynamicFeatures()); - clientDynamicFeatures = parent == null ? new CopyOnWriteArraySet<>() : new CopyOnWriteArraySet<>(parent.getClientDynamicFeatures()); enabledFeatures = parent == null ? new CopyOnWriteArraySet<>() : new CopyOnWriteArraySet<>(parent.getEnabledFeatures()); properties = parent == null ? new ConcurrentHashMap<>() : new ConcurrentHashMap<>(parent.getProperties()); providerClasses = parent == null ? new CopyOnWriteArraySet<>() : new CopyOnWriteArraySet<>(parent.getProviderClasses()); providerInstances = parent == null ? new CopyOnWriteArraySet<>() : new CopyOnWriteArraySet<>(parent.getProviderInstances()); classContracts = parent == null ? new ConcurrentHashMap<>() : new ConcurrentHashMap<>(parent.getClassContracts()); - serverMessageBodyReaders = parent == null ? new MediaTypeMap<>() : parent.getServerMessageBodyReaders().clone(); - serverMessageBodyWriters = parent == null ? new MediaTypeMap<>() : parent.getServerMessageBodyWriters().clone(); - clientMessageBodyReaders = parent == null ? new MediaTypeMap<>() : parent.getClientMessageBodyReaders().clone(); - clientMessageBodyWriters = parent == null ? new MediaTypeMap<>() : parent.getClientMessageBodyWriters().clone(); - sortedExceptionMappers = parent == null ? new ConcurrentHashMap<>() : new ConcurrentHashMap<>(parent.getSortedExceptionMappers()); - asyncResponseProviders = parent == null ? new ConcurrentHashMap<>() : new ConcurrentHashMap<>(parent.getAsyncResponseProviders()); - asyncClientResponseProviders = parent == null ? new ConcurrentHashMap<>() : new ConcurrentHashMap<>(parent.getAsyncClientResponseProviders()); - asyncStreamProviders = parent == null ? new ConcurrentHashMap<>() : new ConcurrentHashMap<>(parent.getAsyncStreamProviders()); + sortedExceptionMappers = parent == null ? new ConcurrentHashMap<>(4) : new ConcurrentHashMap<>(parent.getSortedExceptionMappers()); contextResolvers = new ConcurrentHashMap<>(); if (parent != null) { @@ -332,101 +200,62 @@ protected void initialize(ResteasyProviderFactoryImpl parent) contextResolvers.put(entry.getKey(), entry.getValue().clone()); } } - contextInjectors = parent == null ? new ConcurrentHashMap<>() : new ConcurrentHashMap<>(parent.getContextInjectors()); - asyncContextInjectors = parent == null ? new ConcurrentHashMap<>() : new ConcurrentHashMap<>(parent.getAsyncContextInjectors()); + contextInjectors = parent == null ? new ConcurrentHashMap<>(2) : new ConcurrentHashMap<>(parent.getContextInjectors()); + asyncContextInjectors = parent == null ? new ConcurrentHashMap<>(2) : new ConcurrentHashMap<>(parent.getAsyncContextInjectors()); sortedParamConverterProviders = Collections.synchronizedSortedSet(parent == null ? new TreeSet<>() : new TreeSet<>(parent.getSortedParamConverterProviders())); - stringParameterUnmarshallers = parent == null ? new ConcurrentHashMap<>() : new ConcurrentHashMap<>(parent.getStringParameterUnmarshallers()); - reactiveClasses = parent == null ? new ConcurrentHashMap<>() : new ConcurrentHashMap<>(parent.reactiveClasses); - headerDelegates = parent == null ? new ConcurrentHashMap<>() : new ConcurrentHashMap<>(parent.getHeaderDelegates()); - addHeaderDelegateIfAbsent(MediaType.class, new MediaTypeHeaderDelegate()); - addHeaderDelegateIfAbsent(NewCookie.class, new NewCookieHeaderDelegate()); - addHeaderDelegateIfAbsent(Cookie.class, new CookieHeaderDelegate()); - addHeaderDelegateIfAbsent(URI.class, new UriHeaderDelegate()); - addHeaderDelegateIfAbsent(EntityTag.class, new EntityTagDelegate()); - addHeaderDelegateIfAbsent(CacheControl.class, new CacheControlDelegate()); - addHeaderDelegateIfAbsent(Locale.class, new LocaleDelegate()); - addHeaderDelegateIfAbsent(LinkHeader.class, new LinkHeaderDelegate()); - addHeaderDelegateIfAbsent(javax.ws.rs.core.Link.class, new LinkDelegate()); - addHeaderDelegateIfAbsent(Date.class, new DateDelegate()); + stringParameterUnmarshallers = parent == null ? new ConcurrentHashMap<>(2) : new ConcurrentHashMap<>(parent.getStringParameterUnmarshallers()); resourceBuilder = new ResourceBuilder(); - initializeRegistriesAndFilters(parent); + headerDelegates = parent == null ? new ConcurrentHashMap<>() : new ConcurrentHashMap<>(parent.getHeaderDelegates()); + addHeaderDelegateIfAbsent(MediaType.class, MediaTypeHeaderDelegate.INSTANCE); + addHeaderDelegateIfAbsent(NewCookie.class, NewCookieHeaderDelegate.INSTANCE); + addHeaderDelegateIfAbsent(Cookie.class, CookieHeaderDelegate.INSTANCE); + addHeaderDelegateIfAbsent(URI.class, UriHeaderDelegate.INSTANCE); + addHeaderDelegateIfAbsent(EntityTag.class, EntityTagDelegate.INSTANCE); + addHeaderDelegateIfAbsent(CacheControl.class, CacheControlDelegate.INSTANCE); + addHeaderDelegateIfAbsent(Locale.class, LocaleDelegate.INSTANCE); + addHeaderDelegateIfAbsent(LinkHeader.class, LinkHeaderDelegate.INSTANCE); + addHeaderDelegateIfAbsent(javax.ws.rs.core.Link.class, LinkDelegate.INSTANCE); + addHeaderDelegateIfAbsent(Date.class, DateDelegate.INSTANCE); + + serverHelper.initialize(parent); + clientHelper.initialize(parent); builtinsRegistered = false; registerBuiltins = true; - injectorFactory = parent == null ? new InjectorFactoryImpl() : parent.getInjectorFactory(); - } - - private void initializeRegistriesAndFilters(ResteasyProviderFactory parent) - { - serverReaderInterceptorRegistry = parent == null ? new ReaderInterceptorRegistryImpl(this) : parent.getServerReaderInterceptorRegistry().clone(this); - serverWriterInterceptorRegistry = parent == null ? new WriterInterceptorRegistryImpl(this) : parent.getServerWriterInterceptorRegistry().clone(this); - containerRequestFilterRegistry = parent == null ? new ContainerRequestFilterRegistryImpl(this) : parent.getContainerRequestFilterRegistry().clone(this); - containerResponseFilterRegistry = parent == null ? new ContainerResponseFilterRegistryImpl(this) : parent.getContainerResponseFilterRegistry().clone(this); - - clientRequestFilterRegistry = parent == null ? new ClientRequestFilterRegistryImpl(this) : parent.getClientRequestFilterRegistry().clone(this); - clientResponseFilters = parent == null ? new ClientResponseFilterRegistryImpl(this) : parent.getClientResponseFilters().clone(this); - clientReaderInterceptorRegistry = parent == null ? new ReaderInterceptorRegistryImpl(this) : parent.getClientReaderInterceptorRegistry().clone(this); - clientWriterInterceptorRegistry = parent == null ? new WriterInterceptorRegistryImpl(this) : parent.getClientWriterInterceptorRegistry().clone(this); + injectorFactory = parent == null ? InjectorFactoryImpl.INSTANCE : parent.getInjectorFactory(); } public Set getServerDynamicFeatures() { - if (serverDynamicFeatures == null && parent != null) - return parent.getServerDynamicFeatures(); - return serverDynamicFeatures; + return serverHelper.getServerDynamicFeatures(parent); } public Set getClientDynamicFeatures() { - if (clientDynamicFeatures == null && parent != null) - return parent.getClientDynamicFeatures(); - return clientDynamicFeatures; + return clientHelper.getClientDynamicFeatures(parent); } - private MediaTypeMap> getServerMessageBodyReaders() + protected MediaTypeMap> getServerMessageBodyReaders() { - if (serverMessageBodyReaders == null && parent != null) - return parent.getServerMessageBodyReaders(); - return serverMessageBodyReaders; + return serverHelper.getServerMessageBodyReaders(parent); } - private MediaTypeMap> getServerMessageBodyWriters() + protected MediaTypeMap> getServerMessageBodyWriters() { - if (serverMessageBodyWriters == null && parent != null) - return parent.getServerMessageBodyWriters(); - return serverMessageBodyWriters; + return serverHelper.getServerMessageBodyWriters(parent); } - private MediaTypeMap> getClientMessageBodyReaders() + protected MediaTypeMap> getClientMessageBodyReaders() { - if (clientMessageBodyReaders == null && parent != null) - return parent.getClientMessageBodyReaders(); - return clientMessageBodyReaders; + return clientHelper.getClientMessageBodyReaders(parent); } - private MediaTypeMap> getClientMessageBodyWriters() + protected MediaTypeMap> getClientMessageBodyWriters() { - if (clientMessageBodyWriters == null && parent != null) - return parent.getClientMessageBodyWriters(); - return clientMessageBodyWriters; - } - - public Map, ExceptionMapper> getExceptionMappers() - { - if (exceptionMappers != null) - { - return exceptionMappers; - } - Map, ExceptionMapper> map = new ConcurrentHashMap, ExceptionMapper>(); - for (Entry, SortedKey> entry : getSortedExceptionMappers().entrySet()) - { - map.put(entry.getKey(), entry.getValue().getObj()); - } - exceptionMappers = map; - return map; + return clientHelper.getClientMessageBodyWriters(parent); } private Map, SortedKey> getSortedExceptionMappers() @@ -438,23 +267,17 @@ private Map, SortedKey> getSortedExceptionMappers() public Map, AsyncResponseProvider> getAsyncResponseProviders() { - if (asyncResponseProviders == null && parent != null) - return parent.getAsyncResponseProviders(); - return asyncResponseProviders; + return serverHelper.getAsyncResponseProviders(parent); } - public Map, AsyncClientResponseProvider> getAsyncClientResponseProviders() + public Map, AsyncStreamProvider> getAsyncStreamProviders() { - if (asyncClientResponseProviders == null && parent != null) - return parent.getAsyncClientResponseProviders(); - return asyncClientResponseProviders; + return serverHelper.getAsyncStreamProviders(parent); } - public Map, AsyncStreamProvider> getAsyncStreamProviders() + public Map, AsyncClientResponseProvider> getAsyncClientResponseProviders() { - if (asyncStreamProviders == null && parent != null) - return parent.getAsyncStreamProviders(); - return asyncStreamProviders; + return clientHelper.getAsyncClientResponseProviders(parent); } public Map getContextInjectors() @@ -595,58 +418,42 @@ public void setInjectorFactory(InjectorFactory injectorFactory) public JaxrsInterceptorRegistry getServerReaderInterceptorRegistry() { - if (serverReaderInterceptorRegistry == null && parent != null) - return parent.getServerReaderInterceptorRegistry(); - return serverReaderInterceptorRegistry; + return serverHelper.getServerReaderInterceptorRegistry(parent); } public JaxrsInterceptorRegistry getServerWriterInterceptorRegistry() { - if (serverWriterInterceptorRegistry == null && parent != null) - return parent.getServerWriterInterceptorRegistry(); - return serverWriterInterceptorRegistry; + return serverHelper.getServerWriterInterceptorRegistry(parent); } public JaxrsInterceptorRegistry getContainerRequestFilterRegistry() { - if (containerRequestFilterRegistry == null && parent != null) - return parent.getContainerRequestFilterRegistry(); - return containerRequestFilterRegistry; + return serverHelper.getContainerRequestFilterRegistry(parent); } public JaxrsInterceptorRegistry getContainerResponseFilterRegistry() { - if (containerResponseFilterRegistry == null && parent != null) - return parent.getContainerResponseFilterRegistry(); - return containerResponseFilterRegistry; + return serverHelper.getContainerResponseFilterRegistry(parent); } public JaxrsInterceptorRegistry getClientReaderInterceptorRegistry() { - if (clientReaderInterceptorRegistry == null && parent != null) - return parent.getClientReaderInterceptorRegistry(); - return clientReaderInterceptorRegistry; + return clientHelper.getClientReaderInterceptorRegistry(parent); } public JaxrsInterceptorRegistry getClientWriterInterceptorRegistry() { - if (clientWriterInterceptorRegistry == null && parent != null) - return parent.getClientWriterInterceptorRegistry(); - return clientWriterInterceptorRegistry; + return clientHelper.getClientWriterInterceptorRegistry(parent); } public JaxrsInterceptorRegistry getClientRequestFilterRegistry() { - if (clientRequestFilterRegistry == null && parent != null) - return parent.getClientRequestFilterRegistry(); - return clientRequestFilterRegistry; + return clientHelper.getClientRequestFilterRegistry(parent); } public JaxrsInterceptorRegistry getClientResponseFilters() { - if (clientResponseFilters == null && parent != null) - return parent.getClientResponseFilters(); - return clientResponseFilters; + return clientHelper.getClientResponseFilters(parent); } public boolean isBuiltinsRegistered() @@ -661,17 +468,17 @@ public void setBuiltinsRegistered(boolean builtinsRegistered) public UriBuilder createUriBuilder() { - return new ResteasyUriBuilderImpl(); + return Utils.createUriBuilder(); } public Response.ResponseBuilder createResponseBuilder() { - return new ResponseBuilderImpl(); + return Utils.createResponseBuilder(); } public Variant.VariantListBuilder createVariantListBuilder() { - return new VariantListBuilderImpl(); + return Utils.createVariantListBuilder(); } public HeaderDelegate createHeaderDelegate(Class tClass) @@ -681,201 +488,31 @@ public HeaderDelegate createHeaderDelegate(Class tClass) if (headerDelegates == null && parent != null) return parent.createHeaderDelegate(tClass); - Class clazz = tClass; - while (clazz != null) - { - HeaderDelegate delegate = headerDelegates.get(clazz); - if (delegate != null) - { - return delegate; - } - delegate = createHeaderDelegateFromInterfaces(clazz.getInterfaces()); - if (delegate != null) - { - return delegate; - } - clazz = clazz.getSuperclass(); - } - - return createHeaderDelegateFromInterfaces(tClass.getInterfaces()); - } - - private HeaderDelegate createHeaderDelegateFromInterfaces(Class[] interfaces) - { - HeaderDelegate delegate = null; - for (int i = 0; i < interfaces.length; i++) - { - delegate = headerDelegates.get(interfaces[i]); - if (delegate != null) - { - return delegate; - } - delegate = createHeaderDelegateFromInterfaces(interfaces[i].getInterfaces()); - if (delegate != null) - { - return delegate; - } - } - return null; + return Utils.createHeaderDelegate(headerDelegates, tClass); } private Map, HeaderDelegate> getHeaderDelegates() { if (headerDelegates == null && parent != null) return parent.getHeaderDelegates(); - return headerDelegates; - } - - private void addHeaderDelegateIfAbsent(Class clazz, HeaderDelegate header) - { - if (headerDelegates == null || !headerDelegates.containsKey(clazz)) - { - addHeaderDelegate(clazz, header); - } + return headerDelegates != null ? headerDelegates : Collections.emptyMap(); } public void addHeaderDelegate(Class clazz, HeaderDelegate header) { if (headerDelegates == null) - { - headerDelegates = new ConcurrentHashMap, HeaderDelegate>(); - headerDelegates.putAll(parent.getHeaderDelegates()); - } - headerDelegates.put(clazz, header); + { + headerDelegates = new ConcurrentHashMap, HeaderDelegate>(); + headerDelegates.putAll(parent.getHeaderDelegates()); + } + headerDelegates.put(clazz, header); } - /** - * Specify the provider class. This is there jsut in case the provider instance is a proxy. Proxies tend - * to lose generic type information. - * - * @param provider message reader - * @param providerClass provider class - * @param priority priority - * @param isBuiltin built-in - */ - - private void addMessageBodyReader(MessageBodyReader provider, Class providerClass, int priority, - boolean isBuiltin) - { - SortedKey key = new SortedKey(MessageBodyReader.class, provider, - providerClass, priority, isBuiltin); - injectProperties(providerClass, provider); - Consumes consumeMime = provider.getClass().getAnnotation(Consumes.class); - RuntimeType type = null; - ConstrainedTo constrainedTo = providerClass.getAnnotation(ConstrainedTo.class); - if (constrainedTo != null) - type = constrainedTo.value(); - - if ((type == null || type == RuntimeType.CLIENT) && clientMessageBodyReaders == null) - { - clientMessageBodyReaders = parent.getClientMessageBodyReaders().clone(); - } - if ((type == null || type == RuntimeType.SERVER) && serverMessageBodyReaders == null) - { - serverMessageBodyReaders = parent.getServerMessageBodyReaders().clone(); - } - if (consumeMime != null) - { - for (String consume : consumeMime.value()) - { - if (type == null) - { - clientMessageBodyReaders.add(MediaType.valueOf(consume), key); - serverMessageBodyReaders.add(MediaType.valueOf(consume), key); - } - else if (type == RuntimeType.CLIENT) - { - clientMessageBodyReaders.add(MediaType.valueOf(consume), key); - } - else - { - serverMessageBodyReaders.add(MediaType.valueOf(consume), key); - } - } - } - else - { - if (type == null) - { - clientMessageBodyReaders.add(new MediaType("*", "*"), key); - serverMessageBodyReaders.add(new MediaType("*", "*"), key); - } - else if (type == RuntimeType.CLIENT) - { - clientMessageBodyReaders.add(new MediaType("*", "*"), key); - } - else - { - serverMessageBodyReaders.add(new MediaType("*", "*"), key); - } - } - } - - /** - * Specify the provider class. This is there jsut in case the provider instance is a proxy. Proxies tend - * to lose generic type information - * - * @param provider message reader - * @param providerClass provider class - * @param priority priority - * @param isBuiltin built-in - */ - private void addMessageBodyWriter(MessageBodyWriter provider, Class providerClass, int priority, - boolean isBuiltin) + private void addHeaderDelegateIfAbsent(Class clazz, HeaderDelegate header) { - injectProperties(providerClass, provider); - Produces consumeMime = provider.getClass().getAnnotation(Produces.class); - SortedKey key = new SortedKey(MessageBodyWriter.class, provider, - providerClass, priority, isBuiltin); - RuntimeType type = null; - ConstrainedTo constrainedTo = providerClass.getAnnotation(ConstrainedTo.class); - if (constrainedTo != null) - type = constrainedTo.value(); - - if ((type == null || type == RuntimeType.CLIENT) && clientMessageBodyWriters == null) - { - clientMessageBodyWriters = parent.getClientMessageBodyWriters().clone(); - } - if ((type == null || type == RuntimeType.SERVER) && serverMessageBodyWriters == null) - { - serverMessageBodyWriters = parent.getServerMessageBodyWriters().clone(); - } - if (consumeMime != null) - { - for (String consume : consumeMime.value()) - { - //logger.info(">>> Adding provider: " + provider.getClass().getName() + " with mime type of: " + mime); - if (type == null) - { - clientMessageBodyWriters.add(MediaType.valueOf(consume), key); - serverMessageBodyWriters.add(MediaType.valueOf(consume), key); - } - else if (type == RuntimeType.CLIENT) - { - clientMessageBodyWriters.add(MediaType.valueOf(consume), key); - } - else - { - serverMessageBodyWriters.add(MediaType.valueOf(consume), key); - } - } - } - else + if (headerDelegates == null || !headerDelegates.containsKey(clazz)) { - //logger.info(">>> Adding provider: " + provider.getClass().getName() + " with mime type of: default */*"); - if (type == null) - { - clientMessageBodyWriters.add(new MediaType("*", "*"), key); - serverMessageBodyWriters.add(new MediaType("*", "*"), key); - } - else if (type == RuntimeType.CLIENT) - { - clientMessageBodyWriters.add(new MediaType("*", "*"), key); - } - else - { - serverMessageBodyWriters.add(new MediaType("*", "*"), key); - } + addHeaderDelegate(clazz, header); } } @@ -939,16 +576,16 @@ private MessageBodyReader resolveMessageBodyReader(Class type, Type ge for (SortedKey reader : readers) { //logger.info(" matching reader: " + reader.getClass().getName()); - if (reader.obj.isReadable(type, genericType, annotations, mediaType)) + if (reader.getObj().isReadable(type, genericType, annotations, mediaType)) { LogMessages.LOGGER.debugf("MessageBodyReader: %s", reader.getClass().getName()); - return (MessageBodyReader) reader.obj; + return (MessageBodyReader) reader.getObj(); } } return null; } - protected MessageBodyReader resolveMessageBodyReader(Class type, Type genericType, + private MessageBodyReader resolveMessageBodyReader(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MediaTypeMap> availableReaders, RESTEasyTracingLogger tracingLogger) { @@ -969,10 +606,10 @@ protected MessageBodyReader resolveMessageBodyReader(Class type, Type { final SortedKey reader = iterator.next(); - if (reader.obj.isReadable(type, genericType, annotations, mediaType)) + if (reader.getObj().isReadable(type, genericType, annotations, mediaType)) { LogMessages.LOGGER.debugf("MessageBodyReader: %s", reader.getClass().getName()); - result = (MessageBodyReader) reader.obj; + result = (MessageBodyReader) reader.getObj(); tracingLogger.log("MBR_SELECTED", reader); break; } @@ -984,7 +621,7 @@ protected MessageBodyReader resolveMessageBodyReader(Class type, Type while (iterator.hasNext()) { final SortedKey reader = iterator.next(); - tracingLogger.log("MBR_SKIPPED", reader.obj); + tracingLogger.log("MBR_SKIPPED", reader.getObj()); } } return result; @@ -999,7 +636,7 @@ private void addExceptionMapper(ExceptionMapper provider, Class providerClass, b } Type exceptionType = Types.getActualTypeArgumentsOfAnInterface(providerClass, ExceptionMapper.class)[0]; - injectProperties(providerClass, provider); + Utils.injectProperties(this, providerClass, provider); Class exceptionClass = Types.getRawType(exceptionType); if (!Throwable.class.isAssignableFrom(exceptionClass)) @@ -1011,7 +648,7 @@ private void addExceptionMapper(ExceptionMapper provider, Class providerClass, b sortedExceptionMappers = new ConcurrentHashMap, SortedKey>(); sortedExceptionMappers.putAll(parent.getSortedExceptionMappers()); } - int priority = getPriority(null, null, ExceptionMapper.class, providerClass); + int priority = Utils.getPriority(null, null, ExceptionMapper.class, providerClass); SortedKey candidateExceptionMapper = new SortedKey<>(null, provider, providerClass, priority, isBuiltin); SortedKey registeredExceptionMapper; @@ -1021,53 +658,12 @@ private void addExceptionMapper(ExceptionMapper provider, Class providerClass, b return; } sortedExceptionMappers.put(exceptionClass, candidateExceptionMapper); - exceptionMappers = null; - } - - private void addAsyncResponseProvider(AsyncResponseProvider provider, Class providerClass) - { - Type asyncType = Types.getActualTypeArgumentsOfAnInterface(providerClass, AsyncResponseProvider.class)[0]; - injectProperties(provider.getClass(), provider); - Class asyncClass = Types.getRawType(asyncType); - if (asyncResponseProviders == null) - { - asyncResponseProviders = new ConcurrentHashMap, AsyncResponseProvider>(); - asyncResponseProviders.putAll(parent.getAsyncResponseProviders()); - } - asyncResponseProviders.put(asyncClass, provider); - } - - private void addAsyncClientResponseProvider(AsyncClientResponseProvider provider, Class providerClass) - { - Type asyncType = Types.getActualTypeArgumentsOfAnInterface(providerClass, AsyncClientResponseProvider.class)[0]; - injectProperties(provider.getClass(), provider); - - Class asyncClass = Types.getRawType(asyncType); - if (asyncClientResponseProviders == null) - { - asyncClientResponseProviders = new ConcurrentHashMap, AsyncClientResponseProvider>(); - asyncClientResponseProviders.putAll(parent.getAsyncClientResponseProviders()); - } - asyncClientResponseProviders.put(asyncClass, provider); - } - - private void addAsyncStreamProvider(AsyncStreamProvider provider, Class providerClass) - { - Type asyncType = Types.getActualTypeArgumentsOfAnInterface(providerClass, AsyncStreamProvider.class)[0]; - injectProperties(provider.getClass(), provider); - Class asyncClass = Types.getRawType(asyncType); - if (asyncStreamProviders == null) - { - asyncStreamProviders = new ConcurrentHashMap, AsyncStreamProvider>(); - asyncStreamProviders.putAll(parent.getAsyncStreamProviders()); - } - asyncStreamProviders.put(asyncClass, provider); } private void addContextInjector(ContextInjector provider, Class providerClass) { Type[] typeArgs = Types.getActualTypeArgumentsOfAnInterface(providerClass, ContextInjector.class); - injectProperties(provider.getClass(), provider); + Utils.injectProperties(this, provider.getClass(), provider); if (contextInjectors == null) { @@ -1095,7 +691,7 @@ private void addContextResolver(ContextResolver provider, int priority, Class pr throw new RuntimeException(Messages.MESSAGES.registeringContextResolverAsLambda()); } Type typeParameter = Types.getActualTypeArgumentsOfAnInterface(providerClass, ContextResolver.class)[0]; - injectProperties(providerClass, provider); + Utils.injectProperties(this, providerClass, provider); Class parameterClass = Types.getRawType(typeParameter); if (contextResolvers == null) { @@ -1157,7 +753,7 @@ public List getContextResolvers(final Class clazz, MediaType return null; List rtn = new ArrayList(); List> list = resolvers.getPossible(type); - list.forEach(resolver -> rtn.add(resolver.obj)); + list.forEach(resolver -> rtn.add(resolver.getObj())); return rtn; } @@ -1268,35 +864,7 @@ public HeaderDelegate getHeaderDelegate(Class aClass) */ public void registerProvider(Class provider, boolean isBuiltin) { - registerProvider(provider, null, isBuiltin, null); - } - - protected boolean isA(Class target, Class type, Map, Integer> contracts) - { - return isA(target, type, contracts == null ? null : contracts.keySet()); - } - - protected boolean isA(Object target, Class type, Map, Integer> contracts) - { - return isA(target.getClass(), type, contracts); - } - - private static int getPriority(Integer override, Map, Integer> contracts, Class type, Class component) - { - if (override != null) - return override; - if (contracts != null) - { - Integer p = contracts.get(type); - if (p != null) - return p; - } - // Check for weld proxy. - component = component.isSynthetic() ? component.getSuperclass() : component; - Priority priority = component.getAnnotation(Priority.class); - if (priority == null) - return Priorities.USER; - return priority.value(); + registerProvider(provider, null, isBuiltin, null); } public void registerProvider(Class provider, Integer priorityOverride, boolean isBuiltin, @@ -1314,10 +882,13 @@ public void registerProvider(Class provider, Integer priorityOverride, boolean i classContracts.put(provider, newContracts); } - protected void processProviderContracts(Class provider, Integer priorityOverride, boolean isBuiltin, + private void processProviderContracts(Class provider, Integer priorityOverride, boolean isBuiltin, Map, Integer> contracts, Map, Integer> newContracts) { - if (isA(provider, ParamConverterProvider.class, contracts)) + clientHelper.processProviderContracts(provider, priorityOverride, isBuiltin, contracts, newContracts, parent); + serverHelper.processProviderContracts(provider, priorityOverride, isBuiltin, contracts, newContracts, parent); + + if (Utils.isA(provider, ParamConverterProvider.class, contracts)) { ParamConverterProvider paramConverterProvider = (ParamConverterProvider) injectedInstance(provider); injectProperties(provider); @@ -1326,209 +897,30 @@ protected void processProviderContracts(Class provider, Integer priorityOverride sortedParamConverterProviders = Collections .synchronizedSortedSet(new TreeSet<>(parent.getSortedParamConverterProviders())); } - int priority = getPriority(priorityOverride, contracts, ParamConverterProvider.class, provider); + int priority = Utils.getPriority(priorityOverride, contracts, ParamConverterProvider.class, provider); sortedParamConverterProviders .add(new ExtSortedKey<>(null, paramConverterProvider, provider, priority, isBuiltin)); newContracts.put(ParamConverterProvider.class, priority); } - if (isA(provider, MessageBodyReader.class, contracts)) - { - try - { - int priority = getPriority(priorityOverride, contracts, MessageBodyReader.class, provider); - addMessageBodyReader(createProviderInstance((Class) provider), provider, - priority, isBuiltin); - newContracts.put(MessageBodyReader.class, priority); - } - catch (Exception e) - { - throw new RuntimeException(Messages.MESSAGES.unableToInstantiateMessageBodyReader(), e); - } - } - if (isA(provider, MessageBodyWriter.class, contracts)) - { - try - { - int priority = getPriority(priorityOverride, contracts, MessageBodyWriter.class, provider); - addMessageBodyWriter(createProviderInstance((Class) provider), provider, - priority, isBuiltin); - newContracts.put(MessageBodyWriter.class, priority); - } - catch (Exception e) - { - throw new RuntimeException(Messages.MESSAGES.unableToInstantiateMessageBodyWriter(), e); - } - } - if (isA(provider, ExceptionMapper.class, contracts)) + if (Utils.isA(provider, ExceptionMapper.class, contracts)) { try { addExceptionMapper(createProviderInstance((Class) provider), provider, isBuiltin); newContracts.put(ExceptionMapper.class, - getPriority(priorityOverride, contracts, ExceptionMapper.class, provider)); + Utils.getPriority(priorityOverride, contracts, ExceptionMapper.class, provider)); } catch (Exception e) { throw new RuntimeException(Messages.MESSAGES.unableToInstantiateExceptionMapper(), e); } } - if (isA(provider, AsyncResponseProvider.class, contracts)) - { - try - { - addAsyncResponseProvider(createProviderInstance((Class) provider), - provider); - newContracts.put(AsyncResponseProvider.class, - getPriority(priorityOverride, contracts, AsyncResponseProvider.class, provider)); - } - catch (Exception e) - { - throw new RuntimeException(Messages.MESSAGES.unableToInstantiateAsyncResponseProvider(), e); - } - } - if (isA(provider, AsyncClientResponseProvider.class, contracts)) - { - try - { - addAsyncClientResponseProvider( - createProviderInstance((Class) provider), provider); - newContracts.put(AsyncClientResponseProvider.class, - getPriority(priorityOverride, contracts, AsyncClientResponseProvider.class, provider)); - } - catch (Exception e) - { - throw new RuntimeException(Messages.MESSAGES.unableToInstantiateAsyncClientResponseProvider(), e); - } - } - if (isA(provider, AsyncStreamProvider.class, contracts)) - { - try - { - addAsyncStreamProvider(createProviderInstance((Class) provider), provider); - newContracts.put(AsyncStreamProvider.class, - getPriority(priorityOverride, contracts, AsyncStreamProvider.class, provider)); - } - catch (Exception e) - { - throw new RuntimeException(Messages.MESSAGES.unableToInstantiateAsyncStreamProvider(), e); - } - } - if (isA(provider, ClientRequestFilter.class, contracts)) - { - if (clientRequestFilterRegistry == null) - { - clientRequestFilterRegistry = parent.getClientRequestFilterRegistry().clone(this); - } - int priority = getPriority(priorityOverride, contracts, ClientRequestFilter.class, provider); - clientRequestFilterRegistry.registerClass(provider, priority); - newContracts.put(ClientRequestFilter.class, priority); - } - if (isA(provider, ClientResponseFilter.class, contracts)) - { - if (clientResponseFilters == null) - { - clientResponseFilters = parent.getClientResponseFilters().clone(this); - } - int priority = getPriority(priorityOverride, contracts, ClientResponseFilter.class, provider); - clientResponseFilters.registerClass(provider, priority); - newContracts.put(ClientResponseFilter.class, priority); - } - if (isA(provider, ContainerRequestFilter.class, contracts)) - { - if (containerRequestFilterRegistry == null) - { - containerRequestFilterRegistry = parent.getContainerRequestFilterRegistry().clone(this); - } - int priority = getPriority(priorityOverride, contracts, ContainerRequestFilter.class, provider); - containerRequestFilterRegistry.registerClass(provider, priority); - newContracts.put(ContainerRequestFilter.class, priority); - } - if (isA(provider, ContainerResponseFilter.class, contracts)) - { - if (containerResponseFilterRegistry == null) - { - containerResponseFilterRegistry = parent.getContainerResponseFilterRegistry().clone(this); - } - int priority = getPriority(priorityOverride, contracts, ContainerResponseFilter.class, provider); - containerResponseFilterRegistry.registerClass(provider, priority); - newContracts.put(ContainerResponseFilter.class, priority); - } - if (isA(provider, ReaderInterceptor.class, contracts)) - { - ConstrainedTo constrainedTo = (ConstrainedTo) provider.getAnnotation(ConstrainedTo.class); - int priority = getPriority(priorityOverride, contracts, ReaderInterceptor.class, provider); - if (constrainedTo != null && constrainedTo.value() == RuntimeType.SERVER) - { - if (serverReaderInterceptorRegistry == null) - { - serverReaderInterceptorRegistry = parent.getServerReaderInterceptorRegistry().clone(this); - } - serverReaderInterceptorRegistry.registerClass(provider, priority); - } - if (constrainedTo != null && constrainedTo.value() == RuntimeType.CLIENT) - { - if (clientReaderInterceptorRegistry == null) - { - clientReaderInterceptorRegistry = parent.getClientReaderInterceptorRegistry().clone(this); - } - clientReaderInterceptorRegistry.registerClass(provider, priority); - } - if (constrainedTo == null) - { - if (serverReaderInterceptorRegistry == null) - { - serverReaderInterceptorRegistry = parent.getServerReaderInterceptorRegistry().clone(this); - } - serverReaderInterceptorRegistry.registerClass(provider, priority); - if (clientReaderInterceptorRegistry == null) - { - clientReaderInterceptorRegistry = parent.getClientReaderInterceptorRegistry().clone(this); - } - clientReaderInterceptorRegistry.registerClass(provider, priority); - } - newContracts.put(ReaderInterceptor.class, priority); - } - if (isA(provider, WriterInterceptor.class, contracts)) - { - ConstrainedTo constrainedTo = (ConstrainedTo) provider.getAnnotation(ConstrainedTo.class); - int priority = getPriority(priorityOverride, contracts, WriterInterceptor.class, provider); - if (constrainedTo != null && constrainedTo.value() == RuntimeType.SERVER) - { - if (serverWriterInterceptorRegistry == null) - { - serverWriterInterceptorRegistry = parent.getServerWriterInterceptorRegistry().clone(this); - } - serverWriterInterceptorRegistry.registerClass(provider, priority); - } - if (constrainedTo != null && constrainedTo.value() == RuntimeType.CLIENT) - { - if (clientWriterInterceptorRegistry == null) - { - clientWriterInterceptorRegistry = parent.getClientWriterInterceptorRegistry().clone(this); - } - clientWriterInterceptorRegistry.registerClass(provider, priority); - } - if (constrainedTo == null) - { - if (serverWriterInterceptorRegistry == null) - { - serverWriterInterceptorRegistry = parent.getServerWriterInterceptorRegistry().clone(this); - } - serverWriterInterceptorRegistry.registerClass(provider, priority); - if (clientWriterInterceptorRegistry == null) - { - clientWriterInterceptorRegistry = parent.getClientWriterInterceptorRegistry().clone(this); - } - clientWriterInterceptorRegistry.registerClass(provider, priority); - } - newContracts.put(WriterInterceptor.class, priority); - } - if (isA(provider, ContextResolver.class, contracts)) + if (Utils.isA(provider, ContextResolver.class, contracts)) { try { - int priority = getPriority(priorityOverride, contracts, ContextResolver.class, provider); + int priority = Utils.getPriority(priorityOverride, contracts, ContextResolver.class, provider); addContextResolver(createProviderInstance((Class)provider), priority, provider, isBuiltin); newContracts.put(ContextResolver.class, priority); } @@ -1537,12 +929,12 @@ protected void processProviderContracts(Class provider, Integer priorityOverride throw new RuntimeException(Messages.MESSAGES.unableToInstantiateContextResolver(), e); } } - if (isA(provider, ContextInjector.class, contracts)) + if (Utils.isA(provider, ContextInjector.class, contracts)) { try { addContextInjector(createProviderInstance((Class) provider), provider); - int priority = getPriority(priorityOverride, contracts, ContextInjector.class, provider); + int priority = Utils.getPriority(priorityOverride, contracts, ContextInjector.class, provider); newContracts.put(ContextInjector.class, priority); } catch (Exception e) @@ -1550,13 +942,13 @@ protected void processProviderContracts(Class provider, Integer priorityOverride throw new RuntimeException(Messages.MESSAGES.unableToInstantiateContextInjector(), e); } } - if (isA(provider, StringParameterUnmarshaller.class, contracts)) + if (Utils.isA(provider, StringParameterUnmarshaller.class, contracts)) { addStringParameterUnmarshaller(provider); - int priority = getPriority(priorityOverride, contracts, StringParameterUnmarshaller.class, provider); + int priority = Utils.getPriority(priorityOverride, contracts, StringParameterUnmarshaller.class, provider); newContracts.put(StringParameterUnmarshaller.class, priority); } - if (isA(provider, InjectorFactory.class, contracts)) + if (Utils.isA(provider, InjectorFactory.class, contracts)) { try { @@ -1568,45 +960,10 @@ protected void processProviderContracts(Class provider, Integer priorityOverride throw new RuntimeException(e); } } - if (isA(provider, DynamicFeature.class, contracts)) - { - ConstrainedTo constrainedTo = (ConstrainedTo) provider.getAnnotation(ConstrainedTo.class); - int priority = getPriority(priorityOverride, contracts, DynamicFeature.class, provider); - if (constrainedTo != null && constrainedTo.value() == RuntimeType.SERVER) - { - if (serverDynamicFeatures == null) - { - serverDynamicFeatures = new CopyOnWriteArraySet(parent.getServerDynamicFeatures()); - } - serverDynamicFeatures.add((DynamicFeature) injectedInstance(provider)); - } - if (constrainedTo != null && constrainedTo.value() == RuntimeType.CLIENT) - { - if (clientDynamicFeatures == null) - { - clientDynamicFeatures = new CopyOnWriteArraySet(parent.getClientDynamicFeatures()); - } - clientDynamicFeatures.add((DynamicFeature) injectedInstance(provider)); - } - if (constrainedTo == null) - { - if (serverDynamicFeatures == null) - { - serverDynamicFeatures = new CopyOnWriteArraySet(parent.getServerDynamicFeatures()); - } - serverDynamicFeatures.add((DynamicFeature) injectedInstance(provider)); - if (clientDynamicFeatures == null) - { - clientDynamicFeatures = new CopyOnWriteArraySet(parent.getClientDynamicFeatures()); - } - clientDynamicFeatures.add((DynamicFeature) injectedInstance(provider)); - } - newContracts.put(DynamicFeature.class, priority); - } - if (isA(provider, Feature.class, contracts)) + if (Utils.isA(provider, Feature.class, contracts)) { ConstrainedTo constrainedTo = (ConstrainedTo) provider.getAnnotation(ConstrainedTo.class); - int priority = getPriority(priorityOverride, contracts, Feature.class, provider); + int priority = Utils.getPriority(priorityOverride, contracts, Feature.class, provider); Feature feature = injectedInstance((Class) provider); if (constrainedTo == null || constrainedTo.value() == getRuntimeType()) { @@ -1617,24 +974,13 @@ protected void processProviderContracts(Class provider, Integer priorityOverride } newContracts.put(Feature.class, priority); } - if (isA(provider, RxInvokerProvider.class, contracts)) - { - int priority = getPriority(priorityOverride, contracts, RxInvokerProvider.class, provider); - newContracts.put(RxInvokerProvider.class, priority); - Class clazz = Types.getTemplateParameterOfInterface(provider, RxInvokerProvider.class); - clazz = Types.getTemplateParameterOfInterface(clazz, RxInvoker.class); - if (clazz != null) - { - reactiveClasses.put(clazz, provider); - } - } - if (isA(provider, ResourceClassProcessor.class, contracts)) + if (Utils.isA(provider, ResourceClassProcessor.class, contracts)) { - int priority = getPriority(priorityOverride, contracts, ResourceClassProcessor.class, provider); + int priority = Utils.getPriority(priorityOverride, contracts, ResourceClassProcessor.class, provider); addResourceClassProcessor(provider, priority); newContracts.put(ResourceClassProcessor.class, priority); } - if (isA(provider, HeaderDelegate.class, contracts)) + if (Utils.isA(provider, HeaderDelegate.class, contracts)) { Type[] headerTypes = Types.getActualTypeArgumentsOfAnInterface(provider, HeaderDelegate.class); if (headerTypes.length == 0) @@ -1676,10 +1022,13 @@ public void registerProviderInstance(Object provider, Map, Integer> con classContracts.put(providerClass, newContracts); } - protected void processProviderInstanceContracts(Object provider, Map, Integer> contracts, + private void processProviderInstanceContracts(Object provider, Map, Integer> contracts, Integer priorityOverride, boolean builtIn, Map, Integer> newContracts) { - if (isA(provider, ParamConverterProvider.class, contracts)) + clientHelper.processProviderInstanceContracts(provider, contracts, priorityOverride, builtIn, newContracts, parent); + serverHelper.processProviderInstanceContracts(provider, contracts, priorityOverride, builtIn, newContracts, parent); + + if (Utils.isA(provider, ParamConverterProvider.class, contracts)) { injectProperties(provider); if (sortedParamConverterProviders == null) @@ -1687,43 +1036,17 @@ protected void processProviderInstanceContracts(Object provider, Map, I sortedParamConverterProviders = Collections .synchronizedSortedSet(new TreeSet<>(parent.getSortedParamConverterProviders())); } - int priority = getPriority(priorityOverride, contracts, ParamConverterProvider.class, provider.getClass()); + int priority = Utils.getPriority(priorityOverride, contracts, ParamConverterProvider.class, provider.getClass()); sortedParamConverterProviders.add( new ExtSortedKey<>(null, (ParamConverterProvider) provider, provider.getClass(), priority, builtIn)); newContracts.put(ParamConverterProvider.class, priority); } - if (isA(provider, MessageBodyReader.class, contracts)) - { - try - { - int priority = getPriority(priorityOverride, contracts, MessageBodyReader.class, provider.getClass()); - addMessageBodyReader((MessageBodyReader) provider, provider.getClass(), priority, builtIn); - newContracts.put(MessageBodyReader.class, priority); - } - catch (Exception e) - { - throw new RuntimeException(Messages.MESSAGES.unableToInstantiateMessageBodyReader(), e); - } - } - if (isA(provider, MessageBodyWriter.class, contracts)) - { - try - { - int priority = getPriority(priorityOverride, contracts, MessageBodyWriter.class, provider.getClass()); - addMessageBodyWriter((MessageBodyWriter) provider, provider.getClass(), priority, builtIn); - newContracts.put(MessageBodyWriter.class, priority); - } - catch (Exception e) - { - throw new RuntimeException(Messages.MESSAGES.unableToInstantiateMessageBodyWriter(), e); - } - } - if (isA(provider, ExceptionMapper.class, contracts)) + if (Utils.isA(provider, ExceptionMapper.class, contracts)) { try { addExceptionMapper((ExceptionMapper) provider, provider.getClass(), builtIn); - int priority = getPriority(priorityOverride, contracts, ExceptionMapper.class, provider.getClass()); + int priority = Utils.getPriority(priorityOverride, contracts, ExceptionMapper.class, provider.getClass()); newContracts.put(ExceptionMapper.class, priority); } catch (Exception e) @@ -1731,51 +1054,11 @@ protected void processProviderInstanceContracts(Object provider, Map, I throw new RuntimeException(Messages.MESSAGES.unableToInstantiateExceptionMapper(), e); } } - if (isA(provider, AsyncResponseProvider.class, contracts)) - { - try - { - addAsyncResponseProvider((AsyncResponseProvider) provider, provider.getClass()); - int priority = getPriority(priorityOverride, contracts, AsyncResponseProvider.class, provider.getClass()); - newContracts.put(AsyncResponseProvider.class, priority); - } - catch (Exception e) - { - throw new RuntimeException(Messages.MESSAGES.unableToInstantiateAsyncResponseProvider(), e); - } - } - if (isA(provider, AsyncClientResponseProvider.class, contracts)) - { - try - { - addAsyncClientResponseProvider((AsyncClientResponseProvider) provider, provider.getClass()); - int priority = getPriority(priorityOverride, contracts, AsyncClientResponseProvider.class, - provider.getClass()); - newContracts.put(AsyncClientResponseProvider.class, priority); - } - catch (Exception e) - { - throw new RuntimeException(Messages.MESSAGES.unableToInstantiateAsyncClientResponseProvider(), e); - } - } - if (isA(provider, AsyncStreamProvider.class, contracts)) - { - try - { - addAsyncStreamProvider((AsyncStreamProvider) provider, provider.getClass()); - int priority = getPriority(priorityOverride, contracts, AsyncStreamProvider.class, provider.getClass()); - newContracts.put(AsyncStreamProvider.class, priority); - } - catch (Exception e) - { - throw new RuntimeException(Messages.MESSAGES.unableToInstantiateAsyncStreamProvider(), e); - } - } - if (isA(provider, ContextResolver.class, contracts)) + if (Utils.isA(provider, ContextResolver.class, contracts)) { try { - int priority = getPriority(priorityOverride, contracts, ContextResolver.class, provider.getClass()); + int priority = Utils.getPriority(priorityOverride, contracts, ContextResolver.class, provider.getClass()); addContextResolver((ContextResolver) provider, priority, provider.getClass(), false); newContracts.put(ContextResolver.class, priority); } @@ -1784,12 +1067,12 @@ protected void processProviderInstanceContracts(Object provider, Map, I throw new RuntimeException(Messages.MESSAGES.unableToInstantiateContextResolver(), e); } } - if (isA(provider, ContextInjector.class, contracts)) + if (Utils.isA(provider, ContextInjector.class, contracts)) { try { addContextInjector((ContextInjector) provider, provider.getClass()); - int priority = getPriority(priorityOverride, contracts, ContextInjector.class, provider.getClass()); + int priority = Utils.getPriority(priorityOverride, contracts, ContextInjector.class, provider.getClass()); newContracts.put(ContextInjector.class, priority); } catch (Exception e) @@ -1797,160 +1080,15 @@ protected void processProviderInstanceContracts(Object provider, Map, I throw new RuntimeException(Messages.MESSAGES.unableToInstantiateContextInjector(), e); } } - if (isA(provider, ClientRequestFilter.class, contracts)) - { - if (clientRequestFilterRegistry == null) - { - clientRequestFilterRegistry = parent.getClientRequestFilterRegistry().clone(this); - } - int priority = getPriority(priorityOverride, contracts, ClientRequestFilter.class, provider.getClass()); - clientRequestFilterRegistry.registerSingleton((ClientRequestFilter) provider, priority); - newContracts.put(ClientRequestFilter.class, priority); - } - if (isA(provider, ClientResponseFilter.class, contracts)) - { - if (clientResponseFilters == null) - { - clientResponseFilters = parent.getClientResponseFilters().clone(this); - } - int priority = getPriority(priorityOverride, contracts, ClientResponseFilter.class, provider.getClass()); - clientResponseFilters.registerSingleton((ClientResponseFilter) provider, priority); - newContracts.put(ClientResponseFilter.class, priority); - } - if (isA(provider, ContainerRequestFilter.class, contracts)) - { - if (containerRequestFilterRegistry == null) - { - containerRequestFilterRegistry = parent.getContainerRequestFilterRegistry().clone(this); - } - int priority = getPriority(priorityOverride, contracts, ContainerRequestFilter.class, provider.getClass()); - containerRequestFilterRegistry.registerSingleton((ContainerRequestFilter) provider, priority); - newContracts.put(ContainerRequestFilter.class, priority); - } - if (isA(provider, ContainerResponseFilter.class, contracts)) - { - if (containerResponseFilterRegistry == null) - { - containerResponseFilterRegistry = parent.getContainerResponseFilterRegistry().clone(this); - } - int priority = getPriority(priorityOverride, contracts, ContainerResponseFilter.class, provider.getClass()); - containerResponseFilterRegistry.registerSingleton((ContainerResponseFilter) provider, priority); - newContracts.put(ContainerResponseFilter.class, priority); - } - if (isA(provider, ReaderInterceptor.class, contracts)) - { - ConstrainedTo constrainedTo = (ConstrainedTo) provider.getClass().getAnnotation(ConstrainedTo.class); - int priority = getPriority(priorityOverride, contracts, ReaderInterceptor.class, provider.getClass()); - if (constrainedTo != null && constrainedTo.value() == RuntimeType.SERVER) - { - if (serverReaderInterceptorRegistry == null) - { - serverReaderInterceptorRegistry = parent.getServerReaderInterceptorRegistry().clone(this); - } - serverReaderInterceptorRegistry.registerSingleton((ReaderInterceptor) provider, priority); - } - if (constrainedTo != null && constrainedTo.value() == RuntimeType.CLIENT) - { - if (clientReaderInterceptorRegistry == null) - { - clientReaderInterceptorRegistry = parent.getClientReaderInterceptorRegistry().clone(this); - } - clientReaderInterceptorRegistry.registerSingleton((ReaderInterceptor) provider, priority); - } - if (constrainedTo == null) - { - if (serverReaderInterceptorRegistry == null) - { - serverReaderInterceptorRegistry = parent.getServerReaderInterceptorRegistry().clone(this); - } - serverReaderInterceptorRegistry.registerSingleton((ReaderInterceptor) provider, priority); - if (clientReaderInterceptorRegistry == null) - { - clientReaderInterceptorRegistry = parent.getClientReaderInterceptorRegistry().clone(this); - } - clientReaderInterceptorRegistry.registerSingleton((ReaderInterceptor) provider, priority); - } - newContracts.put(ReaderInterceptor.class, priority); - } - if (isA(provider, WriterInterceptor.class, contracts)) - { - ConstrainedTo constrainedTo = (ConstrainedTo) provider.getClass().getAnnotation(ConstrainedTo.class); - int priority = getPriority(priorityOverride, contracts, WriterInterceptor.class, provider.getClass()); - if (constrainedTo != null && constrainedTo.value() == RuntimeType.SERVER) - { - if (serverWriterInterceptorRegistry == null) - { - serverWriterInterceptorRegistry = parent.getServerWriterInterceptorRegistry().clone(this); - } - serverWriterInterceptorRegistry.registerSingleton((WriterInterceptor) provider, priority); - } - if (constrainedTo != null && constrainedTo.value() == RuntimeType.CLIENT) - { - if (clientWriterInterceptorRegistry == null) - { - clientWriterInterceptorRegistry = parent.getClientWriterInterceptorRegistry().clone(this); - } - clientWriterInterceptorRegistry.registerSingleton((WriterInterceptor) provider, priority); - } - if (constrainedTo == null) - { - if (serverWriterInterceptorRegistry == null) - { - serverWriterInterceptorRegistry = parent.getServerWriterInterceptorRegistry().clone(this); - } - serverWriterInterceptorRegistry.registerSingleton((WriterInterceptor) provider, priority); - if (clientWriterInterceptorRegistry == null) - { - clientWriterInterceptorRegistry = parent.getClientWriterInterceptorRegistry().clone(this); - } - clientWriterInterceptorRegistry.registerSingleton((WriterInterceptor) provider, priority); - } - newContracts.put(WriterInterceptor.class, priority); - } - if (isA(provider, InjectorFactory.class, contracts)) + if (Utils.isA(provider, InjectorFactory.class, contracts)) { this.injectorFactory = (InjectorFactory) provider; newContracts.put(InjectorFactory.class, 0); } - if (isA(provider, DynamicFeature.class, contracts)) - { - ConstrainedTo constrainedTo = (ConstrainedTo) provider.getClass().getAnnotation(ConstrainedTo.class); - int priority = getPriority(priorityOverride, contracts, DynamicFeature.class, provider.getClass()); - if (constrainedTo != null && constrainedTo.value() == RuntimeType.SERVER) - { - if (serverDynamicFeatures == null) - { - serverDynamicFeatures = new CopyOnWriteArraySet(parent.getServerDynamicFeatures()); - } - serverDynamicFeatures.add((DynamicFeature) provider); - } - if (constrainedTo != null && constrainedTo.value() == RuntimeType.CLIENT) - { - if (clientDynamicFeatures == null) - { - clientDynamicFeatures = new CopyOnWriteArraySet(parent.getClientDynamicFeatures()); - } - clientDynamicFeatures.add((DynamicFeature) provider); - } - if (constrainedTo == null) - { - if (serverDynamicFeatures == null) - { - serverDynamicFeatures = new CopyOnWriteArraySet(parent.getServerDynamicFeatures()); - } - serverDynamicFeatures.add((DynamicFeature) provider); - if (clientDynamicFeatures == null) - { - clientDynamicFeatures = new CopyOnWriteArraySet(parent.getClientDynamicFeatures()); - } - clientDynamicFeatures.add((DynamicFeature) provider); - } - newContracts.put(DynamicFeature.class, priority); - } - if (isA(provider, Feature.class, contracts)) + if (Utils.isA(provider, Feature.class, contracts)) { Feature feature = (Feature) provider; - injectProperties(provider.getClass(), provider); + Utils.injectProperties(this, provider.getClass(), provider); ConstrainedTo constrainedTo = (ConstrainedTo) provider.getClass().getAnnotation(ConstrainedTo.class); if (constrainedTo == null || constrainedTo.value() == getRuntimeType()) { @@ -1959,17 +1097,17 @@ protected void processProviderInstanceContracts(Object provider, Map, I enabledFeatures.add(feature); } } - int priority = getPriority(priorityOverride, contracts, Feature.class, provider.getClass()); + int priority = Utils.getPriority(priorityOverride, contracts, Feature.class, provider.getClass()); newContracts.put(Feature.class, priority); } - if (isA(provider, ResourceClassProcessor.class, contracts)) + if (Utils.isA(provider, ResourceClassProcessor.class, contracts)) { - int priority = getPriority(priorityOverride, contracts, ResourceClassProcessor.class, provider.getClass()); + int priority = Utils.getPriority(priorityOverride, contracts, ResourceClassProcessor.class, provider.getClass()); addResourceClassProcessor((ResourceClassProcessor) provider, priority); newContracts.put(ResourceClassProcessor.class, priority); } - if (isA(provider, HeaderDelegate.class, contracts)) + if (Utils.isA(provider, HeaderDelegate.class, contracts)) { Type[] headerTypes = Types.getActualTypeArgumentsOfAnInterface(provider.getClass(), HeaderDelegate.class); if (headerTypes.length == 0) @@ -1989,17 +1127,25 @@ public ExceptionMapper getExceptionMapper(Class type { Class exceptionType = type; SortedKey mapper = null; + Map, SortedKey> mappers = getSortedExceptionMappers(); while (mapper == null) { if (exceptionType == null) break; - mapper = getSortedExceptionMappers().get(exceptionType); + mapper = mappers.get(exceptionType); if (mapper == null) exceptionType = exceptionType.getSuperclass(); } return mapper != null ? mapper.getObj() : null; } + public ExceptionMapper getExceptionMapperForClass(Class type) + { + Map, SortedKey> mappers = getSortedExceptionMappers(); + SortedKey mapper = mappers.get(type); + return mapper != null ? mapper.getObj() : null; + } + // @Override public AsyncResponseProvider getAsyncResponseProvider(Class type) { @@ -2053,9 +1199,9 @@ public MediaType getConcreteMediaTypeFromMessageBodyWriters(Class type, Type List> writers = getServerMessageBodyWriters().getPossible(mediaType, type); for (SortedKey writer : writers) { - if (writer.obj.isWriteable(type, genericType, annotations, mediaType)) + if (writer.getObj().isWriteable(type, genericType, annotations, mediaType)) { - MessageBodyWriter mbw = writer.obj; + MessageBodyWriter mbw = writer.getObj(); Class writerType = Types.getTemplateParameterOfInterface(mbw.getClass(), MessageBodyWriter.class); if (writerType == null || writerType.equals(Object.class) || !writerType.isAssignableFrom(type)) continue; @@ -2081,9 +1227,9 @@ public Map, Class> getPossibleMessageBodyWritersMap(Clas List> writers = getServerMessageBodyWriters().getPossible(accept, type); for (SortedKey writer : writers) { - if (writer.obj.isWriteable(type, genericType, annotations, accept)) + if (writer.getObj().isWriteable(type, genericType, annotations, accept)) { - Class mbwc = writer.obj.getClass(); + Class mbwc = writer.getObj().getClass(); if (!mbwc.isInterface() && mbwc.getSuperclass() != null && !mbwc.getSuperclass().equals(Object.class) && mbwc.isSynthetic()) { @@ -2092,7 +1238,7 @@ public Map, Class> getPossibleMessageBodyWritersMap(Clas Class writerType = Types.getTemplateParameterOfInterface(mbwc, MessageBodyWriter.class); if (writerType == null || !writerType.isAssignableFrom(type)) continue; - map.put(writer.obj, writerType); + map.put(writer.getObj(), writerType); } } return map; @@ -2164,17 +1310,17 @@ private MessageBodyWriter resolveMessageBodyWriter(Class type, Type ge for (SortedKey writer : writers) { - if (writer.obj.isWriteable(type, genericType, annotations, mediaType)) + if (writer.getObj().isWriteable(type, genericType, annotations, mediaType)) { LogMessages.LOGGER.debugf("MessageBodyWriter: %s", writer.getClass().getName()); //logger.info(" picking: " + writer.obj.getClass().getName()); - return (MessageBodyWriter) writer.obj; + return (MessageBodyWriter) writer.getObj(); } } return null; } - protected MessageBodyWriter resolveMessageBodyWriter(Class type, Type genericType, + private MessageBodyWriter resolveMessageBodyWriter(Class type, Type genericType, Annotation[] annotations, MediaType mediaType, MediaTypeMap> availableWriters, RESTEasyTracingLogger tracingLogger) { @@ -2194,10 +1340,10 @@ protected MessageBodyWriter resolveMessageBodyWriter(Class type, Type while (iterator.hasNext()) { final SortedKey writer = iterator.next(); - if (writer.obj.isWriteable(type, genericType, annotations, mediaType)) + if (writer.getObj().isWriteable(type, genericType, annotations, mediaType)) { LogMessages.LOGGER.debugf("MessageBodyWriter: %s", writer.getClass().getName()); - result = (MessageBodyWriter) writer.obj; + result = (MessageBodyWriter) writer.getObj(); tracingLogger.log("MBW_SELECTED", result); break; } @@ -2209,7 +1355,7 @@ protected MessageBodyWriter resolveMessageBodyWriter(Class type, Type while (iterator.hasNext()) { final SortedKey writer = iterator.next(); - tracingLogger.log("MBW_SKIPPED", writer.obj); + tracingLogger.log("MBW_SKIPPED", writer.getObj()); } } return result; @@ -2264,21 +1410,7 @@ public T getContext(Class type) */ public T createProviderInstance(Class clazz) { - ConstructorInjector constructorInjector = createConstructorInjector(clazz); - - T provider = (T) constructorInjector.construct(false).toCompletableFuture().getNow(null); - return provider; - } - - private ConstructorInjector createConstructorInjector(Class clazz) - { - Constructor constructor = PickConstructor.pickSingletonConstructor(clazz); - if (constructor == null) - { - throw new IllegalArgumentException( - Messages.MESSAGES.unableToFindPublicConstructorForProvider(clazz.getName())); - } - return getInjectorFactory().createConstructor(constructor, this); + return Utils.createProviderInstance(this, clazz); } /** @@ -2326,24 +1458,6 @@ public T injectedInstance(Class clazz, HttpRequest request, Htt return (T) obj; } - private void injectProperties(Class declaring, Object obj) - { - getInjectorFactory().createPropertyInjector(declaring, this).inject(obj, false).toCompletableFuture() - .getNow(null); - } - - public void injectProperties(Object obj) - { - getInjectorFactory().createPropertyInjector(obj.getClass(), this).inject(obj, false).toCompletableFuture() - .getNow(null); - } - - public void injectProperties(Object obj, HttpRequest request, HttpResponse response) - { - getInjectorFactory().createPropertyInjector(obj.getClass(), this).inject(request, response, obj, false) - .toCompletableFuture().getNow(null); - } - // Configurable public Map getMutableProperties() { @@ -2586,7 +1700,7 @@ public Set getInstances() @Override public Link.Builder createLinkBuilder() { - return new LinkBuilderImpl(); + return Utils.createLinkBuilder(); } public RxInvokerProvider getRxInvokerProvider(Class clazz) @@ -2607,17 +1721,12 @@ public RxInvokerProvider getRxInvokerProvider(Class public RxInvokerProvider getRxInvokerProviderFromReactiveClass(Class clazz) { - Class rxInvokerProviderClass = reactiveClasses.get(clazz); - if (rxInvokerProviderClass != null) - { - return createProviderInstance(rxInvokerProviderClass); - } - return null; + return clientHelper.getRxInvokerProviderFromReactiveClass(clazz); } public boolean isReactive(Class clazz) { - return reactiveClasses.keySet().contains(clazz); + return clientHelper.isReactive(clazz); } private void addResourceClassProcessor(Class processorClass, int priority) @@ -2641,11 +1750,18 @@ public T getContextData(Class type) return ResteasyContext.getContextData(type); } - @Override public void initializeClientProviders(ResteasyProviderFactory factory) { - clientRequestFilterRegistry = factory == null ? new ClientRequestFilterRegistryImpl(this) : factory.getClientRequestFilterRegistry().clone(this); - clientResponseFilters = factory == null ? new ClientResponseFilterRegistryImpl(this) : factory.getClientResponseFilters().clone(this); + clientHelper.initializeClientProviders(factory); + } + + public void injectProperties(Object obj) + { + Utils.injectProperties(this, obj); } + public void injectProperties(Object obj, HttpRequest request, HttpResponse response) + { + Utils.injectProperties(this, obj, request, response); + } } diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/ServerHelper.java b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/ServerHelper.java new file mode 100644 index 00000000000..38397f7487b --- /dev/null +++ b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/ServerHelper.java @@ -0,0 +1,537 @@ +package org.jboss.resteasy.core.providerfactory; + +import java.lang.reflect.Type; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; + +import javax.ws.rs.ConstrainedTo; +import javax.ws.rs.Consumes; +import javax.ws.rs.Produces; +import javax.ws.rs.RuntimeType; +import javax.ws.rs.container.ContainerRequestFilter; +import javax.ws.rs.container.ContainerResponseFilter; +import javax.ws.rs.container.DynamicFeature; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.ext.MessageBodyReader; +import javax.ws.rs.ext.MessageBodyWriter; +import javax.ws.rs.ext.ReaderInterceptor; +import javax.ws.rs.ext.WriterInterceptor; + +import org.jboss.resteasy.core.MediaTypeMap; +import org.jboss.resteasy.core.interception.jaxrs.ContainerRequestFilterRegistryImpl; +import org.jboss.resteasy.core.interception.jaxrs.ContainerResponseFilterRegistryImpl; +import org.jboss.resteasy.core.interception.jaxrs.ReaderInterceptorRegistryImpl; +import org.jboss.resteasy.core.interception.jaxrs.WriterInterceptorRegistryImpl; +import org.jboss.resteasy.resteasy_jaxrs.i18n.Messages; +import org.jboss.resteasy.spi.AsyncResponseProvider; +import org.jboss.resteasy.spi.AsyncStreamProvider; +import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.jboss.resteasy.spi.interception.JaxrsInterceptorRegistry; +import org.jboss.resteasy.spi.util.Types; + +/** + * + */ +@SuppressWarnings({"rawtypes", "unchecked"}) +public class ServerHelper +{ + private final ResteasyProviderFactoryImpl rpf; + private MediaTypeMap> serverMessageBodyReaders; + private MediaTypeMap> serverMessageBodyWriters; + private JaxrsInterceptorRegistry containerRequestFilterRegistry; + private JaxrsInterceptorRegistry containerResponseFilterRegistry; + private JaxrsInterceptorRegistry serverReaderInterceptorRegistry; + private JaxrsInterceptorRegistry serverWriterInterceptorRegistry; + private Set serverDynamicFeatures; + private Map, AsyncResponseProvider> asyncResponseProviders; + private Map, AsyncStreamProvider> asyncStreamProviders; + + public ServerHelper(final ResteasyProviderFactoryImpl rpf) + { + this.rpf = rpf; + } + + protected void initialize(ResteasyProviderFactoryImpl parent) + { + serverDynamicFeatures = parent == null ? new CopyOnWriteArraySet<>() : new CopyOnWriteArraySet<>(parent.getServerDynamicFeatures()); + asyncResponseProviders = parent == null ? new ConcurrentHashMap<>(4) : new ConcurrentHashMap<>(parent.getAsyncResponseProviders()); + asyncStreamProviders = parent == null ? new ConcurrentHashMap<>(4) : new ConcurrentHashMap<>(parent.getAsyncStreamProviders()); + + serverMessageBodyReaders = parent == null ? new MediaTypeMap<>() : parent.getServerMessageBodyReaders().clone(); + serverMessageBodyWriters = parent == null ? new MediaTypeMap<>() : parent.getServerMessageBodyWriters().clone(); + containerRequestFilterRegistry = parent == null ? new ContainerRequestFilterRegistryImpl(rpf) : parent.getContainerRequestFilterRegistry().clone(rpf); + containerResponseFilterRegistry = parent == null ? new ContainerResponseFilterRegistryImpl(rpf) : parent.getContainerResponseFilterRegistry().clone(rpf); + serverReaderInterceptorRegistry = parent == null ? new ReaderInterceptorRegistryImpl(rpf) : parent.getServerReaderInterceptorRegistry().clone(rpf); + serverWriterInterceptorRegistry = parent == null ? new WriterInterceptorRegistryImpl(rpf) : parent.getServerWriterInterceptorRegistry().clone(rpf); + } + + protected JaxrsInterceptorRegistry getServerReaderInterceptorRegistry(ResteasyProviderFactory parent) + { + if (serverReaderInterceptorRegistry == null && parent != null) + return parent.getServerReaderInterceptorRegistry(); + return serverReaderInterceptorRegistry; + } + + protected JaxrsInterceptorRegistry getServerWriterInterceptorRegistry(ResteasyProviderFactory parent) + { + if (serverWriterInterceptorRegistry == null && parent != null) + return parent.getServerWriterInterceptorRegistry(); + return serverWriterInterceptorRegistry; + } + + protected JaxrsInterceptorRegistry getContainerRequestFilterRegistry(ResteasyProviderFactory parent) + { + if (containerRequestFilterRegistry == null && parent != null) + return parent.getContainerRequestFilterRegistry(); + return containerRequestFilterRegistry; + } + + protected JaxrsInterceptorRegistry getContainerResponseFilterRegistry(ResteasyProviderFactory parent) + { + if (containerResponseFilterRegistry == null && parent != null) + return parent.getContainerResponseFilterRegistry(); + return containerResponseFilterRegistry; + } + + protected Set getServerDynamicFeatures(ResteasyProviderFactory parent) + { + if (serverDynamicFeatures == null && parent != null) + return parent.getServerDynamicFeatures(); + return serverDynamicFeatures; + } + + protected Map, AsyncResponseProvider> getAsyncResponseProviders(ResteasyProviderFactory parent) + { + if (asyncResponseProviders == null && parent != null) + return parent.getAsyncResponseProviders(); + return asyncResponseProviders; + } + + protected Map, AsyncStreamProvider> getAsyncStreamProviders(ResteasyProviderFactory parent) + { + if (asyncStreamProviders == null && parent != null) + return parent.getAsyncStreamProviders(); + return asyncStreamProviders; + } + + protected void processProviderContracts(Class provider, Integer priorityOverride, boolean isBuiltin, + Map, Integer> contracts, Map, Integer> newContracts, ResteasyProviderFactoryImpl parent) + { + if (Utils.isA(provider, MessageBodyReader.class, contracts)) + { + try + { + int priority = Utils.getPriority(priorityOverride, contracts, MessageBodyReader.class, provider); + addMessageBodyReader(Utils.createProviderInstance(rpf, (Class) provider), provider, + priority, isBuiltin, parent); + newContracts.put(MessageBodyReader.class, priority); + } + catch (Exception e) + { + throw new RuntimeException(Messages.MESSAGES.unableToInstantiateMessageBodyReader(), e); + } + } + if (Utils.isA(provider, MessageBodyWriter.class, contracts)) + { + try + { + int priority = Utils.getPriority(priorityOverride, contracts, MessageBodyWriter.class, provider); + addMessageBodyWriter(Utils.createProviderInstance(rpf, (Class) provider), provider, + priority, isBuiltin, parent); + newContracts.put(MessageBodyWriter.class, priority); + } + catch (Exception e) + { + throw new RuntimeException(Messages.MESSAGES.unableToInstantiateMessageBodyWriter(), e); + } + } + if (Utils.isA(provider, ContainerRequestFilter.class, contracts)) + { + if (containerRequestFilterRegistry == null) + { + containerRequestFilterRegistry = parent.getContainerRequestFilterRegistry().clone(rpf); + } + int priority = Utils.getPriority(priorityOverride, contracts, ContainerRequestFilter.class, provider); + containerRequestFilterRegistry.registerClass(provider, priority); + newContracts.put(ContainerRequestFilter.class, priority); + } + if (Utils.isA(provider, ContainerResponseFilter.class, contracts)) + { + if (containerResponseFilterRegistry == null) + { + containerResponseFilterRegistry = parent.getContainerResponseFilterRegistry().clone(rpf); + } + int priority = Utils.getPriority(priorityOverride, contracts, ContainerResponseFilter.class, provider); + containerResponseFilterRegistry.registerClass(provider, priority); + newContracts.put(ContainerResponseFilter.class, priority); + } + if (Utils.isA(provider, ReaderInterceptor.class, contracts)) + { + ConstrainedTo constrainedTo = (ConstrainedTo) provider.getAnnotation(ConstrainedTo.class); + int priority = Utils.getPriority(priorityOverride, contracts, ReaderInterceptor.class, provider); + if (constrainedTo != null && constrainedTo.value() == RuntimeType.SERVER) + { + if (serverReaderInterceptorRegistry == null) + { + serverReaderInterceptorRegistry = parent.getServerReaderInterceptorRegistry().clone(rpf); + } + serverReaderInterceptorRegistry.registerClass(provider, priority); + } + if (constrainedTo == null) + { + if (serverReaderInterceptorRegistry == null) + { + serverReaderInterceptorRegistry = parent.getServerReaderInterceptorRegistry().clone(rpf); + } + serverReaderInterceptorRegistry.registerClass(provider, priority); + } + newContracts.put(ReaderInterceptor.class, priority); + } + if (Utils.isA(provider, WriterInterceptor.class, contracts)) + { + ConstrainedTo constrainedTo = (ConstrainedTo) provider.getAnnotation(ConstrainedTo.class); + int priority = Utils.getPriority(priorityOverride, contracts, WriterInterceptor.class, provider); + if (constrainedTo != null && constrainedTo.value() == RuntimeType.SERVER) + { + if (serverWriterInterceptorRegistry == null) + { + serverWriterInterceptorRegistry = parent.getServerWriterInterceptorRegistry().clone(rpf); + } + serverWriterInterceptorRegistry.registerClass(provider, priority); + } + if (constrainedTo == null) + { + if (serverWriterInterceptorRegistry == null) + { + serverWriterInterceptorRegistry = parent.getServerWriterInterceptorRegistry().clone(rpf); + } + serverWriterInterceptorRegistry.registerClass(provider, priority); + } + newContracts.put(WriterInterceptor.class, priority); + } + if (Utils.isA(provider, DynamicFeature.class, contracts)) + { + ConstrainedTo constrainedTo = (ConstrainedTo) provider.getAnnotation(ConstrainedTo.class); + int priority = Utils.getPriority(priorityOverride, contracts, DynamicFeature.class, provider); + if (constrainedTo != null && constrainedTo.value() == RuntimeType.SERVER) + { + if (serverDynamicFeatures == null) + { + serverDynamicFeatures = new CopyOnWriteArraySet(parent.getServerDynamicFeatures()); + } + serverDynamicFeatures.add((DynamicFeature) rpf.injectedInstance(provider)); + } + if (constrainedTo == null) + { + if (serverDynamicFeatures == null) + { + serverDynamicFeatures = new CopyOnWriteArraySet(parent.getServerDynamicFeatures()); + } + serverDynamicFeatures.add((DynamicFeature) rpf.injectedInstance(provider)); + } + newContracts.put(DynamicFeature.class, priority); + } + if (Utils.isA(provider, AsyncResponseProvider.class, contracts)) + { + try + { + addAsyncResponseProvider(rpf.createProviderInstance((Class) provider), + provider, parent); + newContracts.put(AsyncResponseProvider.class, + Utils.getPriority(priorityOverride, contracts, AsyncResponseProvider.class, provider)); + } + catch (Exception e) + { + throw new RuntimeException(Messages.MESSAGES.unableToInstantiateAsyncResponseProvider(), e); + } + } + if (Utils.isA(provider, AsyncStreamProvider.class, contracts)) + { + try + { + addAsyncStreamProvider(rpf.createProviderInstance((Class) provider), provider, parent); + newContracts.put(AsyncStreamProvider.class, + Utils.getPriority(priorityOverride, contracts, AsyncStreamProvider.class, provider)); + } + catch (Exception e) + { + throw new RuntimeException(Messages.MESSAGES.unableToInstantiateAsyncStreamProvider(), e); + } + } + + } + + protected void processProviderInstanceContracts(Object provider, Map, Integer> contracts, + Integer priorityOverride, boolean builtIn, Map, Integer> newContracts, ResteasyProviderFactoryImpl parent) + { + if (Utils.isA(provider, MessageBodyReader.class, contracts)) + { + try + { + int priority = Utils.getPriority(priorityOverride, contracts, MessageBodyReader.class, provider.getClass()); + addMessageBodyReader((MessageBodyReader) provider, provider.getClass(), priority, builtIn, parent); + newContracts.put(MessageBodyReader.class, priority); + } + catch (Exception e) + { + throw new RuntimeException(Messages.MESSAGES.unableToInstantiateMessageBodyReader(), e); + } + } + if (Utils.isA(provider, MessageBodyWriter.class, contracts)) + { + try + { + int priority = Utils.getPriority(priorityOverride, contracts, MessageBodyWriter.class, provider.getClass()); + addMessageBodyWriter((MessageBodyWriter) provider, provider.getClass(), priority, builtIn, parent); + newContracts.put(MessageBodyWriter.class, priority); + } + catch (Exception e) + { + throw new RuntimeException(Messages.MESSAGES.unableToInstantiateMessageBodyWriter(), e); + } + } + if (Utils.isA(provider, ContainerRequestFilter.class, contracts)) + { + if (containerRequestFilterRegistry == null) + { + containerRequestFilterRegistry = parent.getContainerRequestFilterRegistry().clone(rpf); + } + int priority = Utils.getPriority(priorityOverride, contracts, ContainerRequestFilter.class, provider.getClass()); + containerRequestFilterRegistry.registerSingleton((ContainerRequestFilter) provider, priority); + newContracts.put(ContainerRequestFilter.class, priority); + } + if (Utils.isA(provider, ContainerResponseFilter.class, contracts)) + { + if (containerResponseFilterRegistry == null) + { + containerResponseFilterRegistry = parent.getContainerResponseFilterRegistry().clone(rpf); + } + int priority = Utils.getPriority(priorityOverride, contracts, ContainerResponseFilter.class, provider.getClass()); + containerResponseFilterRegistry.registerSingleton((ContainerResponseFilter) provider, priority); + newContracts.put(ContainerResponseFilter.class, priority); + } + if (Utils.isA(provider, ReaderInterceptor.class, contracts)) + { + ConstrainedTo constrainedTo = (ConstrainedTo) provider.getClass().getAnnotation(ConstrainedTo.class); + int priority = Utils.getPriority(priorityOverride, contracts, ReaderInterceptor.class, provider.getClass()); + if (constrainedTo != null && constrainedTo.value() == RuntimeType.SERVER) + { + if (serverReaderInterceptorRegistry == null) + { + serverReaderInterceptorRegistry = parent.getServerReaderInterceptorRegistry().clone(rpf); + } + serverReaderInterceptorRegistry.registerSingleton((ReaderInterceptor) provider, priority); + } + if (constrainedTo == null) + { + if (serverReaderInterceptorRegistry == null) + { + serverReaderInterceptorRegistry = parent.getServerReaderInterceptorRegistry().clone(rpf); + } + serverReaderInterceptorRegistry.registerSingleton((ReaderInterceptor) provider, priority); + } + newContracts.put(ReaderInterceptor.class, priority); + } + if (Utils.isA(provider, WriterInterceptor.class, contracts)) + { + ConstrainedTo constrainedTo = (ConstrainedTo) provider.getClass().getAnnotation(ConstrainedTo.class); + int priority = Utils.getPriority(priorityOverride, contracts, WriterInterceptor.class, provider.getClass()); + if (constrainedTo != null && constrainedTo.value() == RuntimeType.SERVER) + { + if (serverWriterInterceptorRegistry == null) + { + serverWriterInterceptorRegistry = parent.getServerWriterInterceptorRegistry().clone(rpf); + } + serverWriterInterceptorRegistry.registerSingleton((WriterInterceptor) provider, priority); + } + if (constrainedTo == null) + { + if (serverWriterInterceptorRegistry == null) + { + serverWriterInterceptorRegistry = parent.getServerWriterInterceptorRegistry().clone(rpf); + } + serverWriterInterceptorRegistry.registerSingleton((WriterInterceptor) provider, priority); + } + newContracts.put(WriterInterceptor.class, priority); + } + if (Utils.isA(provider, DynamicFeature.class, contracts)) + { + ConstrainedTo constrainedTo = (ConstrainedTo) provider.getClass().getAnnotation(ConstrainedTo.class); + int priority = Utils.getPriority(priorityOverride, contracts, DynamicFeature.class, provider.getClass()); + if (constrainedTo != null && constrainedTo.value() == RuntimeType.SERVER) + { + if (serverDynamicFeatures == null) + { + serverDynamicFeatures = new CopyOnWriteArraySet(parent.getServerDynamicFeatures()); + } + serverDynamicFeatures.add((DynamicFeature) provider); + } + if (constrainedTo == null) + { + if (serverDynamicFeatures == null) + { + serverDynamicFeatures = new CopyOnWriteArraySet(parent.getServerDynamicFeatures()); + } + serverDynamicFeatures.add((DynamicFeature) provider); + } + newContracts.put(DynamicFeature.class, priority); + } + if (Utils.isA(provider, AsyncResponseProvider.class, contracts)) + { + try + { + addAsyncResponseProvider((AsyncResponseProvider) provider, provider.getClass(), parent); + int priority = Utils.getPriority(priorityOverride, contracts, AsyncResponseProvider.class, provider.getClass()); + newContracts.put(AsyncResponseProvider.class, priority); + } + catch (Exception e) + { + throw new RuntimeException(Messages.MESSAGES.unableToInstantiateAsyncResponseProvider(), e); + } + } + if (Utils.isA(provider, AsyncStreamProvider.class, contracts)) + { + try + { + addAsyncStreamProvider((AsyncStreamProvider) provider, provider.getClass(), parent); + int priority = Utils.getPriority(priorityOverride, contracts, AsyncStreamProvider.class, provider.getClass()); + newContracts.put(AsyncStreamProvider.class, priority); + } + catch (Exception e) + { + throw new RuntimeException(Messages.MESSAGES.unableToInstantiateAsyncStreamProvider(), e); + } + } + } + + protected MediaTypeMap> getServerMessageBodyReaders(ResteasyProviderFactoryImpl parent) + { + if (serverMessageBodyReaders == null && parent != null) + return parent.getServerMessageBodyReaders(); + return serverMessageBodyReaders; + } + + protected MediaTypeMap> getServerMessageBodyWriters(ResteasyProviderFactoryImpl parent) + { + if (serverMessageBodyWriters == null && parent != null) + return parent.getServerMessageBodyWriters(); + return serverMessageBodyWriters; + } + + protected void addMessageBodyReader(MessageBodyReader provider, Class providerClass, int priority, + boolean isBuiltin, ResteasyProviderFactoryImpl parent) + { + SortedKey key = new SortedKey(MessageBodyReader.class, provider, + providerClass, priority, isBuiltin); + Utils.injectProperties(rpf, providerClass, provider); + Consumes consumeMime = provider.getClass().getAnnotation(Consumes.class); + RuntimeType type = null; + ConstrainedTo constrainedTo = providerClass.getAnnotation(ConstrainedTo.class); + if (constrainedTo != null) + type = constrainedTo.value(); + + if ((type == null || type == RuntimeType.SERVER) && serverMessageBodyReaders == null) + { + serverMessageBodyReaders = parent.getServerMessageBodyReaders().clone(); + } + if (consumeMime != null) + { + for (String consume : consumeMime.value()) + { + if (type == null) + { + serverMessageBodyReaders.add(MediaType.valueOf(consume), key); + } + else if (type == RuntimeType.SERVER) + { + serverMessageBodyReaders.add(MediaType.valueOf(consume), key); + } + } + } + else + { + if (type == null) + { + serverMessageBodyReaders.add(new MediaType("*", "*"), key); + } + else if (type == RuntimeType.SERVER) + { + serverMessageBodyReaders.add(new MediaType("*", "*"), key); + } + } + } + + protected void addMessageBodyWriter(MessageBodyWriter provider, Class providerClass, int priority, + boolean isBuiltin, ResteasyProviderFactoryImpl parent) + { + Utils.injectProperties(rpf, providerClass, provider); + Produces consumeMime = provider.getClass().getAnnotation(Produces.class); + SortedKey key = new SortedKey(MessageBodyWriter.class, provider, + providerClass, priority, isBuiltin); + RuntimeType type = null; + ConstrainedTo constrainedTo = providerClass.getAnnotation(ConstrainedTo.class); + if (constrainedTo != null) + type = constrainedTo.value(); + + if ((type == null || type == RuntimeType.SERVER) && serverMessageBodyWriters == null) + { + serverMessageBodyWriters = parent.getServerMessageBodyWriters().clone(); + } + if (consumeMime != null) + { + for (String consume : consumeMime.value()) + { + //logger.info(">>> Adding provider: " + provider.getClass().getName() + " with mime type of: " + mime); + if (type == null) + { + serverMessageBodyWriters.add(MediaType.valueOf(consume), key); + } + else if (type == RuntimeType.SERVER) + { + serverMessageBodyWriters.add(MediaType.valueOf(consume), key); + } + } + } + else + { + //logger.info(">>> Adding provider: " + provider.getClass().getName() + " with mime type of: default */*"); + if (type == null) + { + serverMessageBodyWriters.add(new MediaType("*", "*"), key); + } + else if (type == RuntimeType.SERVER) + { + serverMessageBodyWriters.add(new MediaType("*", "*"), key); + } + } + } + + private void addAsyncResponseProvider(AsyncResponseProvider provider, Class providerClass, ResteasyProviderFactory parent) + { + Type asyncType = Types.getActualTypeArgumentsOfAnInterface(providerClass, AsyncResponseProvider.class)[0]; + Utils.injectProperties(rpf, provider.getClass(), provider); + Class asyncClass = Types.getRawType(asyncType); + if (asyncResponseProviders == null) + { + asyncResponseProviders = new ConcurrentHashMap, AsyncResponseProvider>(); + asyncResponseProviders.putAll(parent.getAsyncResponseProviders()); + } + asyncResponseProviders.put(asyncClass, provider); + } + + private void addAsyncStreamProvider(AsyncStreamProvider provider, Class providerClass, ResteasyProviderFactory parent) + { + Type asyncType = Types.getActualTypeArgumentsOfAnInterface(providerClass, AsyncStreamProvider.class)[0]; + Utils.injectProperties(rpf, provider.getClass(), provider); + Class asyncClass = Types.getRawType(asyncType); + if (asyncStreamProviders == null) + { + asyncStreamProviders = new ConcurrentHashMap, AsyncStreamProvider>(); + asyncStreamProviders.putAll(parent.getAsyncStreamProviders()); + } + asyncStreamProviders.put(asyncClass, provider); + } + +} diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/SortedKey.java b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/SortedKey.java new file mode 100644 index 00000000000..403396ae062 --- /dev/null +++ b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/SortedKey.java @@ -0,0 +1,77 @@ +package org.jboss.resteasy.core.providerfactory; + +import javax.ws.rs.Priorities; + +import org.jboss.resteasy.core.MediaTypeMap; +import org.jboss.resteasy.spi.util.Types; + +/** + * Allow us to sort message body implementations that are more specific for their types + * i.e. MessageBodyWriter<Object> is less specific than MessageBodyWriter<String>. + *

+ * This helps out a lot when the desired media type is a wildcard and to weed out all the possible + * default mappings. + */ +public class SortedKey implements Comparable>, MediaTypeMap.Typed +{ + private final T obj; + private final boolean isBuiltin; + private final Class template; + private final int priority; + + public SortedKey(final Class intf, final T reader, final Class readerClass, final int priority, final boolean isBuiltin) + { + this.obj = reader; + // check the super class for the generic type 1st + Class t = Types.getTemplateParameterOfInterface(readerClass, intf); + template = (t != null) ? t : Object.class; + this.priority = priority; + this.isBuiltin = isBuiltin; + } + + public SortedKey(final Class intf, final T reader, final Class readerClass, final boolean isBuiltin) + { + this(intf, reader, readerClass, Priorities.USER, isBuiltin); + } + + public SortedKey(final Class intf, final T reader, final Class readerClass) + { + this(intf, reader, readerClass, Priorities.USER, false); + } + + public int compareTo(SortedKey tMessageBodyKey) + { + // Sort user provider before builtins + if (this == tMessageBodyKey) + return 0; + if (isBuiltin == tMessageBodyKey.isBuiltin) + { + if (this.priority < tMessageBodyKey.priority) + { + return -1; + } + if (this.priority == tMessageBodyKey.priority) + { + return 0; + } + if (this.priority > tMessageBodyKey.priority) + { + return 1; + } + } + if (isBuiltin) + return 1; + else + return -1; + } + + public Class getType() + { + return template; + } + + public T getObj() + { + return obj; + } +} diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/Utils.java b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/Utils.java new file mode 100644 index 00000000000..1b27efc2bf7 --- /dev/null +++ b/resteasy-core/src/main/java/org/jboss/resteasy/core/providerfactory/Utils.java @@ -0,0 +1,164 @@ +package org.jboss.resteasy.core.providerfactory; + +import java.lang.reflect.Constructor; +import java.util.Map; + +import javax.annotation.Priority; +import javax.ws.rs.Priorities; +import javax.ws.rs.core.Link; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.UriBuilder; +import javax.ws.rs.core.Variant; +import javax.ws.rs.ext.RuntimeDelegate.HeaderDelegate; + +import org.jboss.resteasy.resteasy_jaxrs.i18n.Messages; +import org.jboss.resteasy.specimpl.LinkBuilderImpl; +import org.jboss.resteasy.specimpl.ResponseBuilderImpl; +import org.jboss.resteasy.specimpl.ResteasyUriBuilderImpl; +import org.jboss.resteasy.specimpl.VariantListBuilderImpl; +import org.jboss.resteasy.spi.ConstructorInjector; +import org.jboss.resteasy.spi.HttpRequest; +import org.jboss.resteasy.spi.HttpResponse; +import org.jboss.resteasy.spi.ResteasyProviderFactory; +import org.jboss.resteasy.spi.util.PickConstructor; + +@SuppressWarnings({"rawtypes", "unchecked"}) +public final class Utils +{ + private Utils() { + } + + static boolean isA(Class target, Class type, Map, Integer> contracts) + { + if (!type.isAssignableFrom(target)) + return false; + if (contracts == null || contracts.size() == 0) + return true; + for (Class contract : contracts.keySet()) + { + if (contract.equals(type)) + return true; + } + return false; + } + + static boolean isA(Object target, Class type, Map, Integer> contracts) + { + return isA(target.getClass(), type, contracts); + } + + static int getPriority(Integer override, Map, Integer> contracts, Class type, Class component) + { + if (override != null) + return override; + if (contracts != null) + { + Integer p = contracts.get(type); + if (p != null) + return p; + } + // Check for weld proxy. + component = component.isSynthetic() ? component.getSuperclass() : component; + Priority priority = component.getAnnotation(Priority.class); + if (priority == null) + return Priorities.USER; + return priority.value(); + } + + static void injectProperties(ResteasyProviderFactory rpf, Class declaring, Object obj) + { + rpf.getInjectorFactory().createPropertyInjector(declaring, rpf).inject(obj, false).toCompletableFuture() + .getNow(null); + } + + static void injectProperties(ResteasyProviderFactory rpf, Object obj) + { + rpf.getInjectorFactory().createPropertyInjector(obj.getClass(), rpf).inject(obj, false).toCompletableFuture() + .getNow(null); + } + + static void injectProperties(ResteasyProviderFactory rpf, Object obj, HttpRequest request, HttpResponse response) + { + rpf.getInjectorFactory().createPropertyInjector(obj.getClass(), rpf).inject(request, response, obj, false) + .toCompletableFuture().getNow(null); + } + + static T createProviderInstance(ResteasyProviderFactory rpf, Class clazz) + { + ConstructorInjector constructorInjector = createConstructorInjector(rpf, clazz); + + T provider = (T) constructorInjector.construct(false).toCompletableFuture().getNow(null); + return provider; + } + + private static ConstructorInjector createConstructorInjector(ResteasyProviderFactory rpf, Class clazz) + { + Constructor constructor = PickConstructor.pickSingletonConstructor(clazz); + if (constructor == null) + { + throw new IllegalArgumentException( + Messages.MESSAGES.unableToFindPublicConstructorForProvider(clazz.getName())); + } + return rpf.getInjectorFactory().createConstructor(constructor, rpf); + } + + static UriBuilder createUriBuilder() + { + return new ResteasyUriBuilderImpl(); + } + + static Response.ResponseBuilder createResponseBuilder() + { + return new ResponseBuilderImpl(); + } + + static Variant.VariantListBuilder createVariantListBuilder() + { + return new VariantListBuilderImpl(); + } + + static Link.Builder createLinkBuilder() + { + return new LinkBuilderImpl(); + } + + static HeaderDelegate createHeaderDelegate(Map, HeaderDelegate> headerDelegates, Class tClass) + { + Class clazz = tClass; + while (clazz != null) + { + HeaderDelegate delegate = headerDelegates.get(clazz); + if (delegate != null) + { + return delegate; + } + delegate = createHeaderDelegateFromInterfaces(headerDelegates, clazz.getInterfaces()); + if (delegate != null) + { + return delegate; + } + clazz = clazz.getSuperclass(); + } + + return createHeaderDelegateFromInterfaces(headerDelegates, tClass.getInterfaces()); + } + + private static HeaderDelegate createHeaderDelegateFromInterfaces(Map, HeaderDelegate> headerDelegates, Class[] interfaces) + { + HeaderDelegate delegate = null; + for (int i = 0; i < interfaces.length; i++) + { + delegate = headerDelegates.get(interfaces[i]); + if (delegate != null) + { + return delegate; + } + delegate = createHeaderDelegateFromInterfaces(headerDelegates, interfaces[i].getInterfaces()); + if (delegate != null) + { + return delegate; + } + } + return null; + } +} diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/mock/MockDispatcherFactory.java b/resteasy-core/src/main/java/org/jboss/resteasy/mock/MockDispatcherFactory.java index 208bad51be1..980b632a4da 100644 --- a/resteasy-core/src/main/java/org/jboss/resteasy/mock/MockDispatcherFactory.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/mock/MockDispatcherFactory.java @@ -1,7 +1,7 @@ package org.jboss.resteasy.mock; -import org.jboss.resteasy.core.ResteasyProviderFactoryImpl; import org.jboss.resteasy.core.SynchronousDispatcher; +import org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl; import org.jboss.resteasy.plugins.providers.RegisterBuiltin; import org.jboss.resteasy.spi.Dispatcher; import org.jboss.resteasy.spi.ResteasyProviderFactory; diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/CacheControlDelegate.java b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/CacheControlDelegate.java index 436e7b7c129..3fd0514dcc8 100644 --- a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/CacheControlDelegate.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/CacheControlDelegate.java @@ -14,6 +14,8 @@ */ public class CacheControlDelegate implements RuntimeDelegate.HeaderDelegate { + public static final CacheControlDelegate INSTANCE = new CacheControlDelegate(); + public CacheControl fromString(String value) throws IllegalArgumentException { if (value == null) throw new IllegalArgumentException(Messages.MESSAGES.cacheControlValueNull()); diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/CookieHeaderDelegate.java b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/CookieHeaderDelegate.java index e09db812810..48c77ebe073 100755 --- a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/CookieHeaderDelegate.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/CookieHeaderDelegate.java @@ -10,7 +10,7 @@ */ public class CookieHeaderDelegate implements RuntimeDelegate.HeaderDelegate { - + public static final CookieHeaderDelegate INSTANCE = new CookieHeaderDelegate(); public Cookie fromString(String value) throws IllegalArgumentException { return CookieParser.parseCookies(value).get(0); diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/DateDelegate.java b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/DateDelegate.java index 068c0028812..105618b1146 100644 --- a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/DateDelegate.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/DateDelegate.java @@ -13,6 +13,8 @@ */ public class DateDelegate implements RuntimeDelegate.HeaderDelegate { + public static final DateDelegate INSTANCE = new DateDelegate(); + @Override public Date fromString(String value) { diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/EntityTagDelegate.java b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/EntityTagDelegate.java index 8db9b14b2ca..86eb06837c4 100644 --- a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/EntityTagDelegate.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/EntityTagDelegate.java @@ -11,6 +11,8 @@ */ public class EntityTagDelegate implements RuntimeDelegate.HeaderDelegate { + public static final EntityTagDelegate INSTANCE = new EntityTagDelegate(); + public EntityTag fromString(String value) throws IllegalArgumentException { if (value == null) throw new IllegalArgumentException(Messages.MESSAGES.entityTagValueNull()); diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/LinkDelegate.java b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/LinkDelegate.java index 1cfeb7ef667..32cd4139ad4 100644 --- a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/LinkDelegate.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/LinkDelegate.java @@ -16,6 +16,8 @@ */ public class LinkDelegate implements RuntimeDelegate.HeaderDelegate { + public static final LinkDelegate INSTANCE = new LinkDelegate(); + private static class Parser { private int curr; diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/LinkHeaderDelegate.java b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/LinkHeaderDelegate.java index 32f7837edac..46c147223d8 100644 --- a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/LinkHeaderDelegate.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/LinkHeaderDelegate.java @@ -20,6 +20,8 @@ */ public class LinkHeaderDelegate implements RuntimeDelegate.HeaderDelegate { + public static final LinkHeaderDelegate INSTANCE = new LinkHeaderDelegate(); + private static class Parser { private int curr; diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/LocaleDelegate.java b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/LocaleDelegate.java index 06493db9556..ac53c6c191d 100644 --- a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/LocaleDelegate.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/LocaleDelegate.java @@ -13,6 +13,8 @@ */ public class LocaleDelegate implements RuntimeDelegate.HeaderDelegate { + public static final LocaleDelegate INSTANCE = new LocaleDelegate(); + public Locale fromString(String value) throws IllegalArgumentException { if (value == null) throw new IllegalArgumentException(Messages.MESSAGES.localeValueNull()); diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/MediaTypeHeaderDelegate.java b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/MediaTypeHeaderDelegate.java index 010bdf687a3..ccf08a46224 100755 --- a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/MediaTypeHeaderDelegate.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/MediaTypeHeaderDelegate.java @@ -7,6 +7,8 @@ import javax.ws.rs.ext.RuntimeDelegate; import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; /** * @author Bill Burke @@ -14,6 +16,13 @@ */ public class MediaTypeHeaderDelegate implements RuntimeDelegate.HeaderDelegate { + public static final MediaTypeHeaderDelegate INSTANCE = new MediaTypeHeaderDelegate(); + + private static Map map = new ConcurrentHashMap(); + private static Map reverseMap = new ConcurrentHashMap(); + private static final int MAX_MT_CACHE_SIZE = + Integer.getInteger("org.jboss.resteasy.max_mediatype_cache_size", 200); + public Object fromString(String type) throws IllegalArgumentException { if (type == null) throw new IllegalArgumentException(Messages.MESSAGES.mediaTypeValueNull()); @@ -49,6 +58,22 @@ protected static boolean isValid(String str) } public static MediaType parse(String type) + { + MediaType result = map.get(type); + if (result == null) { + result = internalParse(type); + final int size = map.size(); + if (size >= MAX_MT_CACHE_SIZE) { + map.clear(); + reverseMap.clear(); + } + map.put(type, result); + reverseMap.put(result, type); + } + return result; + } + + private static MediaType internalParse(String type) { int typeIndex = type.indexOf('/'); int paramIndex = type.indexOf(';'); @@ -125,6 +150,22 @@ public String toString(Object o) { if (o == null) throw new IllegalArgumentException(Messages.MESSAGES.paramNull()); MediaType type = (MediaType) o; + String result = reverseMap.get(type); + if (result == null) { + result = internalToString(type); + final int size = reverseMap.size(); + if (size >= MAX_MT_CACHE_SIZE) { + reverseMap.clear(); + map.clear(); + } + reverseMap.put(type, result); + map.put(result, type); + } + return result; + } + + private String internalToString(MediaType type) + { StringBuilder buf = new StringBuilder(); buf.append(type.getType().toLowerCase()).append("/").append(type.getSubtype().toLowerCase()); diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/NewCookieHeaderDelegate.java b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/NewCookieHeaderDelegate.java index ed08adeac97..30d77ad62e8 100755 --- a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/NewCookieHeaderDelegate.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/NewCookieHeaderDelegate.java @@ -18,6 +18,7 @@ * @version $Revision: 1 $ */ public class NewCookieHeaderDelegate implements RuntimeDelegate.HeaderDelegate { + public static final NewCookieHeaderDelegate INSTANCE = new NewCookieHeaderDelegate(); private static final String OLD_COOKIE_PATTERN = "EEE, dd-MMM-yyyy HH:mm:ss z"; public Object fromString(String newCookie) throws IllegalArgumentException { diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/UriHeaderDelegate.java b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/UriHeaderDelegate.java index b23bc14cc8e..1eb2bfe3917 100644 --- a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/UriHeaderDelegate.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/delegates/UriHeaderDelegate.java @@ -12,6 +12,8 @@ */ public class UriHeaderDelegate implements RuntimeDelegate.HeaderDelegate { + public static final UriHeaderDelegate INSTANCE = new UriHeaderDelegate(); + public Object fromString(String value) throws IllegalArgumentException { if (value == null) throw new IllegalArgumentException(Messages.MESSAGES.uriValueNull()); diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/providers/RegisterBuiltin.java b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/providers/RegisterBuiltin.java index 8fc9660670c..c1e88e21a3e 100644 --- a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/providers/RegisterBuiltin.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/providers/RegisterBuiltin.java @@ -14,10 +14,15 @@ import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; +import java.util.WeakHashMap; +import javax.ws.rs.RuntimeType; import javax.ws.rs.ext.Providers; import org.jboss.resteasy.core.ThreadLocalResteasyProviderFactory; +import org.jboss.resteasy.core.providerfactory.ClientHelper; +import org.jboss.resteasy.core.providerfactory.NOOPServerHelper; +import org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl; import org.jboss.resteasy.plugins.interceptors.AcceptEncodingGZIPFilter; import org.jboss.resteasy.plugins.interceptors.GZIPDecodingInterceptor; import org.jboss.resteasy.plugins.interceptors.GZIPEncodingInterceptor; @@ -30,6 +35,39 @@ */ public class RegisterBuiltin { + private static final Map configuredClientFactories = new WeakHashMap<>(); + private static final boolean gzipForCachedFactories = isGZipEnabled(); + + public static synchronized ResteasyProviderFactory getClientInitializedResteasyProviderFactory(ClassLoader cl) + { + ResteasyProviderFactory rpf = null; + final boolean gzip = isGZipEnabled(); + if (gzipForCachedFactories == gzip) { + rpf = configuredClientFactories.get(cl); + } + if (rpf == null) { + rpf = new ResteasyProviderFactoryImpl(null, true) { + @Override + public RuntimeType getRuntimeType() + { + return RuntimeType.CLIENT; + } + @Override + protected void initializeUtils() + { + clientHelper = new ClientHelper(this); + serverHelper = NOOPServerHelper.INSTANCE; + } + }; + if (!rpf.isBuiltinsRegistered()) { + register(rpf); + } + if (gzipForCachedFactories == gzip) { + configuredClientFactories.put(cl, rpf); + } + } + return rpf; + } public static void register(ResteasyProviderFactory factory) { @@ -141,18 +179,22 @@ public Class run() throws ClassNotFoundException LogMessages.LOGGER.classNotFoundException(line, entry.getValue(), ex); } } - if (AccessController.doPrivileged(new PrivilegedAction() { + if (isGZipEnabled()) { + factory.registerProvider(AcceptEncodingGZIPFilter.class, true); + factory.registerProvider(GZIPDecodingInterceptor.class, true); + factory.registerProvider(GZIPEncodingInterceptor.class, true); + } + } + + private static boolean isGZipEnabled() { + return AccessController.doPrivileged(new PrivilegedAction() { @Override public Boolean run() { final String value = System.getProperty("resteasy.allowGzip"); if ("".equals(value)) return Boolean.FALSE; return Boolean.parseBoolean(value); } - })) { - factory.registerProvider(AcceptEncodingGZIPFilter.class, true); - factory.registerProvider(GZIPDecodingInterceptor.class, true); - factory.registerProvider(GZIPEncodingInterceptor.class, true); - } + }); } } diff --git a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/providers/sse/InboundSseEventImpl.java b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/providers/sse/InboundSseEventImpl.java index c8ae7305487..2863644ce33 100644 --- a/resteasy-core/src/main/java/org/jboss/resteasy/plugins/providers/sse/InboundSseEventImpl.java +++ b/resteasy-core/src/main/java/org/jboss/resteasy/plugins/providers/sse/InboundSseEventImpl.java @@ -202,7 +202,9 @@ public T readData(GenericType type, MediaType mediaType) else { ResteasyProviderFactory factory = ResteasyProviderFactory.getInstance(); - RegisterBuiltin.register(factory); + if (!factory.isBuiltinsRegistered()) { + RegisterBuiltin.register(factory); + } reader = factory.getClientMessageBodyReader(type.getRawType(), type.getType(), annotations, mediaType); } if (reader == null) diff --git a/resteasy-core/src/main/resources/META-INF/services/javax.ws.rs.ext.RuntimeDelegate b/resteasy-core/src/main/resources/META-INF/services/javax.ws.rs.ext.RuntimeDelegate index a8ec46bb254..68d177c17e5 100644 --- a/resteasy-core/src/main/resources/META-INF/services/javax.ws.rs.ext.RuntimeDelegate +++ b/resteasy-core/src/main/resources/META-INF/services/javax.ws.rs.ext.RuntimeDelegate @@ -1 +1 @@ -org.jboss.resteasy.core.ResteasyProviderFactoryImpl \ No newline at end of file +org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl diff --git a/resteasy-jsapi/src/test/java/org/jboss/resteasy/test/i18n/TestMessagesAbstract.java b/resteasy-jsapi/src/test/java/org/jboss/resteasy/test/i18n/TestMessagesAbstract.java index aa097ad6170..d25d43c7b32 100644 --- a/resteasy-jsapi/src/test/java/org/jboss/resteasy/test/i18n/TestMessagesAbstract.java +++ b/resteasy-jsapi/src/test/java/org/jboss/resteasy/test/i18n/TestMessagesAbstract.java @@ -10,7 +10,7 @@ import org.jboss.resteasy.core.InjectorFactoryImpl; import org.jboss.resteasy.core.ResourceMethodInvoker; -import org.jboss.resteasy.core.ResteasyProviderFactoryImpl; +import org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl; import org.jboss.resteasy.plugins.server.resourcefactory.POJOResourceFactory; import org.jboss.resteasy.jsapi.i18n.Messages; import org.jboss.resteasy.spi.InjectorFactory; diff --git a/security/jose-jwt/src/main/java/org/jboss/resteasy/jwt/JsonSerialization.java b/security/jose-jwt/src/main/java/org/jboss/resteasy/jwt/JsonSerialization.java index 34f8091c27e..4de896cfca8 100644 --- a/security/jose-jwt/src/main/java/org/jboss/resteasy/jwt/JsonSerialization.java +++ b/security/jose-jwt/src/main/java/org/jboss/resteasy/jwt/JsonSerialization.java @@ -12,7 +12,7 @@ import javax.ws.rs.ext.Providers; import org.jboss.resteasy.core.ResteasyContext; -import org.jboss.resteasy.core.ResteasyProviderFactoryImpl; +import org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl; import org.jboss.resteasy.jose.i18n.Messages; import org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider; import org.jboss.resteasy.spi.ResteasyProviderFactory; diff --git a/testsuite/integration-tests/src/test/java/org/jboss/resteasy/test/client/InContainerClientBenchTest.java b/testsuite/integration-tests/src/test/java/org/jboss/resteasy/test/client/InContainerClientBenchTest.java new file mode 100644 index 00000000000..3258ac3591c --- /dev/null +++ b/testsuite/integration-tests/src/test/java/org/jboss/resteasy/test/client/InContainerClientBenchTest.java @@ -0,0 +1,107 @@ +package org.jboss.resteasy.test.client; + +import java.util.concurrent.CountDownLatch; + +import javax.ws.rs.client.Client; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.InvocationCallback; +import javax.ws.rs.client.WebTarget; +import javax.ws.rs.core.Response; + +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.container.test.api.RunAsClient; +import org.jboss.arquillian.junit.Arquillian; +import org.jboss.logging.Logger; +import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; +import javax.ws.rs.client.ClientBuilder; +import org.jboss.resteasy.test.client.resource.AsyncInvokeResource; +import org.jboss.resteasy.test.client.resource.InContainerClientResource; +import org.jboss.resteasy.utils.TestUtil; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.spec.WebArchive; +import org.junit.After; +import org.junit.Assert; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * @tpChapter Client tests + * @tpSubChapter Performances + * @tpTestCaseDetails https://issues.jboss.org/browse/RESTEASY-XYZ + * @tpSince RESTEasy 4.0.0 + */ +@RunWith(Arquillian.class) +@RunAsClient +@Ignore("Not a functional test") +public class InContainerClientBenchTest extends ClientTestBase +{ + + static Client nioClient; + private static Logger log = Logger.getLogger(InContainerClientBenchTest.class); + + static final int ITERATIONS = 4000; + static final int MAX_CONNECTIONS = 40; + + @Deployment + public static Archive deploy() + { + WebArchive war = TestUtil.prepareArchive(InContainerClientBenchTest.class.getSimpleName()); + war.addClass(InContainerClientBenchTest.class); + war.addClass(ClientTestBase.class); + return TestUtil.finishContainerPrepare(war, null, AsyncInvokeResource.class, InContainerClientResource.class); + } + + @After + public void after() throws Exception + { + if (nioClient != null) + nioClient.close(); + } + + @Test + public void testAsyncComposedPost() throws Exception + { + long start = System.currentTimeMillis(); + final String oldProp = System.getProperty("http.maxConnections"); + System.setProperty("http.maxConnections", String.valueOf(MAX_CONNECTIONS)); + nioClient = ((ResteasyClientBuilder)ClientBuilder.newBuilder()).useAsyncHttpEngine().build(); + WebTarget wt = nioClient.target(generateURL("/test-client")); + runCallback(wt, "NIO", "client-post post "); + long end = System.currentTimeMillis() - start; + log.info("TEST COMPOSED NON BLOCKING IO - " + ITERATIONS + " iterations took " + end + "ms"); + if (oldProp != null) + { + System.setProperty("http.maxConnections", oldProp); + } + else + { + System.clearProperty("http.maxConnections"); + } + } + + private void runCallback(WebTarget wt, String msg, String expectedResultPrefix) throws Exception + { + CountDownLatch latch = new CountDownLatch(ITERATIONS); + for (int i = 0; i < ITERATIONS; i++) { + final String m = msg + i; + wt.request().async().post(Entity.text(m), new InvocationCallback() + { + @Override + public void completed(Response response) + { + String entity = response.readEntity(String.class); + Assert.assertEquals("Got: "+ entity, expectedResultPrefix + m, entity); + latch.countDown(); + } + + @Override + public void failed(Throwable error) + { + throw new RuntimeException(error); + } + }); + } + latch.await(); + } +} diff --git a/testsuite/integration-tests/src/test/java/org/jboss/resteasy/test/client/resource/InContainerClientResource.java b/testsuite/integration-tests/src/test/java/org/jboss/resteasy/test/client/resource/InContainerClientResource.java new file mode 100644 index 00000000000..64fcd62af0c --- /dev/null +++ b/testsuite/integration-tests/src/test/java/org/jboss/resteasy/test/client/resource/InContainerClientResource.java @@ -0,0 +1,30 @@ +package org.jboss.resteasy.test.client.resource; + +import javax.ws.rs.Consumes; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.client.Client; +import javax.ws.rs.client.ClientBuilder; +import javax.ws.rs.client.Entity; +import javax.ws.rs.core.Context; +import javax.ws.rs.core.UriInfo; + +@Path("/test-client") +public class InContainerClientResource { + + @Context + private UriInfo uriInfo; + + @POST + @Consumes("text/plain") + public String post(String str) throws Exception { + Client client = ClientBuilder.newClient(); + String result = null; + try { + result = client.target(uriInfo.getBaseUri() + "test").request().post(Entity.text(str)).readEntity(String.class); + } finally { + client.close(); + } + return "client-post " + result; + } +} diff --git a/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/client/ConfigurationInheritanceTest.java b/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/client/ConfigurationInheritanceTest.java index b04f8598c18..c5d12567600 100644 --- a/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/client/ConfigurationInheritanceTest.java +++ b/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/client/ConfigurationInheritanceTest.java @@ -34,7 +34,7 @@ import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; import org.jboss.resteasy.client.jaxrs.internal.ResteasyClientBuilderImpl; -import org.jboss.resteasy.core.ResteasyProviderFactoryImpl; +import org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl; import org.jboss.resteasy.test.client.resource.ConfigurationInheritanceTestFeature1; import org.jboss.resteasy.test.client.resource.ConfigurationInheritanceTestFeature2; import org.jboss.resteasy.test.client.resource.ConfigurationInheritanceTestFeature3; diff --git a/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/providers/HeaderDelegateTest.java b/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/providers/HeaderDelegateTest.java index 334b77488f3..1ecb81b1323 100644 --- a/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/providers/HeaderDelegateTest.java +++ b/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/providers/HeaderDelegateTest.java @@ -2,7 +2,7 @@ import javax.ws.rs.ext.RuntimeDelegate.HeaderDelegate; -import org.jboss.resteasy.core.ResteasyProviderFactoryImpl; +import org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.junit.Assert; import org.junit.Test; diff --git a/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/providers/MultipurtContainsJsonTest.java b/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/providers/MultipurtContainsJsonTest.java index dfd82fcfb8c..577236d5784 100644 --- a/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/providers/MultipurtContainsJsonTest.java +++ b/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/providers/MultipurtContainsJsonTest.java @@ -12,8 +12,8 @@ import javax.ws.rs.ext.Providers; import org.jboss.logging.Logger; -import org.jboss.resteasy.client.jaxrs.internal.LocalResteasyProviderFactory; import org.jboss.resteasy.core.ResteasyContext; +import org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl; import org.jboss.resteasy.plugins.providers.RegisterBuiltin; import org.jboss.resteasy.plugins.providers.multipart.MultipartFormDataOutput; import org.jboss.resteasy.resteasy_jaxrs.i18n.LogMessages; @@ -43,7 +43,7 @@ public static MultipartFormDataOutput getMultipartWithoutJSON() { } public static MessageBodyWriter getWriter() { - ResteasyProviderFactory factory = new LocalResteasyProviderFactory(ResteasyProviderFactory.newInstance()); + ResteasyProviderFactory factory = new ResteasyProviderFactoryImpl(ResteasyProviderFactory.newInstance(), true); RegisterBuiltin.register(factory); factory.registerProviderInstance(new ProviderFactoryPrecendencePlainTextWriter()); factory.registerProviderInstance(new ProviderFactoryPrecedenceIntegerPlainTextWriter()); diff --git a/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/providers/PriorityEqualityTest.java b/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/providers/PriorityEqualityTest.java index 62a1e7a0345..bb3badb51de 100644 --- a/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/providers/PriorityEqualityTest.java +++ b/testsuite/unit-tests/src/test/java/org/jboss/resteasy/test/providers/PriorityEqualityTest.java @@ -10,7 +10,7 @@ import javax.ws.rs.ext.ParamConverterProvider; import javax.ws.rs.ext.Provider; -import org.jboss.resteasy.core.ResteasyProviderFactoryImpl; +import org.jboss.resteasy.core.providerfactory.ResteasyProviderFactoryImpl; import org.jboss.resteasy.plugins.providers.RegisterBuiltin; import org.jboss.resteasy.spi.ResteasyProviderFactory; import org.junit.Assert; @@ -148,7 +148,7 @@ public void testExceptionMappersFromClass() throws Exception { ResteasyProviderFactoryImpl factory = new ResteasyProviderFactoryImpl(); factory.register(ExceptionMapper1.class); factory.register(ExceptionMapper2.class); - Assert.assertEquals(1, factory.getExceptionMappers().size()); + Assert.assertEquals(ExceptionMapper2.class, factory.getExceptionMapper(TestException.class).getClass()); } /** @@ -161,6 +161,6 @@ public void testExceptionObjects() throws Exception { ResteasyProviderFactoryImpl factory = new ResteasyProviderFactoryImpl(); factory.registerProviderInstance(new ExceptionMapper1()); factory.registerProviderInstance(new ExceptionMapper2()); - Assert.assertEquals(1, factory.getExceptionMappers().size()); + Assert.assertEquals(ExceptionMapper2.class, factory.getExceptionMapper(TestException.class).getClass()); } }