You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2016/02/01 18:48:54 UTC

[24/50] brooklyn-server git commit: Adds JMX reachable listener, for setting service-down

Adds JMX reachable listener, for setting service-down

- adds JmxReachableAdapter, for responding to MBean not-reachable
- adds AbstractPollHelper.polledListeners (rather than
  just setting sensors)
- JmxAttributeAdapter:
-- don't wait 15 seconds for MBean to exist during activate
-- and catch exception if connect exception
- tests JmxSensorAdapter for when jmx service/mbean unreachable
- tests/fixes web-apps for kill, that they report service-down


Project: http://git-wip-us.apache.org/repos/asf/brooklyn-server/repo
Commit: http://git-wip-us.apache.org/repos/asf/brooklyn-server/commit/79ddd7e9
Tree: http://git-wip-us.apache.org/repos/asf/brooklyn-server/tree/79ddd7e9
Diff: http://git-wip-us.apache.org/repos/asf/brooklyn-server/diff/79ddd7e9

Branch: refs/heads/0.4.0
Commit: 79ddd7e921f6614f706afc5136087b7c685d5b27
Parents: 191fa83
Author: Aled Sage <al...@gmail.com>
Authored: Sat Oct 6 15:30:32 2012 +0100
Committer: Aled Sage <al...@gmail.com>
Committed: Tue Oct 9 10:01:36 2012 +0100

----------------------------------------------------------------------
 .../event/adapter/AbstractPollHelper.groovy     | 14 +++-
 .../event/adapter/AbstractSensorAdapter.groovy  | 10 +--
 .../event/adapter/JmxAttributeAdapter.groovy    | 15 ++--
 .../java/brooklyn/event/adapter/JmxHelper.java  |  2 +-
 .../event/adapter/JmxObjectNameAdapter.groovy   |  5 ++
 .../event/adapter/JmxReachableAdapter.java      | 78 ++++++++++++++++++++
 .../event/adapter/SensorRegistry.groovy         | 10 +--
 .../java/brooklyn/util/GroovyJavaMethods.groovy |  4 +-
 .../event/adapter/JmxSensorAdapterTest.groovy   | 55 +++++++++++++-
 9 files changed, 173 insertions(+), 20 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/79ddd7e9/core/src/main/java/brooklyn/event/adapter/AbstractPollHelper.groovy
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/adapter/AbstractPollHelper.groovy b/core/src/main/java/brooklyn/event/adapter/AbstractPollHelper.groovy
index d412b64..51b3107 100644
--- a/core/src/main/java/brooklyn/event/adapter/AbstractPollHelper.groovy
+++ b/core/src/main/java/brooklyn/event/adapter/AbstractPollHelper.groovy
@@ -18,6 +18,8 @@ public abstract class AbstractPollHelper {
 
     final Map<AttributeSensor, Closure> polledSensors = [:]
 
+    final List<Closure> polledListeners = []
+
     boolean lastWasSuccessful = false;
 
     AbstractSensorAdapter adapter;
@@ -32,6 +34,10 @@ public abstract class AbstractPollHelper {
         if (old!=null) log.warn "change of provider (discouraged) for sensor ${s} on ${entity}", new Throwable("path of discouraged change");
     }
 
+    public void addListener(Closure c) {
+        polledListeners.add(c)
+    }
+
     ScheduledTask schedule;
 
     protected activatePoll() {
@@ -50,7 +56,7 @@ public abstract class AbstractPollHelper {
     }
 
     protected boolean isEmpty() {
-        polledSensors.isEmpty();
+        polledSensors.isEmpty() && polledListeners.isEmpty();
     }
     
     /** implementation-specific generation of AbstractSensorEvaluationContext which is then typically passed to evaluateSensorsOnPollResponse */
@@ -87,6 +93,12 @@ public abstract class AbstractPollHelper {
 
     void evaluateSensorsOnResponse(AbstractSensorEvaluationContext response) {
         polledSensors.each { s, c -> evaluateSensorOnResponse(s, c, response) }
+        polledListeners.each {
+            Object v = response.evaluate({it})
+            if (v != AbstractSensorEvaluationContext.UNSET) {
+                it.call(v)
+            }
+        }
     }
 
     Object evaluateSensorOnResponse(Sensor<?> s, Closure c, AbstractSensorEvaluationContext response) {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/79ddd7e9/core/src/main/java/brooklyn/event/adapter/AbstractSensorAdapter.groovy
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/adapter/AbstractSensorAdapter.groovy b/core/src/main/java/brooklyn/event/adapter/AbstractSensorAdapter.groovy
index 4092c01..8107cad 100644
--- a/core/src/main/java/brooklyn/event/adapter/AbstractSensorAdapter.groovy
+++ b/core/src/main/java/brooklyn/event/adapter/AbstractSensorAdapter.groovy
@@ -44,22 +44,22 @@ public abstract class AbstractSensorAdapter {
 		registry.addActivationLifecycleListeners({ activateAdapter() }, { deactivateAdapter() })
 	}
 	
-	private List<Closure> activationListeners = []
-	private List<Closure> deactivationListeners = []
-	protected void addActivationLifecycleListeners(Closure onUp, Closure onDown) {
+	private List<Runnable> activationListeners = []
+	private List<Runnable> deactivationListeners = []
+	protected void addActivationLifecycleListeners(Runnable onUp, Runnable onDown) {
 		activationListeners << onUp
 		deactivationListeners << onDown
 	}
 	protected void activateAdapter() {
         if (activated) return; //prevent double activation
 		if (log.isDebugEnabled()) log.debug "activating adapter {} for {}", this, entity
-		activationListeners.each { it.call() }
+		activationListeners.each { it.run() }
 		activated = true;
 	}
 	protected void deactivateAdapter() {
 		if (log.isDebugEnabled()) log.debug "deactivating adapter {} for {}", this, entity
 		activated = false;
-		deactivationListeners.each { it.call() }
+		deactivationListeners.each { it.run() }
 	}
 
 	protected boolean isConnected() { isActivated() }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/79ddd7e9/core/src/main/java/brooklyn/event/adapter/JmxAttributeAdapter.groovy
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/adapter/JmxAttributeAdapter.groovy b/core/src/main/java/brooklyn/event/adapter/JmxAttributeAdapter.groovy
index d76be3d..a917ece 100644
--- a/core/src/main/java/brooklyn/event/adapter/JmxAttributeAdapter.groovy
+++ b/core/src/main/java/brooklyn/event/adapter/JmxAttributeAdapter.groovy
@@ -1,5 +1,6 @@
 package brooklyn.event.adapter;
 
+import groovy.time.TimeDuration
 import groovy.transform.InheritConstructors
 
 import javax.management.ObjectName
@@ -65,11 +66,15 @@ public class JmxAttributeAdapter extends AbstractSensorAdapter {
     @Override
     protected void activateAdapter() {
         super.activateAdapter();
-        if (adapter.checkObjectNameExists(objectName)) {
-            if (log.isDebugEnabled()) 
-                log.debug("For $entity ${adapter.helper.url}, MBean ${objectName} exists");
-        } else {
-            log.warn("For $entity ${adapter.helper.url}, MBean ${objectName} does not yet exist; continuing...");
+        try {
+            if (adapter.checkObjectNameExists(objectName, new TimeDuration(0, 0, 0, 0))) {
+                if (log.isDebugEnabled()) 
+                    log.debug("For $entity ${adapter.helper.url}, MBean ${objectName} exists");
+            } else {
+                log.warn("For $entity ${adapter.helper.url}, MBean ${objectName} does not yet exist; continuing...");
+            }
+        } catch (Exception e) {
+            log.warn("For $entity ${adapter.helper.url}, not reachable for MBean ${objectName}; continuing...", e);
         }
     }
 }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/79ddd7e9/core/src/main/java/brooklyn/event/adapter/JmxHelper.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/adapter/JmxHelper.java b/core/src/main/java/brooklyn/event/adapter/JmxHelper.java
index 194833f..9664c4f 100644
--- a/core/src/main/java/brooklyn/event/adapter/JmxHelper.java
+++ b/core/src/main/java/brooklyn/event/adapter/JmxHelper.java
@@ -225,7 +225,7 @@ public class JmxHelper {
         int attempt = 0;
         while (currentTime <= endMs) {
             currentTime = System.currentTimeMillis();
-            if (attempt != 0) sleep(100); //sleep 100 to prevent trashing and facilitate interruption
+            if (attempt != 0) sleep(100); //sleep 100 to prevent thrashing and facilitate interruption
             if (LOG.isTraceEnabled()) LOG.trace("trying connection to {} at time {}", url, currentTime);
 
             try {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/79ddd7e9/core/src/main/java/brooklyn/event/adapter/JmxObjectNameAdapter.groovy
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/adapter/JmxObjectNameAdapter.groovy b/core/src/main/java/brooklyn/event/adapter/JmxObjectNameAdapter.groovy
index 8a87cf4..d923e45 100644
--- a/core/src/main/java/brooklyn/event/adapter/JmxObjectNameAdapter.groovy
+++ b/core/src/main/java/brooklyn/event/adapter/JmxObjectNameAdapter.groovy
@@ -18,6 +18,11 @@ public class JmxObjectNameAdapter {
 		this.adapter = adapter;
 		this.objectName = objectName;
 	}
+    
+    JmxReachableAdapter reachable(Map flags=[:]) {
+        adapter.registry.register(new JmxReachableAdapter(flags, adapter, objectName));
+    }
+
 	JmxAttributeAdapter attribute(Map flags=[:], String attributeName) {
 		adapter.registry.register(new JmxAttributeAdapter(flags, adapter, objectName, attributeName));
 	}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/79ddd7e9/core/src/main/java/brooklyn/event/adapter/JmxReachableAdapter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/adapter/JmxReachableAdapter.java b/core/src/main/java/brooklyn/event/adapter/JmxReachableAdapter.java
new file mode 100644
index 0000000..e83b1ab
--- /dev/null
+++ b/core/src/main/java/brooklyn/event/adapter/JmxReachableAdapter.java
@@ -0,0 +1,78 @@
+package brooklyn.event.adapter;
+
+import groovy.lang.Closure;
+
+import java.util.Map;
+
+import javax.management.ObjectName;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import brooklyn.util.GroovyJavaMethods;
+import brooklyn.util.MutableMap;
+
+import com.google.common.base.Function;
+
+
+/** 
+ * Adapter that polls for a JMX attribute.
+ * "Attribute" here refers to the JMX concept, rather than the brooklyn concept.
+ * 
+ * @see {@link JmxSensorAdapter} for recommended way of using this
+ */
+public class JmxReachableAdapter extends AbstractSensorAdapter {
+    private static final Logger LOG = LoggerFactory.getLogger(JmxReachableAdapter.class);
+    
+	final JmxSensorAdapter adapter;
+	final ObjectName objectName;
+	final ReachablePollHelper poller;
+
+	public JmxReachableAdapter(JmxSensorAdapter adapter, ObjectName objectName) {
+	    this(MutableMap.of(), adapter, objectName);
+	}
+	public JmxReachableAdapter(Map flags, JmxSensorAdapter adapter, ObjectName objectName) {
+		super(flags);
+		this.adapter = adapter;
+        adapter.addActivationLifecycleListeners(
+                new Runnable() { public void run() { activateAdapter(); } },
+                new Runnable() { public void run() { deactivateAdapter(); } });
+		poller = new ReachablePollHelper(adapter, objectName);
+		this.objectName = objectName;
+	}
+	
+	static class ReachablePollHelper extends AbstractPollHelper {
+		JmxSensorAdapter adapter;
+		ObjectName objectName;
+		ReachablePollHelper(JmxSensorAdapter adapter, ObjectName objectName) {
+			super(adapter);
+			this.adapter = adapter;
+			this.objectName = objectName;
+		}
+		@Override
+		protected AbstractSensorEvaluationContext executePollOnSuccess() {
+		    SingleValueResponseContext result = new SingleValueResponseContext();
+		    try {
+		        result.setValue(adapter.getHelper().findMBean(objectName) != null);
+		    } catch (Exception e) {
+		        if (LOG.isDebugEnabled()) LOG.debug("Error for "+getEntity()+" "+adapter.getHelper().getUrl()+
+		                ", finding MBean "+objectName+"; assuming unreachable", e);
+		        result.setValue(false);
+		    }
+		    return result;
+		}
+	}
+	
+	public void poll(Closure listener) {
+		poller.addListener(listener);
+	}
+	
+    public void poll(Function<Boolean, Void> listener) {
+        poller.addListener(GroovyJavaMethods.closureFromFunction(listener));
+    }
+    
+    @Override
+    protected void activateAdapter() {
+        super.activateAdapter();
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/79ddd7e9/core/src/main/java/brooklyn/event/adapter/SensorRegistry.groovy
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/event/adapter/SensorRegistry.groovy b/core/src/main/java/brooklyn/event/adapter/SensorRegistry.groovy
index 5246ef3..c122afd 100644
--- a/core/src/main/java/brooklyn/event/adapter/SensorRegistry.groovy
+++ b/core/src/main/java/brooklyn/event/adapter/SensorRegistry.groovy
@@ -81,20 +81,20 @@ public class SensorRegistry {
 	
 	boolean activated = false;
 	
-	private List<Closure> activationListeners = []
-	private List<Closure> deactivationListeners = []
-	void addActivationLifecycleListeners(Closure onUp, Closure onDown) {
+	private List<Runnable> activationListeners = []
+	private List<Runnable> deactivationListeners = []
+	void addActivationLifecycleListeners(Runnable onUp, Runnable onDown) {
 		activationListeners << onUp
 		deactivationListeners << onDown
 	}
 	public void activateAdapters() {
 		if (log.isDebugEnabled()) log.debug "activating adapters at sensor registry for {}", this, entity
 		activated = true;
-		activationListeners.each { it.call() }
+		activationListeners.each { it.run() }
 	}
 	public void deactivateAdapters() {
 		if (log.isDebugEnabled()) log.debug "deactivating adapters at sensor registry for {}", this, entity
-		deactivationListeners.each { it.call() }
+		deactivationListeners.each { it.run() }
 	}
 
 	public void close() {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/79ddd7e9/core/src/main/java/brooklyn/util/GroovyJavaMethods.groovy
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/util/GroovyJavaMethods.groovy b/core/src/main/java/brooklyn/util/GroovyJavaMethods.groovy
index 24cdb55..edbbd76 100644
--- a/core/src/main/java/brooklyn/util/GroovyJavaMethods.groovy
+++ b/core/src/main/java/brooklyn/util/GroovyJavaMethods.groovy
@@ -13,8 +13,8 @@ import com.google.common.base.Predicate
 public class GroovyJavaMethods {
 
     //TODO use named subclasses, would that be more efficient?
-    
-    // TODO xFromY nethods not in correct class: they are not "handy method available in groovy"?
+
+    // TODO xFromY methods not in correct class: they are not "handy method available in groovy"?
     public static Closure closureFromRunnable(final Runnable job) {
         return {
             if (job in Callable) { return job.call() }

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/79ddd7e9/core/src/test/java/brooklyn/event/adapter/JmxSensorAdapterTest.groovy
----------------------------------------------------------------------
diff --git a/core/src/test/java/brooklyn/event/adapter/JmxSensorAdapterTest.groovy b/core/src/test/java/brooklyn/event/adapter/JmxSensorAdapterTest.groovy
index b154822..99351d0 100644
--- a/core/src/test/java/brooklyn/event/adapter/JmxSensorAdapterTest.groovy
+++ b/core/src/test/java/brooklyn/event/adapter/JmxSensorAdapterTest.groovy
@@ -2,7 +2,6 @@ package brooklyn.event.adapter
 
 import static org.testng.Assert.*
 
-import java.util.Map
 import java.util.concurrent.TimeUnit
 import java.util.concurrent.atomic.AtomicInteger
 
@@ -60,11 +59,14 @@ public class JmxSensorAdapterTest {
     private JmxHelper jmxHelper
     
     private BasicAttributeSensor<Integer> intAttribute = [ Integer, "brooklyn.test.intAttribute", "Brooklyn testing int attribute" ]
+    private BasicAttributeSensor<Boolean> boolAttribute = [ Boolean, "brooklyn.test.boolAttribute", "Brooklyn testing bool attribute" ]
     private BasicAttributeSensor<String> stringAttribute = [ String, "brooklyn.test.stringAttribute", "Brooklyn testing string attribute" ]
     private BasicAttributeSensor<Map> mapAttribute = [ Map, "brooklyn.test.mapAttribute", "Brooklyn testing map attribute" ]
     private String objectName = 'Brooklyn:type=MyTestMBean,name=myname'
+    private String wrongObjectName = 'Brooklyn:type=MyTestMBean,name=wrongname'
     private ObjectName jmxObjectName = new ObjectName('Brooklyn:type=MyTestMBean,name=myname')
     private String attributeName = 'myattrib'
+    private String wrongAttributeName = 'wrongattrib'
     private String opName = 'myop'
     
     @BeforeMethod(alwaysRun=true)
@@ -117,6 +119,57 @@ public class JmxSensorAdapterTest {
         }
     }
 
+    @Test
+    public void jmxPollerWillPollEvenIfOnlyConnectsAfterActivatingAdapters() {
+        jmxService.shutdown();
+        
+        jmxAdapter.setJmxConnectionTimeout(0);
+        jmxAdapter.objectName(objectName).with {
+            attribute(attributeName).subscribe(intAttribute)
+        }
+        registry.activateAdapters()
+
+        jmxService = new JmxService(entity);
+        GeneralisedDynamicMBean mbean = jmxService.registerMBean(objectName, (attributeName): 42)
+        
+        // Retrieves value after JMX Service becomes available
+        TestUtils.executeUntilSucceeds(timeout:TIMEOUT) {
+            assertEquals entity.getAttribute(intAttribute), 42
+        }
+    }
+
+    @Test(enabled=false)
+    public void jmxReachablePollerRespondsToConnectException() {
+        jmxService.shutdown();
+        
+        boolean isup = true;
+        
+        jmxAdapter.setJmxConnectionTimeout(10);
+        jmxAdapter.objectName(wrongObjectName).with {
+            reachable().poll( { isup = it } )
+        }
+        registry.activateAdapters()
+        
+        TestUtils.executeUntilSucceeds(timeout:TIMEOUT) {
+            assertFalse(isup);
+        }
+    }
+
+    @Test
+    public void jmxReachablePollerRespondsToMBeanNotFound() {
+        GeneralisedDynamicMBean mbean = jmxService.registerMBean(objectName, (attributeName): 42)
+        boolean isup = true;
+        
+        jmxAdapter.objectName(wrongObjectName).with {
+            reachable().poll( { isup = it } )
+        }
+        registry.activateAdapters()
+        
+        TestUtils.executeUntilSucceeds(timeout:TIMEOUT) {
+            assertFalse(isup);
+        }
+    }
+
     @Test(expectedExceptions=[IllegalStateException.class])
     public void jmxCheckInstanceExistsEventuallyThrowsIfNotFound() {
         jmxHelper.connect(TIMEOUT)