You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by gr...@apache.org on 2014/11/11 19:32:39 UTC

[3/5] incubator-brooklyn git commit: Tidy up sensor addition code

Tidy up sensor addition code


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

Branch: refs/heads/master
Commit: e0b6ed1fb6c2d93e2dee5eb51c0de6b87d1c3926
Parents: 8285297
Author: Andrew Kennedy <gr...@apache.org>
Authored: Sat Nov 8 02:30:20 2014 +0000
Committer: Andrew Kennedy <gr...@apache.org>
Committed: Sat Nov 8 16:41:51 2014 +0000

----------------------------------------------------------------------
 .../brooklyn/entity/effector/AddSensor.java     | 62 +++++++++------
 .../entity/software/http/HttpRequestSensor.java | 55 +++++++------
 .../software/java/JmxAttributeSensor.java       | 48 ++++++-----
 .../entity/software/ssh/SshCommandSensor.java   | 84 +++++++++++---------
 4 files changed, 137 insertions(+), 112 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e0b6ed1f/core/src/main/java/brooklyn/entity/effector/AddSensor.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/brooklyn/entity/effector/AddSensor.java b/core/src/main/java/brooklyn/entity/effector/AddSensor.java
index 3dfa91b..040f168 100644
--- a/core/src/main/java/brooklyn/entity/effector/AddSensor.java
+++ b/core/src/main/java/brooklyn/entity/effector/AddSensor.java
@@ -18,13 +18,14 @@
  */
 package brooklyn.entity.effector;
 
+import java.util.Map;
+
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.EntityInternal;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.entity.proxying.EntityInitializer;
 import brooklyn.event.AttributeSensor;
-import brooklyn.event.Sensor;
 import brooklyn.event.basic.Sensors;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.time.Duration;
@@ -33,47 +34,54 @@ import com.google.common.annotations.Beta;
 import com.google.common.base.Preconditions;
 
 /**
- * Creates a new sensor. The configuration can include the sensor {@code name} and {@code targetType}.
- * For the targetType, currently this only supports classes on the initial classpath
- * (e.g. not those in OSGi bundles added at runtime).
+ * Creates a new {@link AttributeSensor} on an entity.
+ * <p>
+ * The configuration can include the sensor {@code name}, {@code period} and {@code targetType}.
+ * For the targetType, currently this only supports classes on the initial classpath, not those in
+ * OSGi bundles added at runtime.
+ *
  * @since 0.7.0
- * */
+ */
 @Beta
-public class AddSensor<RT,T extends Sensor<RT>> implements EntityInitializer {
-    protected final T sensor;
-    public static final ConfigKey<String> SENSOR_NAME = ConfigKeys.newStringConfigKey("name");
+public class AddSensor<T> implements EntityInitializer {
+
+    public static final ConfigKey<String> SENSOR_NAME = ConfigKeys.newStringConfigKey("name", "The name of the sensor to create");
     public static final ConfigKey<Duration> SENSOR_PERIOD = ConfigKeys.newConfigKey(Duration.class, "period", "Period, including units e.g. 1m or 5s or 200ms; default 5 minutes", Duration.FIVE_MINUTES);
     public static final ConfigKey<String> SENSOR_TYPE = ConfigKeys.newStringConfigKey("targetType", "Target type for the value; default String", "String");
 
-    public AddSensor(T sensor) {
-        this.sensor = Preconditions.checkNotNull(sensor, "sensor");
-    }
-    
-    @Override
-    public void apply(EntityLocal entity) {
-        ((EntityInternal)entity).getMutableEntityType().addSensor(sensor);
+    protected final String name;
+    protected final Duration period;
+    protected final String type;
+    protected final AttributeSensor<T> sensor;
+
+    public AddSensor(Map<String, String> params) {
+        this(ConfigBag.newInstance(params));
     }
 
-    public static <T> AttributeSensor<T> newSensor(Class<T> type, ConfigBag params){
-        String name = Preconditions.checkNotNull(params.get(SENSOR_NAME), "Name must be supplied when defining a sensor");
-        return Sensors.newSensor(type, name);
+    public AddSensor(final ConfigBag params) {
+        this.name = Preconditions.checkNotNull(params.get(SENSOR_NAME), "Name must be supplied when defining a sensor");
+        this.period = params.get(SENSOR_PERIOD);
+        this.type = params.get(SENSOR_TYPE);
+        this.sensor = newSensor();
     }
 
-    @SuppressWarnings("unchecked")
-    public static <T> AttributeSensor<T> newSensor(ConfigBag params) {
-        String name = Preconditions.checkNotNull(params.get(SENSOR_NAME), "Name must be supplied when defining a sensor");
-        String className = getFullClassName(params.get(SENSOR_TYPE));
-        Class<T> type = null;
+    @Override
+    public void apply(EntityLocal entity) {
+        ((EntityInternal) entity).getMutableEntityType().addSensor(sensor);
+    }
 
+    private AttributeSensor<T> newSensor() {
+        String className = getFullClassName(type);
+        Class<T> clazz = null;
         try {
-            type = (Class<T>) Class.forName(className);
+            clazz = (Class<T>) Class.forName(className);
         } catch (ClassNotFoundException e) {
             throw new IllegalArgumentException("Invalid target type for sensor "+name+": " + className);
         }
-        return Sensors.newSensor(type, name);
+        return Sensors.newSensor(clazz, name);
     }
 
-    private static String getFullClassName(String className) {
+    private String getFullClassName(String className) {
         if (className.equalsIgnoreCase("string")) {
             return "java.lang.String";
         } else if (className.equalsIgnoreCase("int") || className.equalsIgnoreCase("integer")) {
@@ -86,6 +94,8 @@ public class AddSensor<RT,T extends Sensor<RT>> implements EntityInitializer {
             return "java.lang.Double";
         } else if (className.equalsIgnoreCase("bool") || className.equalsIgnoreCase("boolean")) {
             return "java.lang.Boolean";
+        } else if (className.equalsIgnoreCase("byte")) {
+            return "java.lang.Byte";
         } else if (className.equalsIgnoreCase("char") || className.equalsIgnoreCase("character")) {
             return "java.lang.Character";
         } else if (className.equalsIgnoreCase("object")) {

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e0b6ed1f/software/base/src/main/java/brooklyn/entity/software/http/HttpRequestSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/http/HttpRequestSensor.java b/software/base/src/main/java/brooklyn/entity/software/http/HttpRequestSensor.java
index 4c4e776..02ddba9 100644
--- a/software/base/src/main/java/brooklyn/entity/software/http/HttpRequestSensor.java
+++ b/software/base/src/main/java/brooklyn/entity/software/http/HttpRequestSensor.java
@@ -18,61 +18,66 @@
  */
 package brooklyn.entity.software.http;
 
+import java.net.URI;
+
+import net.minidev.json.JSONObject;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.entity.effector.AddSensor;
-import brooklyn.event.AttributeSensor;
+import brooklyn.entity.software.java.JmxAttributeSensor;
+import brooklyn.entity.software.ssh.SshCommandSensor;
 import brooklyn.event.feed.http.HttpFeed;
 import brooklyn.event.feed.http.HttpPollConfig;
 import brooklyn.event.feed.http.HttpValueFunctions;
 import brooklyn.util.config.ConfigBag;
-import brooklyn.util.time.Duration;
-import com.google.common.base.Functions;
-import com.google.common.base.Preconditions;
-import org.slf4j.LoggerFactory;
 
 import com.google.common.annotations.Beta;
-
-import java.util.Map;
+import com.google.common.base.Functions;
+import com.google.common.base.Supplier;
 
 /**
  * Configurable {@link brooklyn.entity.proxying.EntityInitializer} which adds an HTTP sensor feed to retrieve the
- * <code>JSONObject</code> from a JSON response in order to populate the sensor with the indicated <code>name</code>.
+ * {@link JSONObject} from a JSON response in order to populate the sensor with the data at the {@code jsonPath}.
  *
  * @see SshCommandSensor
  * @see JmxAttributeSensor
  */
 @Beta
-public final class HttpRequestSensor<T> extends AddSensor<T, AttributeSensor<T>> {
+public final class HttpRequestSensor<T> extends AddSensor<T> {
 
-    private static final org.slf4j.Logger log = LoggerFactory.getLogger(HttpRequestSensor.class);
+    private static final Logger LOG = LoggerFactory.getLogger(HttpRequestSensor.class);
 
-    public static final ConfigKey<String> JSON_PATH = ConfigKeys.newStringConfigKey("jsonPath");
-    public static final ConfigKey<String> SENSOR_URI = ConfigKeys.newStringConfigKey("uri");
+    public static final ConfigKey<String> SENSOR_URI = ConfigKeys.newStringConfigKey("uri", "HTTP URI to poll for JSON");
+    public static final ConfigKey<String> JSON_PATH = ConfigKeys.newStringConfigKey("jsonPath", "JSON path to select in HTTP response; default $", "$");
 
-    private final String jsonPath;
-    private final String uri;
+    protected final Supplier<URI> uri;
+    protected final String jsonPath;
 
-    public HttpRequestSensor(Map<String, String> params) {
-        this(ConfigBag.newInstance(params));
-    }
+    public HttpRequestSensor(final ConfigBag params) {
+        super(params);
 
-    public HttpRequestSensor(ConfigBag params) {
-        super(AddSensor.<T>newSensor(params));
-        jsonPath = Preconditions.checkNotNull(params.get(JSON_PATH), JSON_PATH);
-        uri = Preconditions.checkNotNull(params.get(SENSOR_URI), SENSOR_URI);
+        uri = new Supplier<URI>() {
+            @Override
+            public URI get() {
+                return URI.create(params.get(SENSOR_URI));
+            }
+        };
+        jsonPath = params.get(JSON_PATH);
     }
 
     @Override
     public void apply(final EntityLocal entity) {
         super.apply(entity);
 
-        Duration period = entity.getConfig(SENSOR_PERIOD);
-        if (period==null) period = Duration.ONE_SECOND;
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Adding HTTP JSON sensor {} to {}", name, entity);
+        }
 
-        log.debug("Adding sensor "+sensor+" to "+entity+" polling "+uri+" for "+jsonPath);
-        
         HttpPollConfig<T> pollConfig = new HttpPollConfig<T>(sensor)
                 .checkSuccess(HttpValueFunctions.responseCodeEquals(200))
                 .onFailureOrException(Functions.constant((T) null))

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e0b6ed1f/software/base/src/main/java/brooklyn/entity/software/java/JmxAttributeSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/java/JmxAttributeSensor.java b/software/base/src/main/java/brooklyn/entity/software/java/JmxAttributeSensor.java
index 00280c7..d468750 100644
--- a/software/base/src/main/java/brooklyn/entity/software/java/JmxAttributeSensor.java
+++ b/software/base/src/main/java/brooklyn/entity/software/java/JmxAttributeSensor.java
@@ -18,9 +18,12 @@
  */
 package brooklyn.entity.software.java;
 
-import java.util.Map;
 import java.util.concurrent.Callable;
 
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+
+import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import brooklyn.config.ConfigKey;
@@ -30,7 +33,6 @@ import brooklyn.entity.effector.AddSensor;
 import brooklyn.entity.java.UsesJmx;
 import brooklyn.entity.software.http.HttpRequestSensor;
 import brooklyn.entity.software.ssh.SshCommandSensor;
-import brooklyn.event.AttributeSensor;
 import brooklyn.event.basic.DependentConfiguration;
 import brooklyn.event.feed.jmx.JmxAttributePollConfig;
 import brooklyn.event.feed.jmx.JmxFeed;
@@ -53,27 +55,30 @@ import com.google.common.base.Preconditions;
  * @see HttpRequestSensor
  */
 @Beta
-public final class JmxAttributeSensor<T> extends AddSensor<T, AttributeSensor<T>> {
-
-    private static final org.slf4j.Logger log = LoggerFactory.getLogger(JmxAttributeSensor.class);
+public final class JmxAttributeSensor<T> extends AddSensor<T> {
 
-    public static final ConfigKey<String> OBJECT_NAME = ConfigKeys.newStringConfigKey("objectName");
-    public static final ConfigKey<String> ATTRIBUTE = ConfigKeys.newStringConfigKey("attribute");
-    public static final ConfigKey<Object> DEFAULT_VALUE = ConfigKeys.newConfigKey(Object.class, "default");
+    private static final Logger LOG = LoggerFactory.getLogger(JmxAttributeSensor.class);
 
-    private final String objectName;
-    private final String attribute;
-    private final Object defaultValue;
+    public static final ConfigKey<String> OBJECT_NAME = ConfigKeys.newStringConfigKey("objectName", "JMX object name for sensor lookup");
+    public static final ConfigKey<String> ATTRIBUTE = ConfigKeys.newStringConfigKey("attribute", "JMX attribute to poll in object");
+    public static final ConfigKey<Object> DEFAULT_VALUE = ConfigKeys.newConfigKey(Object.class, "defaultValue", "Default value for sensor; normally null");
 
-    public JmxAttributeSensor(Map<String, String> params) {
-        this(ConfigBag.newInstance(params));
-    }
+    protected final String objectName;
+    protected final String attribute;
+    protected final Object defaultValue;
 
-    public JmxAttributeSensor(ConfigBag params) {
-        super(AddSensor.<T>newSensor(params));
-        objectName = Preconditions.checkNotNull(params.get(OBJECT_NAME), OBJECT_NAME);
-        attribute = Preconditions.checkNotNull(params.get(ATTRIBUTE), ATTRIBUTE);
+    public JmxAttributeSensor(final ConfigBag params) {
+        super(params);
+ 
+        objectName = Preconditions.checkNotNull(params.get(OBJECT_NAME), "objectName");
+        attribute = Preconditions.checkNotNull(params.get(ATTRIBUTE), "attribute");
         defaultValue = params.get(DEFAULT_VALUE);
+
+        try {
+            ObjectName.getInstance(objectName);
+        } catch (MalformedObjectNameException mone) {
+            throw new IllegalArgumentException("Malformed JMX object name: " + objectName, mone);
+        }
     }
 
     @Override
@@ -81,8 +86,8 @@ public final class JmxAttributeSensor<T> extends AddSensor<T, AttributeSensor<T>
         super.apply(entity);
 
         if (entity instanceof UsesJmx) {
-            if (log.isDebugEnabled()) {
-                log.debug("Submitting task to add JMX sensor "+sensor+" to "+entity+" polling "+objectName+" for "+attribute);
+            if (LOG.isDebugEnabled()) {
+                LOG.debug("Submitting task to add JMX sensor {} to {}", name, entity);
             }
 
             Task<Integer> jmxPortTask = DependentConfiguration.attributeWhenReady(entity, UsesJmx.JMX_PORT);
@@ -103,8 +108,7 @@ public final class JmxAttributeSensor<T> extends AddSensor<T, AttributeSensor<T>
                                             .attributeName(attribute)
                                             .onFailureOrException(Functions.<T>constant((T) defaultValue)))
                                     .build();
-                            feed.start();
-                            return feed;
+                           return feed;
                         }
                     })
                     .build();

http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/e0b6ed1f/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandSensor.java
----------------------------------------------------------------------
diff --git a/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandSensor.java b/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandSensor.java
index 56bc7d4..2f75780 100644
--- a/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandSensor.java
+++ b/software/base/src/main/java/brooklyn/entity/software/ssh/SshCommandSensor.java
@@ -20,89 +20,95 @@ package brooklyn.entity.software.ssh;
 
 import java.util.Map;
 
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
 import brooklyn.config.ConfigKey;
 import brooklyn.entity.basic.ConfigKeys;
 import brooklyn.entity.basic.EntityLocal;
 import brooklyn.entity.basic.SoftwareProcess;
 import brooklyn.entity.effector.AddSensor;
 import brooklyn.entity.proxying.EntityInitializer;
-import brooklyn.event.AttributeSensor;
+import brooklyn.entity.software.http.HttpRequestSensor;
+import brooklyn.entity.software.java.JmxAttributeSensor;
 import brooklyn.event.feed.ssh.SshFeed;
 import brooklyn.event.feed.ssh.SshPollConfig;
 import brooklyn.event.feed.ssh.SshValueFunctions;
 import brooklyn.util.collections.MutableMap;
 import brooklyn.util.config.ConfigBag;
 import brooklyn.util.text.Strings;
-import brooklyn.util.time.Duration;
 
+import com.google.common.annotations.Beta;
 import com.google.common.base.Functions;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Supplier;
 
 /** 
  * Configurable {@link EntityInitializer} which adds an SSH sensor feed running the <code>command</code> supplied
- * in order to populate the sensor with the indicated <code>name</code>.
+ * in order to populate the sensor with the indicated <code>name</code>. Note that the <code>targetType</code> is ignored,
+ * and always set to {@link String}.
  *
  * @see HttpRequestSensor
  * @see JmxAttributeSensor
  */
 // generics introduced here because we might support a configurable 'targetType` parameter in future, 
 // with automatic casting (e.g. for ints); this way it remains compatible
-public final class SshCommandSensor<T extends String> extends AddSensor<String,AttributeSensor<String>> {
-
-    public static final ConfigKey<String> SENSOR_COMMAND = ConfigKeys.newStringConfigKey("command");
-    
-    String command;
-    
-    public SshCommandSensor(ConfigBag params) {
-        super(newSensor(String.class, params));
-        command = Preconditions.checkNotNull(params.get(SENSOR_COMMAND), SENSOR_COMMAND);
+@Beta
+public final class SshCommandSensor<T extends String> extends AddSensor<String> {
+
+    private static final Logger LOG = LoggerFactory.getLogger(SshCommandSensor.class);
+
+    public static final ConfigKey<String> SENSOR_COMMAND = ConfigKeys.newStringConfigKey("command", "SSH command to execute for sensor");
+
+    protected final String command;
+
+    public SshCommandSensor(final ConfigBag params) {
+        super(params.configure(SENSOR_TYPE, "String"));
+
+        // TODO create a supplier for the command string to support attribute embedding
+        command = Preconditions.checkNotNull(params.get(SENSOR_COMMAND), "command");
     }
-    
+
     @Override
     public void apply(final EntityLocal entity) {
         super.apply(entity);
 
+        if (LOG.isDebugEnabled()) {
+            LOG.debug("Adding SSH sensor {} to {}", name, entity);
+        }
+
         Supplier<Map<String,String>> envSupplier = new Supplier<Map<String,String>>() {
             @Override
             public Map<String, String> get() {
-                Map<String, String> result = MutableMap.of();
-                result.putAll(Strings.toStringMap(entity.getConfig(SoftwareProcess.SHELL_ENVIRONMENT)));
-                // TODO any custom env values?
-                return result;
+                return MutableMap.copyOf(Strings.toStringMap(entity.getConfig(SoftwareProcess.SHELL_ENVIRONMENT)));
             }
         };
-        
+
         Supplier<String> commandSupplier = new Supplier<String>() {
             @Override
             public String get() {
                 String finalCommand = command;
                 String runDir = entity.getAttribute(SoftwareProcess.RUN_DIR);
-                if (runDir!=null) finalCommand = "cd '"+runDir+"'\n"+finalCommand;
+                if (runDir != null) {
+                    finalCommand = "cd '"+runDir+"' && "+finalCommand;
+                }
                 return finalCommand;
             }
         };
-        
-        Duration period = entity.getConfig(SENSOR_PERIOD);
-        
+
         SshPollConfig<String> pollConfig = new SshPollConfig<String>(sensor)
-            .env(envSupplier)
-            .command(commandSupplier)
-            .checkSuccess(SshValueFunctions.exitStatusEquals(0))
-            .onFailureOrException(Functions.constant((String)null))
-            .onSuccess(SshValueFunctions.stdout());
-        
-        if (period!=null) pollConfig.period(period);
-        
-        SshFeed.builder().entity(entity)
-            .onlyIfServiceUp()
-            .poll(pollConfig)
-            .build();
-    }
-    
-    public SshCommandSensor(Map<String,String> params) {
-        this(ConfigBag.newInstance(params));
-    }
+                .period(period)
+                .env(envSupplier)
+                .command(commandSupplier)
+                .checkSuccess(SshValueFunctions.exitStatusEquals(0))
+                .onFailureOrException(Functions.constant((String) null))
+                .onSuccess(SshValueFunctions.stdout());
 
+        SshFeed.builder()
+                .entity(entity)
+                .onlyIfServiceUp()
+                .poll(pollConfig)
+                .build();
+    }
 
 }