Repository: tomee Updated Branches: refs/heads/master 1c961beea -> 7f1ee68c3
TOMEE-1727 caching getSingletons and getClasses calls for jaxrs Project: http://git-wip-us.apache.org/repos/asf/tomee/repo Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/84ede0f2 Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/84ede0f2 Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/84ede0f2 Branch: refs/heads/master Commit: 84ede0f229433d9f8f74a10dcaba7a69afdf12b5 Parents: 1c961be Author: Romain manni-Bucau <rmannibu...@gmail.com> Authored: Tue Mar 8 21:40:40 2016 +0100 Committer: Romain manni-Bucau <rmannibu...@gmail.com> Committed: Tue Mar 8 21:40:40 2016 +0100 ---------------------------------------------------------------------- .../server/cxf/rs/CxfRsHttpListener.java | 68 ++++++++--------- .../server/cxf/rs/SingletonProviderTest.java | 79 ++++++++++++++++++++ .../server/rest/InternalApplication.java | 4 + .../apache/openejb/server/rest/RESTService.java | 15 ++-- 4 files changed, 126 insertions(+), 40 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tomee/blob/84ede0f2/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java ---------------------------------------------------------------------- diff --git a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java index 77a6dd2..1a8d95e 100644 --- a/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java +++ b/server/openejb-cxf-rs/src/main/java/org/apache/openejb/server/cxf/rs/CxfRsHttpListener.java @@ -41,8 +41,6 @@ import org.apache.cxf.message.Message; import org.apache.cxf.service.invoker.Invoker; import org.apache.cxf.transport.DestinationFactory; import org.apache.cxf.transport.servlet.BaseUrlHelper; -import org.apache.johnzon.jaxrs.ConfigurableJohnzonProvider; -import org.apache.johnzon.jaxrs.JohnzonProvider; import org.apache.johnzon.jaxrs.WadlDocumentMessageBodyWriter; import org.apache.openejb.AppContext; import org.apache.openejb.BeanContext; @@ -83,6 +81,24 @@ import org.apache.webbeans.config.WebBeansContext; import org.apache.webbeans.container.BeanManagerImpl; import org.apache.webbeans.context.creational.CreationalContextImpl; +import javax.enterprise.context.spi.CreationalContext; +import javax.enterprise.inject.spi.Bean; +import javax.management.ObjectName; +import javax.management.openmbean.TabularData; +import javax.naming.Context; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import javax.servlet.http.HttpServletResponse; +import javax.ws.rs.ConstrainedTo; +import javax.ws.rs.RuntimeType; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Configuration; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.ext.MessageBodyReader; +import javax.ws.rs.ext.MessageBodyWriter; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -107,24 +123,6 @@ import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import java.util.logging.Level; import java.util.regex.Pattern; -import javax.enterprise.context.spi.CreationalContext; -import javax.enterprise.inject.spi.Bean; -import javax.management.ObjectName; -import javax.management.openmbean.TabularData; -import javax.naming.Context; -import javax.servlet.ServletException; -import javax.servlet.ServletOutputStream; -import javax.servlet.ServletRequest; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletRequestWrapper; -import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.ConstrainedTo; -import javax.ws.rs.RuntimeType; -import javax.ws.rs.core.Application; -import javax.ws.rs.core.Configuration; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.ext.MessageBodyReader; -import javax.ws.rs.ext.MessageBodyWriter; import static java.util.Arrays.asList; import static org.apache.openejb.loader.JarLocation.jarLocation; @@ -146,7 +144,7 @@ public class CxfRsHttpListener implements RsHttpListener { private static final boolean FAIL_ON_CONSTRAINED_TO = "true".equalsIgnoreCase(SystemInstance.get().getProperty("openejb.jaxrs.fail-on-constrainedto", "true")); private static final Map<String, String> STATIC_CONTENT_TYPES; - private static final String[] DEFAULT_WELCOME_FILES = new String[]{ "/index.html", "/index.htm" }; + private static final String[] DEFAULT_WELCOME_FILES = new String[]{"/index.html", "/index.htm"}; private final DestinationFactory transportFactory; private final String wildcard; @@ -159,7 +157,7 @@ public class CxfRsHttpListener implements RsHttpListener { private final Collection<CreationalContext<?>> toRelease = new LinkedHashSet<>(); private final Collection<CdiSingletonResourceProvider> singletons = new LinkedHashSet<>(); - private static final char[] URL_SEP = new char[] { '?', '#', ';' }; + private static final char[] URL_SEP = new char[]{'?', '#', ';'}; static { STATIC_CONTENT_TYPES = new HashMap<>(); @@ -473,7 +471,7 @@ public class CxfRsHttpListener implements RsHttpListener { private static boolean shouldSkipProvider(final String name) { return "false".equalsIgnoreCase(SystemInstance.get().getProperty(name + ".activated", "true")) - || name.startsWith("org.apache.wink.common.internal."); + || name.startsWith("org.apache.wink.common.internal."); } private static void addMandatoryProviders(final Collection<Object> instances) { @@ -556,7 +554,7 @@ public class CxfRsHttpListener implements RsHttpListener { factory.setResourceProvider(clazz, new NoopResourceProvider(restServiceInfo.context.getBeanClass(), proxy)); } else { factory.setResourceProvider(clazz, new OpenEJBPerRequestPojoResourceProvider( - classLoader, clazz, injections, context, owbCtx)); + classLoader, clazz, injections, context, owbCtx)); } } } @@ -572,7 +570,7 @@ public class CxfRsHttpListener implements RsHttpListener { final Object proxy = ProxyEJB.subclassProxy(restServiceInfo.context); factory.setResourceProvider(clazz, new NoopResourceProvider(restServiceInfo.context.getBeanClass(), proxy)); } else { - if (owbCtx.getBeanManagerImpl().isInUse()) { + if (owbCtx != null && owbCtx.getBeanManagerImpl().isInUse()) { final CdiSingletonResourceProvider provider = new CdiSingletonResourceProvider(classLoader, clazz, o, injections, context, owbCtx); singletons.add(provider); factory.setResourceProvider(clazz, provider); @@ -778,7 +776,9 @@ public class CxfRsHttpListener implements RsHttpListener { // effective logging - LOGGER.info("REST Application: " + Logs.forceLength(prefix, addressSize, true) + " -> " + application.getClass().getName()); + LOGGER.info("REST Application: " + Logs.forceLength(prefix, addressSize, true) + " -> " + + (InternalApplication.class.isInstance(application) && InternalApplication.class.cast(application).getOriginal() != null ? + InternalApplication.class.cast(application).getOriginal() : application)); Collections.sort(resourcesToLog); @@ -924,7 +924,7 @@ public class CxfRsHttpListener implements RsHttpListener { } SystemInstance.get().fireEvent(new ExtensionProviderRegistration( - AppFinder.findAppContextOrWeb(Thread.currentThread().getContextClassLoader(), AppFinder.AppContextTransformer.INSTANCE), providers)); + AppFinder.findAppContextOrWeb(Thread.currentThread().getContextClassLoader(), AppFinder.AppContextTransformer.INSTANCE), providers)); if (!providers.isEmpty()) { factory.setProviders(providers); @@ -934,7 +934,7 @@ public class CxfRsHttpListener implements RsHttpListener { private Comparator<?> findProviderComparator(final ServiceConfiguration serviceConfiguration, final WebBeansContext ctx) { final String comparatorKey = CXF_JAXRS_PREFIX + "provider-comparator"; final String comparatorClass = serviceConfiguration.getProperties() - .getProperty(comparatorKey, SystemInstance.get().getProperty(comparatorKey)); + .getProperty(comparatorKey, SystemInstance.get().getProperty(comparatorKey)); Comparator<Object> comparator = null; if (comparatorClass == null) { @@ -1026,8 +1026,8 @@ public class CxfRsHttpListener implements RsHttpListener { final boolean loadersNotNull = classLoader1 != null && classLoader2 != null; if (classLoader1 != classLoader2 - && loadersNotNull - && !classLoader1.equals(classLoader2) && !classLoader2.equals(classLoader1)) { + && loadersNotNull + && !classLoader1.equals(classLoader2) && !classLoader2.equals(classLoader1)) { if (isParent(classLoader1, classLoader2)) { return 1; } @@ -1042,9 +1042,9 @@ public class CxfRsHttpListener implements RsHttpListener { if (MessageBodyWriter.class.isInstance(o1.getProvider())) { final List<MediaType> types1 = - JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderProduceTypes(MessageBodyWriter.class.cast(o1.getProvider())), JAXRSUtils.MEDIA_TYPE_QS_PARAM); + JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderProduceTypes(MessageBodyWriter.class.cast(o1.getProvider())), JAXRSUtils.MEDIA_TYPE_QS_PARAM); final List<MediaType> types2 = - JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderProduceTypes(MessageBodyWriter.class.cast(o2.getProvider())), JAXRSUtils.MEDIA_TYPE_QS_PARAM); + JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderProduceTypes(MessageBodyWriter.class.cast(o2.getProvider())), JAXRSUtils.MEDIA_TYPE_QS_PARAM); if (types1.contains(MediaType.WILDCARD_TYPE) && !types2.contains(MediaType.WILDCARD_TYPE)) { return 1; @@ -1059,9 +1059,9 @@ public class CxfRsHttpListener implements RsHttpListener { } } else if (MessageBodyReader.class.isInstance(o1.getProvider())) { // else is not super good but using both is not sa well so let it be for now final List<MediaType> types1 = - JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderConsumeTypes(MessageBodyReader.class.cast(o1.getProvider())), null); + JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderConsumeTypes(MessageBodyReader.class.cast(o1.getProvider())), null); final List<MediaType> types2 = - JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderConsumeTypes(MessageBodyReader.class.cast(o2.getProvider())), null); + JAXRSUtils.sortMediaTypes(JAXRSUtils.getProviderConsumeTypes(MessageBodyReader.class.cast(o2.getProvider())), null); if (types1.contains(MediaType.WILDCARD_TYPE) && !types2.contains(MediaType.WILDCARD_TYPE)) { return 1; http://git-wip-us.apache.org/repos/asf/tomee/blob/84ede0f2/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/SingletonProviderTest.java ---------------------------------------------------------------------- diff --git a/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/SingletonProviderTest.java b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/SingletonProviderTest.java new file mode 100644 index 0000000..0f7ad6e --- /dev/null +++ b/server/openejb-cxf-rs/src/test/java/org/apache/openejb/server/cxf/rs/SingletonProviderTest.java @@ -0,0 +1,79 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.openejb.server.cxf.rs; + +import org.apache.openejb.junit.ApplicationComposer; +import org.apache.openejb.loader.IO; +import org.apache.openejb.testing.Classes; +import org.apache.openejb.testing.EnableServices; +import org.apache.openejb.testing.RandomPort; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.Response; +import javax.ws.rs.ext.ExceptionMapper; +import javax.ws.rs.ext.Provider; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.HashSet; +import java.util.Set; + +import static org.junit.Assert.assertEquals; + +@EnableServices("jax-rs") +@Classes(value = SingletonProviderTest.ApplicationSample.class, context = "app") +@RunWith(ApplicationComposer.class) +public class SingletonProviderTest { + @RandomPort("http") + private URL base; + + @Test + public void check() throws Exception { + final HttpURLConnection conn = HttpURLConnection.class.cast(new URL(base.toExternalForm() + "app/need-provider").openConnection()); + assertEquals("ok", IO.slurp(conn.getInputStream())); + conn.getInputStream().close(); + } + + @Path("need-provider") + public static class NeedAProvider { + @GET + public String providers() { + throw new IllegalArgumentException(); + } + } + + @Provider + public static class DontLetResourcesFail implements ExceptionMapper<IllegalArgumentException> { + @Override + public Response toResponse(final IllegalArgumentException throwable) { + return Response.ok("ok").build(); + } + } + + public static class ApplicationSample extends Application { + @Override + public Set<Object> getSingletons() { + return new HashSet<Object>() {{ + add(new NeedAProvider()); + add(new DontLetResourcesFail()); + }}; + } + } +} http://git-wip-us.apache.org/repos/asf/tomee/blob/84ede0f2/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/InternalApplication.java ---------------------------------------------------------------------- diff --git a/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/InternalApplication.java b/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/InternalApplication.java index cb36fda..04a8cbd 100644 --- a/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/InternalApplication.java +++ b/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/InternalApplication.java @@ -27,6 +27,10 @@ public class InternalApplication extends Application { public InternalApplication(final Application original) { this.original = original; + if (original != null) { + singletons.addAll(original.getSingletons()); + classes.addAll(original.getClasses()); + } } @Override http://git-wip-us.apache.org/repos/asf/tomee/blob/84ede0f2/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RESTService.java ---------------------------------------------------------------------- diff --git a/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RESTService.java b/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RESTService.java index fc28001..d7ac5e5 100644 --- a/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RESTService.java +++ b/server/openejb-rest/src/main/java/org/apache/openejb/server/rest/RESTService.java @@ -51,6 +51,12 @@ import org.apache.openejb.util.Logger; import org.apache.webbeans.config.WebBeansContext; import org.apache.xbean.finder.MetaAnnotatedClass; +import javax.naming.Context; +import javax.ws.rs.ApplicationPath; +import javax.ws.rs.Path; +import javax.ws.rs.core.Application; +import javax.ws.rs.core.UriBuilder; +import javax.ws.rs.ext.Provider; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -67,12 +73,6 @@ import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; -import javax.naming.Context; -import javax.ws.rs.ApplicationPath; -import javax.ws.rs.Path; -import javax.ws.rs.core.Application; -import javax.ws.rs.core.UriBuilder; -import javax.ws.rs.ext.Provider; @SuppressWarnings("UnusedDeclaration") public abstract class RESTService implements ServerService, SelfManaging { @@ -155,6 +155,9 @@ public abstract class RESTService implements ServerService, SelfManaging { throw new OpenEJBRestRuntimeException("can't create class " + app, e); } + application = "true".equalsIgnoreCase(appInfo.properties.getProperty("openejb.cxf-rs.cache-application", "true")) + ? new InternalApplication(application) /* caches singletons and classes */ : application; + final Set<Class<?>> classes = new HashSet<>(application.getClasses()); final Set<Object> singletons = application.getSingletons();