felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From pde...@apache.org
Subject svn commit: r1579451 - in /felix/sandbox/pderop/dependencymanager-prototype: dm.it/src/dm/it/TemporalServiceDependencyTest.java dm/src/dm/DependencyManager.java dm/src/dm/TemporalServiceDependency.java dm/src/dm/impl/TemporalServiceDependencyImpl.java
Date Wed, 19 Mar 2014 23:10:30 GMT
Author: pderop
Date: Wed Mar 19 23:10:29 2014
New Revision: 1579451

URL: http://svn.apache.org/r1579451
Log:
Refactored and simplified the TemporalServiceDependencyImpl.
Fixed a bug in the TemporalServiceDependencyImpl: the dynamic proxy was only injected in autoconfig
fields.
Now the dyn proxy can also be injected using ServiceDependency callbacks (add/remove).
Removed the TemporalServiceDependency interface: the DependencyManager's createTemporalServiceDependency
method is 
now returning a ServiceDependency and takes as argument the temporal service invocation timeout.
Addapted the test accordingly.

Removed:
    felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/TemporalServiceDependency.java
Modified:
    felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/TemporalServiceDependencyTest.java
    felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/DependencyManager.java
    felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/TemporalServiceDependencyImpl.java

Modified: felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/TemporalServiceDependencyTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/TemporalServiceDependencyTest.java?rev=1579451&r1=1579450&r2=1579451&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/TemporalServiceDependencyTest.java
(original)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm.it/src/dm/it/TemporalServiceDependencyTest.java
Wed Mar 19 23:10:29 2014
@@ -1,7 +1,9 @@
 package dm.it;
 
+import junit.framework.Assert;
 import dm.Component;
 import dm.DependencyManager;
+import dm.ServiceDependency;
 
 public class TemporalServiceDependencyTest extends TestBase {
     public void testServiceConsumptionAndIntermittentAvailability() {
@@ -9,20 +11,24 @@ public class TemporalServiceDependencyTe
         // helper class that ensures certain steps get executed in sequence
         Ensure e = new Ensure();
         // create a service provider and consumer
-        Component sp = m.createComponent().setImplementation(new TemporalServiceProvider(e)).setInterface(TemporalServiceInterface.class.getName(),
null);
-        Component sp2 = m.createComponent().setImplementation(new TemporalServiceProvider2(e)).setInterface(TemporalServiceInterface.class.getName(),
null);
-        Component sc = m.createComponent().setImplementation(new TemporalServiceConsumer(e)).add(m.createTemporalServiceDependency().setService(TemporalServiceInterface.class).setRequired(true));
+        TemporalServiceProvider provider = new TemporalServiceProvider(e);
+        Component sp = m.createComponent().setImplementation(provider).setInterface(TemporalServiceInterface.class.getName(),
null);
+        TemporalServiceProvider2 provider2 = new TemporalServiceProvider2(e);
+        Component sp2 = m.createComponent().setImplementation(provider2).setInterface(TemporalServiceInterface.class.getName(),
null);
+        TemporalServiceConsumer consumer = new TemporalServiceConsumer(e);
+        Component sc = m.createComponent().setImplementation(consumer)
+            .add(m.createTemporalServiceDependency(10000).setService(TemporalServiceInterface.class).setRequired(true));
         // add the service consumer
         m.add(sc);
         // now add the first provider
         m.add(sp);
-        e.waitForStep(2, 15000);
+        e.waitForStep(2, 5000);
         // and remove it again (this should not affect the consumer yet)
         m.remove(sp);
         // now add the second provider
         m.add(sp2);
         e.step(3);
-        e.waitForStep(4, 15000);
+        e.waitForStep(4, 5000);
         // and remove it again
         m.remove(sp2);
         // finally remove the consumer
@@ -32,6 +38,41 @@ public class TemporalServiceDependencyTe
         m.clear();
     }
 
+    public void testServiceConsumptionWithCallbackAndIntermittentAvailability() {
+        DependencyManager m = new DependencyManager(context);
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        // create a service provider and consumer
+        TemporalServiceProvider provider = new TemporalServiceProvider(e);
+        Component sp = m.createComponent().setImplementation(provider).setInterface(TemporalServiceInterface.class.getName(),
null);
+        TemporalServiceProvider2 provider2 = new TemporalServiceProvider2(e);
+        Component sp2 = m.createComponent().setImplementation(provider2).setInterface(TemporalServiceInterface.class.getName(),
null);
+        TemporalServiceConsumerWithCallback consumer = new TemporalServiceConsumerWithCallback(e);
+        ServiceDependency temporalDep =  m.createTemporalServiceDependency(10000).setService(TemporalServiceInterface.class).setRequired(true).setCallbacks("add",
"remove");
+        Component sc = m.createComponent().setImplementation(consumer).add(temporalDep);
+            
+        // add the service consumer
+        m.add(sc);
+        // now add the first provider
+        m.add(sp);
+        e.waitForStep(2, 5000);
+        // and remove it again (this should not affect the consumer yet)
+        m.remove(sp);
+        // now add the second provider
+        m.add(sp2);
+        e.step(3);
+        e.waitForStep(4, 5000);
+        // and remove it again
+        m.remove(sp2);
+        // finally remove the consumer
+        m.remove(sc);
+        // Wait for the consumer.remove callback
+        e.waitForStep(6, 5000);
+        // ensure we executed all steps inside the component instance
+        e.step(7);
+        m.clear();
+    }
+
     static interface TemporalServiceInterface {
         public void invoke();
     }
@@ -47,7 +88,7 @@ public class TemporalServiceDependencyTe
     }
 
     static class TemporalServiceProvider2 implements TemporalServiceInterface {
-        private final Ensure m_ensure;
+        protected final Ensure m_ensure;
         public TemporalServiceProvider2(Ensure e) {
             m_ensure = e;
         }
@@ -57,8 +98,8 @@ public class TemporalServiceDependencyTe
     }
 
     static class TemporalServiceConsumer implements Runnable {
-        private volatile TemporalServiceInterface m_service;
-        private final Ensure m_ensure;
+        protected volatile TemporalServiceInterface m_service;
+        protected final Ensure m_ensure;
 
         public TemporalServiceConsumer(Ensure e) {
             m_ensure = e;
@@ -80,4 +121,19 @@ public class TemporalServiceDependencyTe
             m_ensure.step(5);
         }
     }
+    
+    static class TemporalServiceConsumerWithCallback extends TemporalServiceConsumer {
+        public TemporalServiceConsumerWithCallback(Ensure e) {
+            super(e);
+        }
+        
+        public void add(TemporalServiceInterface service) {
+            m_service = service;
+        }
+        
+        public void remove(TemporalServiceInterface service) {
+            Assert.assertTrue(m_service == service);
+            m_ensure.step(6);
+        }
+    }
 }

Modified: felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/DependencyManager.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/DependencyManager.java?rev=1579451&r1=1579450&r2=1579451&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/DependencyManager.java (original)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/DependencyManager.java Wed
Mar 19 23:10:29 2014
@@ -170,8 +170,8 @@ public class DependencyManager {
         return new ResourceDependencyImpl(m_context, m_logger);
     }
 
-    public TemporalServiceDependency createTemporalServiceDependency() {
-        return new TemporalServiceDependencyImpl(m_context, m_logger);
+    public ServiceDependency createTemporalServiceDependency(long timeout) {
+        return new TemporalServiceDependencyImpl(m_context, m_logger, timeout);
     }
 
     public Component createAdapterService(Class serviceInterface, String serviceFilter, String
autoConfig) {

Modified: felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/TemporalServiceDependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/TemporalServiceDependencyImpl.java?rev=1579451&r1=1579450&r2=1579451&view=diff
==============================================================================
--- felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/TemporalServiceDependencyImpl.java
(original)
+++ felix/sandbox/pderop/dependencymanager-prototype/dm/src/dm/impl/TemporalServiceDependencyImpl.java
Wed Mar 19 23:10:29 2014
@@ -1,8 +1,5 @@
 package dm.impl;
 
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
@@ -12,7 +9,6 @@ import org.osgi.framework.BundleContext;
 import org.osgi.framework.ServiceReference;
 
 import dm.ServiceDependency;
-import dm.TemporalServiceDependency;
 
 /**
  * Temporal Service dependency implementation, used to hide temporary service dependency
"outage".
@@ -20,18 +16,15 @@ import dm.TemporalServiceDependency;
  *
  * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
  */
-public class TemporalServiceDependencyImpl extends ServiceDependencyImpl implements TemporalServiceDependency,
InvocationHandler {
+public class TemporalServiceDependencyImpl extends ServiceDependencyImpl implements ServiceDependency,
InvocationHandler {
     // Max millis to wait for service availability.
-    private long m_timeout = 30000;
-    
-    // Dependency service currently used (with highest rank or highest service id).
-    private volatile Object m_cachedService;
-    
+    private final long m_timeout;
+        
     // Framework bundle (we use it to detect if the framework is stopping)
     private final Bundle m_frameworkBundle;
 
     // The service proxy, which blocks when service is not available.
-    private Object m_serviceInstance;
+    private volatile Object m_serviceInstance;
 
     /**
      * Creates a new Temporal Service Dependency.
@@ -40,26 +33,14 @@ public class TemporalServiceDependencyIm
      * @param logger the logger our Internal logger for logging events.
      * @see DependencyActivatorBase#createTemporalServiceDependency()
      */
-    public TemporalServiceDependencyImpl(BundleContext context, Logger logger) {
+    public TemporalServiceDependencyImpl(BundleContext context, Logger logger, long timeout)
{
         super(context, logger);
         super.setRequired(true);
-        m_frameworkBundle = context.getBundle(0);
-    }
-
-    /**
-     * Sets the timeout for this temporal dependency. Specifying a timeout value of zero
means that there is no timeout period,
-     * and an invocation on a missing service will fail immediately.
-     * 
-     * @param timeout the dependency timeout value greater or equals to 0
-     * @throws IllegalArgumentException if the timeout is negative
-     * @return this temporal dependency
-     */
-    public synchronized TemporalServiceDependency setTimeout(long timeout) {
         if (timeout < 0) {
             throw new IllegalArgumentException("Invalid timeout value: " + timeout);
         }
         m_timeout = timeout;
-        return this;
+        m_frameworkBundle = context.getBundle(0);
     }
 
     /**
@@ -79,7 +60,7 @@ public class TemporalServiceDependencyIm
         super.setRequired(required);
         return this;
     }
-
+    
     /**
      * The ServiceTracker calls us here in order to inform about a service arrival.
      */
@@ -87,17 +68,18 @@ public class TemporalServiceDependencyIm
     public void addedService(ServiceReference ref, Object service) {
         // Update our service cache, using the tracker. We do this because the
         // just added service might not be the service with the highest rank ...
-        m_cachedService = m_tracker.getService(); 
-        boolean makeAvailable = ! isAvailable();
-        if (makeAvailable) {
-            m_serviceInstance = Proxy.newProxyInstance(m_trackedServiceName.getClassLoader(),
new Class[] { m_trackedServiceName }, this);
-        }
-        add(new ServiceEventImpl(ref, service));
-        if (!makeAvailable) {
-            synchronized (this) {
-                notifyAll();
+        boolean makeAvailable = false;
+        synchronized (this) {
+            if (m_serviceInstance == null) {
+                m_serviceInstance = Proxy.newProxyInstance(m_trackedServiceName.getClassLoader(),
new Class[] { m_trackedServiceName }, this);
+                makeAvailable = true;
             }
         }
+        if (makeAvailable) {
+            add(new ServiceEventImpl(ref, m_serviceInstance));
+        } else {
+            // This added will possibly unblock our invoke() method (if it's blocked in m_tracker.waitForService
method).
+        }
     }
 
     /**
@@ -122,49 +104,35 @@ public class TemporalServiceDependencyIm
             // our "invoke" method won't use the tracker to get the service dependency (because
at this point, 
             // the tracker has withdrawn its reference to the lost service). So, you will
see that the "invoke" 
             // method will use the "m_cachedService" instead ...
-            super.removedService(ref, service);
+            boolean makeUnavailable = false;
+            synchronized (this) {
+                if (m_tracker.getService() == null) {
+                    makeUnavailable = true;
+                }
+            }
+            if (makeUnavailable) {
+                remove(new ServiceEventImpl(ref, m_serviceInstance)); // will unget the service
ref
+            }
         } else {
             // Unget what we got in addingService (see ServiceTracker 701.4.1)
             m_context.ungetService(ref);
-            // Now, ask the service tracker if there is another available service (with a
lower rank).
-            // If no more service dependencies are available, the tracker will then return
null;
-            // and our invoke method will block the service method invocation, until another
service
-            // becomes available.
-            m_cachedService = m_tracker.getService();
+            // if there is no available services, the next call to invoke() method will block
until another service
+            // becomes available. Else the next call to invoke() will return that highest
ranked available service.
         }
     }
 
-    /**
-     * @returns our dependency instance. Unlike in ServiceDependency, we always returns our
proxy.
-     */
-    @Override
-    protected synchronized Object getService() {
-        return m_serviceInstance;
-    }
-
     @Override
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
-        Object service = m_cachedService;
+        Object service = null;
+        try {
+            service = m_tracker.waitForService(m_timeout);
+        } catch (InterruptedException e) {            
+        }
+        
         if (service == null) {
-            synchronized (this) {
-                long start = System.currentTimeMillis();
-                long waitTime = m_timeout;
-                while (service == null) {
-                    if (waitTime <= 0) {
-                        throw new IllegalStateException("Service unavailable: " + m_trackedServiceName.getName());
-                    }
-                    try {
-                        wait(waitTime);
-                    }
-                    catch (InterruptedException e) {
-                        throw new IllegalStateException("Service unavailable: " + m_trackedServiceName.getName());
-                    }
-                    waitTime = m_timeout - (System.currentTimeMillis() - start);
-                    service = m_cachedService;
-                }
-                
-            }
+            throw new IllegalStateException("Service unavailable: " + m_trackedServiceName.getName());
         }
+        
         try {
             return method.invoke(service, args);
         }



Mime
View raw message