Repository: aries-jax-rs-whiteboard Updated Branches: refs/heads/new-spec-with-component-dsl 17341dd48 -> 4d8abfaa0
Add support for services lifecycle Project: http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/repo Commit: http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/commit/4d8abfaa Tree: http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/tree/4d8abfaa Diff: http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/diff/4d8abfaa Branch: refs/heads/new-spec-with-component-dsl Commit: 4d8abfaa02457841cb2fc963a46426599290a77a Parents: 17341dd Author: Carlos Sierra <[email protected]> Authored: Thu Feb 23 15:44:41 2017 +0100 Committer: Carlos Sierra <[email protected]> Committed: Thu Feb 23 15:44:41 2017 +0100 ---------------------------------------------------------------------- jax-rs.itests/pom.xml | 2 +- jax-rs.itests/src/main/java/test/JaxrsTest.java | 97 +++++++++++++++- .../java/test/types/TestAddonLifecycle.java | 31 +++++ jax-rs.whiteboard/pom.xml | 2 +- .../activator/CXFJaxRsBundleActivator.java | 114 ++++++++++++++++--- .../internal/CXFJaxRsServiceRegistrator.java | 68 +++++------ 6 files changed, 260 insertions(+), 54 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/4d8abfaa/jax-rs.itests/pom.xml ---------------------------------------------------------------------- diff --git a/jax-rs.itests/pom.xml b/jax-rs.itests/pom.xml index 59e4b50..d5147a1 100644 --- a/jax-rs.itests/pom.xml +++ b/jax-rs.itests/pom.xml @@ -46,7 +46,7 @@ <dependency> <groupId>org.osgi</groupId> <artifactId>org.osgi.core</artifactId> - <version>5.0.0</version> + <version>6.0.0</version> </dependency> <dependency> <groupId>org.osgi</groupId> http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/4d8abfaa/jax-rs.itests/src/main/java/test/JaxrsTest.java ---------------------------------------------------------------------- diff --git a/jax-rs.itests/src/main/java/test/JaxrsTest.java b/jax-rs.itests/src/main/java/test/JaxrsTest.java index f5b434b..20f8910 100644 --- a/jax-rs.itests/src/main/java/test/JaxrsTest.java +++ b/jax-rs.itests/src/main/java/test/JaxrsTest.java @@ -21,11 +21,15 @@ import java.util.Dictionary; import java.util.Hashtable; import org.junit.Test; +import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.FrameworkUtil; +import org.osgi.framework.PrototypeServiceFactory; +import org.osgi.framework.ServiceFactory; import org.osgi.framework.ServiceRegistration; import test.types.TestAddon; +import test.types.TestAddonLifecycle; import test.types.TestApplication; import test.types.TestFilter; @@ -36,6 +40,7 @@ import javax.ws.rs.core.Application; import javax.ws.rs.core.Response; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNull; @@ -341,6 +346,60 @@ public class JaxrsTest { } @Test + public void testStandaloneEndPointSingletonLifecycle() { + Client client = createClient(); + + WebTarget webTarget = client. + target("http://localhost:8080"). + path("/test-addon"); + + ServiceRegistration<?> serviceRegistration = null; + + try { + serviceRegistration = registerAddonLifecycle( + true, "osgi.jaxrs.resource.base", "/test-addon"); + + String first = webTarget.request().get().readEntity(String.class); + + String second = webTarget.request().get().readEntity(String.class); + + assertEquals("This should be equal", first, second); + } + finally { + if (serviceRegistration != null) { + serviceRegistration.unregister(); + } + } + } + + @Test + public void testStandaloneEndPointPrototypeLifecycle() { + Client client = createClient(); + + WebTarget webTarget = client. + target("http://localhost:8080"). + path("/test-addon"); + + ServiceRegistration<?> serviceRegistration = null; + + try { + serviceRegistration = registerAddonLifecycle( + false, "osgi.jaxrs.resource.base", "/test-addon"); + + String first = webTarget.request().get().readEntity(String.class); + + String second = webTarget.request().get().readEntity(String.class); + + assertNotEquals("This should be different", first, second); + } + finally { + if (serviceRegistration != null) { + serviceRegistration.unregister(); + } + } + } + + @Test public void testStandaloneFilter() { Client client = createClient(); @@ -512,7 +571,6 @@ public class JaxrsTest { } private ServiceRegistration<?> registerAddon(Object ... keyValues) { - TestAddon testAddon = new TestAddon(); Dictionary<String, Object> properties = new Hashtable<>(); @@ -525,6 +583,43 @@ public class JaxrsTest { Object.class, testAddon, properties); } + private ServiceRegistration<?> registerAddonLifecycle( + boolean singleton, Object ... keyValues) { + + Dictionary<String, Object> properties = new Hashtable<>(); + + for (int i = 0; i < keyValues.length; i = i + 2) { + properties.put(keyValues[i].toString(), keyValues[i + 1]); + } + + if (singleton) { + return bundleContext.registerService( + Object.class, new TestAddonLifecycle(), properties); + } + else { + PrototypeServiceFactory<Object> prototypeServiceFactory = + new PrototypeServiceFactory<Object>() { + @Override + public Object getService( + Bundle bundle, ServiceRegistration registration) { + + return new TestAddonLifecycle(); + } + + @Override + public void ungetService( + Bundle bundle, ServiceRegistration registration, + Object service) { + + } + }; + + return bundleContext.registerService( + Object.class, (ServiceFactory<?>)prototypeServiceFactory, + properties); + } + } + private ServiceRegistration<?> registerApplication() { TestApplication testApplication = new TestApplication(); http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/4d8abfaa/jax-rs.itests/src/main/java/test/types/TestAddonLifecycle.java ---------------------------------------------------------------------- diff --git a/jax-rs.itests/src/main/java/test/types/TestAddonLifecycle.java b/jax-rs.itests/src/main/java/test/types/TestAddonLifecycle.java new file mode 100644 index 0000000..f271dc7 --- /dev/null +++ b/jax-rs.itests/src/main/java/test/types/TestAddonLifecycle.java @@ -0,0 +1,31 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package test.types; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; + +public class TestAddonLifecycle { + + @GET + @Path("/") + public String sayHello() { + return this.toString(); + } + +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/4d8abfaa/jax-rs.whiteboard/pom.xml ---------------------------------------------------------------------- diff --git a/jax-rs.whiteboard/pom.xml b/jax-rs.whiteboard/pom.xml index 23a0ce7..26baa7d 100644 --- a/jax-rs.whiteboard/pom.xml +++ b/jax-rs.whiteboard/pom.xml @@ -80,7 +80,7 @@ <dependency> <groupId>org.osgi</groupId> <artifactId>org.osgi.core</artifactId> - <version>5.0.0</version> + <version>6.0.0</version> </dependency> <dependency> <groupId>org.osgi</groupId> http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/4d8abfaa/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/activator/CXFJaxRsBundleActivator.java ---------------------------------------------------------------------- diff --git a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/activator/CXFJaxRsBundleActivator.java b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/activator/CXFJaxRsBundleActivator.java index 8618122..23d0427 100644 --- a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/activator/CXFJaxRsBundleActivator.java +++ b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/activator/CXFJaxRsBundleActivator.java @@ -19,6 +19,7 @@ package org.apache.aries.jax.rs.whiteboard.activator; import javax.servlet.Servlet; import javax.ws.rs.core.Application; +import javax.ws.rs.ext.Provider; import javax.ws.rs.ext.RuntimeDelegate; import org.apache.aries.jax.rs.whiteboard.internal.CXFJaxRsServiceRegistrator; @@ -28,10 +29,13 @@ import org.apache.aries.osgi.functional.OSGiResult; import org.apache.cxf.Bus; import org.apache.cxf.BusFactory; import org.apache.cxf.bus.CXFBusFactory; +import org.apache.cxf.jaxrs.lifecycle.ResourceProvider; +import org.apache.cxf.message.Message; import org.apache.cxf.transport.servlet.CXFNonSpringServlet; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; +import org.osgi.framework.ServiceObjects; import org.osgi.framework.ServiceReference; import org.osgi.framework.ServiceRegistration; import org.osgi.framework.wiring.BundleWiring; @@ -68,6 +72,15 @@ public class CXFJaxRsBundleActivator implements BundleActivator { )); } + private static <T> OSGi<ServiceObjects<T>> serviceObjects( + ServiceReference<T> serviceReference) { + + return + bundleContext().flatMap(bundleContext -> + just(bundleContext.getServiceObjects(serviceReference)) + ); + } + private static OSGi<CXFJaxRsServiceRegistrator> cxfRegistrator( Bus bus, Application application, Map<String, Object> props) { @@ -129,7 +142,7 @@ public class CXFJaxRsBundleActivator implements BundleActivator { OSGi<?> extensions = serviceReferences(getExtensionFilter()).flatMap(ref -> waitForExtensionDependencies(ref, - safeRegisterEndpoint(ref, defaultServiceRegistrator) + safeRegisterExtension(ref, defaultServiceRegistrator) ) ); @@ -142,12 +155,44 @@ public class CXFJaxRsBundleActivator implements BundleActivator { flatMap(applicationFilter -> services(CXFJaxRsServiceRegistrator.class, applicationFilter). flatMap(registrator -> - safeRegisterEndpoint(ref, registrator) + testProvider(ref).flatMap(isProvider -> { + if (isProvider) { + return safeRegisterExtension(ref, registrator); + } + else { + return safeRegisterEndpoint(ref, registrator); + } + }) ))); _applicationSingletonsResult = applicationSingletons.run(bundleContext); } + private OSGi<Boolean> testProvider(ServiceReference<?> serviceReference) { + return bundleContext().flatMap(bundleContext -> { + Object service = bundleContext.getService(serviceReference); + Class<?> serviceClass = service.getClass(); + if (serviceClass.isAnnotationPresent(Provider.class)) { + return just(Boolean.TRUE); + } + else { + return just(Boolean.FALSE); + } + }); + } + + private OSGi<?> safeRegisterExtension( + ServiceReference<Object> ref, + CXFJaxRsServiceRegistrator registrator) { + + return + service(ref).flatMap(extension -> + onClose(() -> registrator.removeProvider(extension)). + foreach(ign -> + registrator.addProvider(extension) + )); + } + /** * Initialize instance so it is never looked up again * @param bundleContext @@ -195,20 +240,22 @@ public class CXFJaxRsBundleActivator implements BundleActivator { return program; } - private OSGi<?> safeRegisterEndpoint( - ServiceReference<?> ref, CXFJaxRsServiceRegistrator registrator) { + private <T> OSGi<?> safeRegisterEndpoint( + ServiceReference<T> ref, CXFJaxRsServiceRegistrator registrator) { return bundleContext().flatMap(bundleContext -> - service(ref).flatMap(service -> - onClose(() -> unregisterEndpoint(registrator, service)).then( - registerEndpoint(ref, registrator, service) - ))); + serviceObjects(ref).flatMap(service -> + registerEndpoint(ref, registrator, service). + flatMap(serviceInformation -> + onClose( + () -> unregisterEndpoint(registrator, serviceInformation))))); } - private OSGi<?> registerEndpoint( + private <T> OSGi<ServiceInformation> registerEndpoint( ServiceReference<?> ref, - CXFJaxRsServiceRegistrator registrator, Object service) { + CXFJaxRsServiceRegistrator registrator, + ServiceObjects<T> serviceObjects) { Thread thread = Thread.currentThread(); ClassLoader contextClassLoader = thread.getContextClassLoader(); @@ -216,6 +263,8 @@ public class CXFJaxRsBundleActivator implements BundleActivator { getClassLoader(); Object resourceBaseObject = ref.getProperty("osgi.jaxrs.resource.base"); + ResourceProvider resourceProvider = getResourceProvider(serviceObjects); + String resourceBase; if (resourceBaseObject == null) { @@ -226,18 +275,55 @@ public class CXFJaxRsBundleActivator implements BundleActivator { } try { thread.setContextClassLoader(classLoader); - registrator.add(new ServiceInformation(resourceBase, "", service)); + ServiceInformation serviceInformation = new ServiceInformation( + resourceBase, resourceProvider); + registrator.add(serviceInformation); + return just(serviceInformation); } finally { thread.setContextClassLoader(contextClassLoader); } - return just(service); + } + + private <T> ResourceProvider getResourceProvider( + ServiceObjects<T> serviceObjects) { + + ResourceProvider resourceProvider; + T service = serviceObjects.getService(); + Class<?> serviceClass = service.getClass(); + + resourceProvider = new ResourceProvider() { + + @Override + public Object getInstance(Message m) { + return serviceObjects.getService(); + } + + @Override + public void releaseInstance(Message m, Object o) { + serviceObjects.ungetService((T)o); + } + + @Override + public Class<?> getResourceClass() { + return serviceClass; + } + + @Override + public boolean isSingleton() { + return false; + } + }; + + serviceObjects.ungetService(service); + return resourceProvider; } private void unregisterEndpoint( - CXFJaxRsServiceRegistrator registrator, Object service) { + CXFJaxRsServiceRegistrator registrator, + ServiceInformation serviceInformation) { - registrator.remove(service); + registrator.remove(serviceInformation); } private ServiceRegistration<Servlet> registerCXFServletService(Bus bus) { http://git-wip-us.apache.org/repos/asf/aries-jax-rs-whiteboard/blob/4d8abfaa/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/CXFJaxRsServiceRegistrator.java ---------------------------------------------------------------------- diff --git a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/CXFJaxRsServiceRegistrator.java b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/CXFJaxRsServiceRegistrator.java index 683cb0f..e6170cb 100644 --- a/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/CXFJaxRsServiceRegistrator.java +++ b/jax-rs.whiteboard/src/main/java/org/apache/aries/jax/rs/whiteboard/internal/CXFJaxRsServiceRegistrator.java @@ -20,19 +20,17 @@ package org.apache.aries.jax.rs.whiteboard.internal; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; -import java.util.Iterator; import java.util.List; import java.util.Map; import javax.ws.rs.core.Application; -import javax.ws.rs.ext.Provider; import javax.ws.rs.ext.RuntimeDelegate; import org.apache.cxf.Bus; import org.apache.cxf.endpoint.Server; import org.apache.cxf.jaxrs.JAXRSServerFactoryBean; import org.apache.cxf.jaxrs.JAXRSServiceFactoryBean; -import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider; +import org.apache.cxf.jaxrs.lifecycle.ResourceProvider; import org.apache.cxf.jaxrs.model.ClassResourceInfo; import org.apache.cxf.jaxrs.model.URITemplate; import org.apache.cxf.jaxrs.provider.json.JSONProvider; @@ -89,38 +87,40 @@ public class CXFJaxRsServiceRegistrator { return; } - Object object = serviceInformation.getService(); + _services.add(serviceInformation); - if (object.getClass().isAnnotationPresent(Provider.class)) { - _providers.add(object); - } else { - _services.add(serviceInformation); - } rewire(); } - public void remove(Object object) { + public void remove(ServiceInformation serviceInformation) { if (_closed) { return; } - if (object.getClass().isAnnotationPresent(Provider.class)) { - _providers.remove(object); - } - else { - Iterator<ServiceInformation> iterator = _services.iterator(); - while (iterator.hasNext()) { - ServiceInformation next = iterator.next(); + _services.remove(serviceInformation); - if (next.getService() == object) { - iterator.remove(); - } - } + rewire(); + } + + public void addProvider(Object provider) { + if (_closed) { + return; } + _providers.add(provider); + rewire(); } + public void removeProvider(Object provider) { + if (_closed) { + return; + } + + _providers.remove(provider); + + rewire(); + } protected synchronized void rewire() { if (_server != null) { _server.destroy(); @@ -159,18 +159,18 @@ public class CXFJaxRsServiceRegistrator { jaxRsServerFactoryBean.getServiceFactory(); for (ServiceInformation serviceInformation : _services) { - Object service = serviceInformation.getService(); - SingletonResourceProvider rp = new SingletonResourceProvider( - service, true); + ResourceProvider resourceProvider = + serviceInformation.getResourceProvider(); - jaxRsServerFactoryBean.setResourceProvider(rp); + jaxRsServerFactoryBean.setResourceProvider(resourceProvider); List<ClassResourceInfo> classResourceInfo = serviceFactory.getClassResourceInfo(); for (ClassResourceInfo resourceInfo : classResourceInfo) { - if (resourceInfo.getServiceClass() == service.getClass()) { + if (resourceInfo.getServiceClass() == + resourceProvider.getResourceClass()) { URITemplate uriTemplate = resourceInfo.getURITemplate(); resourceInfo.setURITemplate( new URITemplate( @@ -203,27 +203,21 @@ public class CXFJaxRsServiceRegistrator { public static class ServiceInformation { private final String prefixPath; - private final String scope; - private final Object service; + private final ResourceProvider _resourceProvider; public ServiceInformation( - String prefixPath, String scope, Object service) { + String prefixPath, ResourceProvider resourceProvider) { this.prefixPath = prefixPath; - this.scope = scope; - this.service = service; + this._resourceProvider = resourceProvider; } public String getPrefixPath() { return prefixPath; } - public String getScope() { - return scope; - } - - public Object getService() { - return service; + public ResourceProvider getResourceProvider() { + return _resourceProvider; } }
