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;
         }
 
     }