Add support for services lifecycle
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>
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.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.Response;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNull;
@@ -341,6 +346,60 @@
}
@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 @@
}
private ServiceRegistration<?> registerAddon(Object ... keyValues) {
-
TestAddon testAddon = new TestAddon();
Dictionary<String, Object> properties = new Hashtable<>();
@@ -525,6 +583,43 @@
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();
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
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>
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 @@
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.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 @@
));
}
+ 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 @@
OSGi<?> extensions =
serviceReferences(getExtensionFilter()).flatMap(ref ->
waitForExtensionDependencies(ref,
- safeRegisterEndpoint(ref, defaultServiceRegistrator)
+ safeRegisterExtension(ref, defaultServiceRegistrator)
)
);
@@ -142,12 +155,44 @@
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 @@
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 @@
getClassLoader();
Object resourceBaseObject = ref.getProperty("osgi.jaxrs.resource.base");
+ ResourceProvider resourceProvider = getResourceProvider(serviceObjects);
+
String resourceBase;
if (resourceBaseObject == null) {
@@ -226,18 +275,55 @@
}
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) {
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 @@
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 @@
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();
-
- if (next.getService() == object) {
- iterator.remove();
- }
- }
- }
+ _services.remove(serviceInformation);
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 @@
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 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;
}
}