felix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject svn commit: r1567905 - in /felix/sandbox/marrs/dependencymanager-prototype/dm: src/dm/Component.java src/dm/Dependency.java src/dm/impl/ComponentImpl.java src/dm/impl/DependencyImpl.java src/dm/impl/EventImpl.java test/test/ComponentTest.java
Date Thu, 13 Feb 2014 12:31:26 GMT
Author: marrs
Date: Thu Feb 13 12:31:26 2014
New Revision: 1567905

URL: http://svn.apache.org/r1567905
Log:
Added dependency callbacks, plus some more tests.

Modified:
    felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/Component.java
    felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/Dependency.java
    felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java
    felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/DependencyImpl.java
    felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/EventImpl.java
    felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/ComponentTest.java

Modified: felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/Component.java
URL: http://svn.apache.org/viewvc/felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/Component.java?rev=1567905&r1=1567904&r2=1567905&view=diff
==============================================================================
--- felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/Component.java (original)
+++ felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/Component.java Thu Feb 13 12:31:26
2014
@@ -26,4 +26,7 @@ public interface Component {
 	public void remove(ComponentStateListener l);
 
 	public List<Dependency> getDependencies(); // for testing only...
+	
+	public void invokeCallbackMethod(Object[] instances, String methodName, Class[][] signatures,
Object[][] parameters);
+    public Object[] getInstances();
 }

Modified: felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/Dependency.java
URL: http://svn.apache.org/viewvc/felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/Dependency.java?rev=1567905&r1=1567904&r2=1567905&view=diff
==============================================================================
--- felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/Dependency.java (original)
+++ felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/Dependency.java Thu Feb 13 12:31:26
2014
@@ -23,4 +23,8 @@ public interface Dependency {
 
 	public boolean isInstanceBound();
 	public void setInstanceBound(boolean instanceBound);
+	public void setCallbacks(String add, String remove);
+	
+	public void invokeAdd();
+	public void invokeRemove();
 }

Modified: felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java?rev=1567905&r1=1567904&r2=1567905&view=diff
==============================================================================
--- felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java (original)
+++ felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/ComponentImpl.java Thu
Feb 13 12:31:26 2014
@@ -15,7 +15,7 @@ public class ComponentImpl implements Co
     private static final Class[] VOID = new Class[] {};
 	private final SerialExecutor m_executor = new SerialExecutor(new Logger(null));
 	private ComponentState m_state = ComponentState.INACTIVE;
-	private List<Dependency> m_dependencies = new ArrayList<>();
+	private List<Dependency> m_dependencies = new CopyOnWriteArrayList<>();
 	private List<ComponentStateListener> m_listeners = new CopyOnWriteArrayList<>();
 	private boolean m_isStarted;
 	
@@ -151,6 +151,7 @@ public class ComponentImpl implements Co
 
 	/** Perform all the actions associated with state transitions. Returns true if a transition
was performed. */
 	private boolean performTransition(ComponentState oldState, ComponentState newState) {
+//		System.out.println("transition from " + oldState + " to " + newState);
 		if (oldState == ComponentState.INACTIVE && newState == ComponentState.WAITING_FOR_REQUIRED)
{
 			for (Dependency d : m_dependencies) {
 				d.start();
@@ -160,22 +161,26 @@ public class ComponentImpl implements Co
 		}
 		if (oldState == ComponentState.WAITING_FOR_REQUIRED && newState == ComponentState.INSTANTIATED_AND_WAITING_FOR_REQUIRED)
{
 			instantiateComponent();
+			invokeAddRequiredDependencies();
 	        invoke("init" /* TODO make callbacks configurable */ );
 			notifyListeners(newState);
 			return true;
 		}
 		if (oldState == ComponentState.INSTANTIATED_AND_WAITING_FOR_REQUIRED && newState
== ComponentState.TRACKING_OPTIONAL) {
+			invokeAddInstanceBoundDependencies();
 			invoke("start");
 			notifyListeners(newState);
 			return true;
 		}
 		if (oldState == ComponentState.TRACKING_OPTIONAL && newState == ComponentState.INSTANTIATED_AND_WAITING_FOR_REQUIRED)
{
 			invoke("stop");
+			invokeRemoveInstanceBoundDependencies();
 			notifyListeners(newState);
 			return true;
 		}
 		if (oldState == ComponentState.INSTANTIATED_AND_WAITING_FOR_REQUIRED && newState
== ComponentState.WAITING_FOR_REQUIRED) {
 			invoke("destroy");
+			invokeRemoveRequiredDependencies();
 			notifyListeners(newState);
 			destroyComponent();
 			return true;
@@ -209,21 +214,54 @@ public class ComponentImpl implements Co
 		m_componentInstance = null;
 	}
 	
-    private void invoke(String name) {
+	private void invokeAddRequiredDependencies() {
+		for (Dependency d : m_dependencies) {
+			if (!d.isInstanceBound()) {
+				d.invokeAdd();
+			}
+		}
+	}
+	private void invokeAddInstanceBoundDependencies() {
+		for (Dependency d : m_dependencies) {
+			if (d.isInstanceBound()) {
+				d.invokeAdd();
+			}
+		}
+	}
+
+	private void invokeRemoveRequiredDependencies() {
+		for (Dependency d : m_dependencies) {
+			if (!d.isInstanceBound()) {
+				d.invokeRemove();
+			}
+		}
+	}
+
+	private void invokeRemoveInstanceBoundDependencies() {
+		for (Dependency d : m_dependencies) {
+			if (d.isInstanceBound()) {
+				d.invokeRemove();
+			}
+		}
+	}
+
+	private void invoke(String name) {
         if (name != null) {
             // if a callback instance was specified, look for the method there, if not,
             // ask the service for its composition instances
         	
-        	// TODO
-//            Object[] instances = m_callbackInstance != null ? new Object[] { m_callbackInstance
} : getCompositionInstances();
-            
-            Object[] instances = { m_componentInstance };
-            invokeCallbackMethod(instances, name, 
+            invokeCallbackMethod(getInstances(), name, 
                 new Class[][] {{ Component.class }, {}}, 
                 new Object[][] {{ this }, {}});
         }
     }
     
+    public Object[] getInstances() {
+    	// TODO
+//      Object[] instances = m_callbackInstance != null ? new Object[] { m_callbackInstance
} : getCompositionInstances();
+    	return new Object[] { m_componentInstance };
+    }
+    
     public void invokeCallbackMethod(Object[] instances, String methodName, Class[][] signatures,
Object[][] parameters) {
         for (int i = 0; i < instances.length; i++) {
             try {
@@ -241,8 +279,6 @@ public class ComponentImpl implements Co
             }
         }
     }
-	
-	
 
     private Object createInstance(Class clazz) throws SecurityException, NoSuchMethodException,
InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
{
 		Constructor constructor = clazz.getConstructor(VOID);

Modified: felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/DependencyImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/DependencyImpl.java?rev=1567905&r1=1567904&r2=1567905&view=diff
==============================================================================
--- felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/DependencyImpl.java (original)
+++ felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/DependencyImpl.java Thu
Feb 13 12:31:26 2014
@@ -1,8 +1,6 @@
 package dm.impl;
 
-import java.util.List;
 import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
 import java.util.concurrent.CopyOnWriteArraySet;
 
 import dm.Component;
@@ -13,6 +11,8 @@ public class DependencyImpl implements D
 	private Component m_component;
 	private boolean m_available;
 	private boolean m_instanceBound;
+	private String m_add;
+	private String m_remove;
 	private Set<Event> m_dependencies = new CopyOnWriteArraySet<>();
 	
 	public synchronized void add(final Event e) {
@@ -52,6 +52,11 @@ public class DependencyImpl implements D
 	protected void addDependency(Event e) {
 		m_dependencies.add(e);
 		m_available = true;
+		// if this is an optional dependency and the component is in an instantiated
+		// state, we can invoke the callback here
+		if (m_component.isAvailable()) {
+			invokeAdd(e);
+		}
 		m_component.handleChange();
 	}
 
@@ -64,6 +69,9 @@ public class DependencyImpl implements D
 	protected void removeDependency(Event e) {
 		m_dependencies.remove(e);
 		m_available = (!m_dependencies.isEmpty());
+		if (m_component.isAvailable()) {
+			invokeRemove(e);
+		}
 		m_component.handleChange();
 	}
 
@@ -101,4 +109,31 @@ public class DependencyImpl implements D
 	public void setInstanceBound(boolean instanceBound) {
 		m_instanceBound = instanceBound;
 	}
+	
+	public void setCallbacks(String add, String remove) {
+		m_add = add;
+		m_remove = remove;
+	}
+	
+	public void invokeAdd() {
+		for (Event e : m_dependencies) {
+			invokeAdd(e);
+		}
+	}
+	
+	public void invokeRemove() {
+		for (Event e : m_dependencies) {
+			invokeRemove(e);
+		}
+	}
+
+	public void invokeAdd(Event e) {
+		// specific for this type of dependency
+		m_component.invokeCallbackMethod(m_component.getInstances(), m_add, new Class[][] {{}},
new Object[][] {{}});
+	}
+	
+	public void invokeRemove(Event e) {
+		// specific for this type of dependency
+		m_component.invokeCallbackMethod(m_component.getInstances(), m_remove, new Class[][] {{}},
new Object[][] {{}});
+	}
 }

Modified: felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/EventImpl.java
URL: http://svn.apache.org/viewvc/felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/EventImpl.java?rev=1567905&r1=1567904&r2=1567905&view=diff
==============================================================================
--- felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/EventImpl.java (original)
+++ felix/sandbox/marrs/dependencymanager-prototype/dm/src/dm/impl/EventImpl.java Thu Feb
13 12:31:26 2014
@@ -6,15 +6,25 @@ import dm.Event;
  * or something similar
  */
 public class EventImpl implements Event {
+	private final int m_id;
+
+	public EventImpl() {
+		this(1);
+	}
+	/** By constructing events with different IDs, we can simulate different unique instances.
*/
+	public EventImpl(int id) {
+		m_id = id;
+	}
+
 	@Override
 	public int hashCode() {
-		return 1;
+		return m_id;
 	}
 
 	@Override
 	public boolean equals(Object obj) {
 		if (obj instanceof EventImpl) {
-			return true;
+			return ((EventImpl) obj).m_id == m_id;
 		}
 		return false;
 	}

Modified: felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/ComponentTest.java
URL: http://svn.apache.org/viewvc/felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/ComponentTest.java?rev=1567905&r1=1567904&r2=1567905&view=diff
==============================================================================
--- felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/ComponentTest.java (original)
+++ felix/sandbox/marrs/dependencymanager-prototype/dm/test/test/ComponentTest.java Thu Feb
13 12:31:26 2014
@@ -2,6 +2,7 @@ package test;
 
 import org.junit.Assert;
 import org.junit.Test;
+import org.osgi.framework.ServiceReference;
 
 import dm.Component;
 import dm.ComponentState;
@@ -182,4 +183,201 @@ public class ComponentTest {
 		c.stop();
 		Assert.assertEquals("component stopped, should be unavailable again", false, c.isAvailable());
 	}
+
+	@Test
+	public void createComponentAddDependencyMakeAvailableAndUnavailableWithCallbacks() {
+		final Ensure e = new Ensure();
+		Component c = new ComponentImpl();
+		c.setImplementation(new Object() {
+			public void add() {
+				e.step(1);
+			}
+			public void remove() {
+				e.step(3);
+			}
+		});
+		Dependency d1 = new DependencyImpl();
+		d1.setCallbacks("add", "remove");
+		// add the dependency to the component
+		c.add(d1);
+		// start the component
+		c.start();
+		// make the dependency available, we expect the add callback
+		// to be invoked here
+		d1.add(new EventImpl());
+		e.step(2);
+		// remove the dependency, should trigger the remove callback
+		d1.remove(new EventImpl());
+		e.step(4);
+		c.stop();
+		c.remove(d1);
+		Assert.assertEquals("component stopped, should be unavailable again", false, c.isAvailable());
+	}
+	
+	@Test
+	public void createAndStartComponentAddDependencyMakeAvailableAndUnavailableWithCallbacks()
{
+		final Ensure e = new Ensure();
+		Component c = new ComponentImpl();
+		c.setImplementation(new Object() {
+			public void add() {
+				e.step(1);
+			}
+			public void remove() {
+				e.step(3);
+			}
+		});
+		Dependency d1 = new DependencyImpl();
+		d1.setCallbacks("add", "remove");
+		// start the component (it should become available)
+		c.start();
+		// add the dependency (it should become unavailable)
+		c.add(d1);
+		// make the dependency available, which should invoke the
+		// add callback
+		d1.add(new EventImpl());
+		e.step(2);
+		// make the dependency unavailable, should trigger the
+		// remove callback
+		d1.remove(new EventImpl());
+		e.step(4);
+		c.remove(d1);
+		c.stop();
+		Assert.assertEquals("component stopped, should be unavailable again", false, c.isAvailable());
+	}
+
+	@Test
+	public void createComponentAddTwoDependenciesMakeBothAvailableAndUnavailableWithCallbacks()
{
+		final Ensure e = new Ensure();
+		Component c = new ComponentImpl();
+		c.setImplementation(new Object() {
+			public void add() {
+				e.step();
+			}
+			public void remove() {
+				e.step();
+			}
+		});
+		Dependency d1 = new DependencyImpl();
+		d1.setCallbacks("add", "remove");
+		Dependency d2 = new DependencyImpl();
+		d2.setCallbacks("add", "remove");
+		// start the component, which should become active because there are no
+		// dependencies yet
+		c.start();
+		// now add the dependencies, making the component unavailable
+		c.add(d1);
+		c.add(d2);
+		// make the first dependency available, should have no effect on the
+		// component
+		d1.add(new EventImpl());
+		e.step(1);
+		// second dependency available, now all the add callbacks should be
+		// invoked
+		d2.add(new EventImpl());
+		e.step(4);
+		// remove the first dependency, triggering the remove callbacks
+		d1.remove(new EventImpl());
+		e.step(7);
+		// remove the second dependency, should not trigger more callbacks
+		d2.remove(new EventImpl());
+		e.step(8);
+		c.remove(d2);
+		c.remove(d1);
+		c.stop();
+		// still, no more callbacks should have been invoked
+		e.step(9);
+		Assert.assertEquals("component stopped, should be unavailable again", false, c.isAvailable());
+	}
+	
+	@Test
+	public void createAndStartComponentAddTwoDependenciesMakeBothAvailableAndUnavailableWithCallbacks()
{
+		final Ensure e = new Ensure();
+		Component c = new ComponentImpl();
+		c.setImplementation(new Object() {
+			public void add() {
+				e.step();
+			}
+			public void remove() {
+				e.step();
+			}
+		});
+		// start the component, it should become available
+		c.start();
+		Dependency d1 = new DependencyImpl();
+		d1.setCallbacks("add", "remove");
+		Dependency d2 = new DependencyImpl();
+		d2.setCallbacks("add", "remove");
+		// add the first dependency, component should be unavailable
+		c.add(d1);
+		c.add(d2);
+		// make first dependency available, component should still be unavailable
+		d1.add(new EventImpl());
+		e.step(1);
+		// make second dependency available, component available, callbacks should
+		// be invoked
+		d2.add(new EventImpl());
+		e.step(4);
+		// remove the first dependency, callbacks should be invoked
+		d1.remove(new EventImpl());
+		e.step(7);
+		// remove second dependency, no callbacks should be invoked
+		d2.remove(new EventImpl());
+		e.step(8);
+		c.remove(d2);
+		c.remove(d1);
+		c.stop();
+		e.step(9);
+		Assert.assertEquals("component stopped, should be unavailable again", false, c.isAvailable());
+	}
+
+	@Test
+	public void createAndStartComponentAddTwoDependenciesWithMultipleServicesWithCallbacks()
{
+		final Ensure e = new Ensure();
+		Component c = new ComponentImpl();
+		c.setImplementation(new Object() {
+			public void add() {
+				e.step();
+			}
+			public void remove() {
+				e.step();
+			}
+		});
+		// start component
+		c.start();
+		Dependency d1 = new DependencyImpl();
+		d1.setCallbacks("add", "remove");
+		Dependency d2 = new DependencyImpl();
+		d2.setCallbacks("add", "remove");
+		c.add(d1);
+		c.add(d2);
+		// add three instances to first dependency, no callbacks should
+		// be triggered
+		d1.add(new EventImpl(1));
+		d1.add(new EventImpl(2));
+		d1.add(new EventImpl(3));
+		e.step(1);
+		// add two instances to the second dependency, callbacks should
+		// be invoked (4x)
+		d2.add(new EventImpl(1));
+		e.step(6);
+		// add another dependency, triggering another callback
+		d2.add(new EventImpl(2));
+		e.step(8);
+		// remove first dependency (all three of them) which makes the 
+		// component unavailable so it should trigger calling remove for
+		// all of them (so 5x)
+		d1.remove(new EventImpl(1));
+		d1.remove(new EventImpl(2));
+		d1.remove(new EventImpl(3));
+		e.step(14);
+		// remove second dependency, should not trigger further callbacks
+		d2.remove(new EventImpl(1));
+		d2.remove(new EventImpl(2));
+		e.step(15);
+		c.remove(d2);
+		c.remove(d1);
+		c.stop();
+		e.step(16);
+		Assert.assertEquals("component stopped, should be unavailable again", false, c.isAvailable());
+	}
 }



Mime
View raw message