Repository: brooklyn-server
Updated Branches:
  refs/heads/master 9b27d0d45 -> d961de340


Add suppressDuplicates to yaml sensor initializers


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

Branch: refs/heads/master
Commit: 406581c556f804be7df0cdff7824adbcfb2e6564
Parents: 9b27d0d
Author: Aled Sage <[email protected]>
Authored: Mon Aug 14 13:54:34 2017 +0100
Committer: Aled Sage <[email protected]>
Committed: Mon Aug 14 14:57:04 2017 +0100

----------------------------------------------------------------------
 .../camp/brooklyn/SshCommandSensorYamlTest.java |  46 +++++++
 .../core/sensor/http/HttpRequestSensor.java     |   6 +
 .../core/sensor/ssh/SshCommandSensor.java       |   9 ++
 .../core/sensor/http/HttpRequestSensorTest.java |  29 ++++
 .../entity/java/JmxAttributeSensor.java         |  11 +-
 .../entity/java/JmxAttributeSensorTest.java     | 134 +++++++++++++++++++
 .../core/sensor/windows/WinRmCommandSensor.java |  26 ++--
 .../feed/windows/WinRmCommandSensorTest.java    |  33 +++++
 8 files changed, 284 insertions(+), 10 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/406581c5/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/SshCommandSensorYamlTest.java
----------------------------------------------------------------------
diff --git 
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/SshCommandSensorYamlTest.java
 
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/SshCommandSensorYamlTest.java
index cb4473b..09c99ac 100644
--- 
a/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/SshCommandSensorYamlTest.java
+++ 
b/camp/camp-brooklyn/src/test/java/org/apache/brooklyn/camp/brooklyn/SshCommandSensorYamlTest.java
@@ -18,16 +18,23 @@
  */
 package org.apache.brooklyn.camp.brooklyn;
 
+import org.apache.brooklyn.api.entity.Application;
 import org.apache.brooklyn.api.entity.Entity;
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.entity.RecordingSensorEventListener;
 import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.entity.software.base.VanillaSoftwareProcess;
+import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.core.internal.ssh.RecordingSshTool;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import com.google.common.base.Predicates;
 import com.google.common.collect.Iterables;
 
 public class SshCommandSensorYamlTest extends AbstractYamlTest {
@@ -65,6 +72,45 @@ public class SshCommandSensorYamlTest extends 
AbstractYamlTest {
         EntityAsserts.assertAttributeEqualsEventually(entity, 
Sensors.newStringSensor("mySensor"), "myResponse");
     }
     
+    // "Integration" because takes a second 
+    @Test(groups="Integration")
+    public void testSupressingDuplicates() throws Exception {
+        AttributeSensor<String> mySensor = Sensors.newStringSensor("mySensor");
+        
+        RecordingSensorEventListener<String> listener = new 
RecordingSensorEventListener<>();
+        Application tmpApp = 
mgmt().getEntityManager().createEntity(EntitySpec.create(TestApplication.class));
+        tmpApp.subscriptions().subscribe(null, mySensor, listener);
+        
+        RecordingSshTool.setCustomResponse(".*myCommand.*", new 
RecordingSshTool.CustomResponse(0, "myResponse", null));
+        
+        Entity app = createAndStartApplication(
+            "location:",
+            "  localhost:",
+            "    sshToolClass: "+RecordingSshTool.class.getName(),
+            "services:",
+            "- type: " + VanillaSoftwareProcess.class.getName(),
+            "  brooklyn.config:",
+            "    onbox.base.dir.skipResolution: true",
+            "  brooklyn.initializers:",
+            "  - type: org.apache.brooklyn.core.sensor.ssh.SshCommandSensor",
+            "    brooklyn.config:",
+            "      name: mySensor",
+            "      command: myCommand",
+            "      suppressDuplicates: true",
+            "      period: 10ms",
+            "      onlyIfServiceUp: false");
+        waitForApplicationTasks(app);
+
+        VanillaSoftwareProcess entity = (VanillaSoftwareProcess) 
Iterables.getOnlyElement(app.getChildren());
+        EntityAsserts.assertAttributeEqualsEventually(entity, mySensor, 
"myResponse");
+        listener.assertHasEventEventually(Predicates.alwaysTrue());
+        
+        Asserts.succeedsContinually(new Runnable() {
+            @Override public void run() {
+                listener.assertEventCount(1);
+            }});
+    }
+    
     @Override
     protected Logger getLogger() {
         return log;

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/406581c5/core/src/main/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensor.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensor.java
 
b/core/src/main/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensor.java
index 5485471..842bcb4 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensor.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensor.java
@@ -62,6 +62,10 @@ public final class HttpRequestSensor<T> extends AddSensor<T> 
{
     public static final ConfigKey<String> USERNAME = 
ConfigKeys.newStringConfigKey("username", "Username for HTTP request, if 
required");
     public static final ConfigKey<String> PASSWORD = 
ConfigKeys.newStringConfigKey("password", "Password for HTTP request, if 
required");
     public static final ConfigKey<Map<String, String>> HEADERS = new 
MapConfigKey<>(String.class, "headers");
+    public static final ConfigKey<Boolean> SUPPRESS_DUPLICATES = 
ConfigKeys.newBooleanConfigKey(
+            "suppressDuplicates", 
+            "Whether to publish the sensor value again, if it is the same as 
the previous value",
+            Boolean.FALSE);
     
     public static final ConfigKey<Boolean> PREEMPTIVE_BASIC_AUTH = 
ConfigKeys.newBooleanConfigKey(
             "preemptiveBasicAuth",
@@ -96,6 +100,7 @@ public final class HttpRequestSensor<T> extends AddSensor<T> 
{
         final String password = EntityInitializers.resolve(allConfig, 
PASSWORD);
         final Map<String, String> headers = 
EntityInitializers.resolve(allConfig, HEADERS);
         final Boolean preemptiveBasicAuth = 
EntityInitializers.resolve(allConfig, PREEMPTIVE_BASIC_AUTH);
+        final Boolean suppressDuplicates = 
EntityInitializers.resolve(allConfig, SUPPRESS_DUPLICATES);
         
         Function<? super HttpToolResponse, T> successFunction;
         if (Strings.isBlank(jsonPath)) {
@@ -109,6 +114,7 @@ public final class HttpRequestSensor<T> extends 
AddSensor<T> {
                 .checkSuccess(HttpValueFunctions.responseCodeEquals(200))
                 .onFailureOrException(Functions.constant((T) null))
                 .onSuccess(successFunction)
+                .suppressDuplicates(Boolean.TRUE.equals(suppressDuplicates))
                 .period(period);
 
         HttpFeed.Builder httpRequestBuilder = HttpFeed.builder().entity(entity)

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/406581c5/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java 
b/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java
index fc93d74..a5052df 100644
--- 
a/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java
+++ 
b/core/src/main/java/org/apache/brooklyn/core/sensor/ssh/SshCommandSensor.java
@@ -40,6 +40,7 @@ import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.config.MapConfigKey;
 import org.apache.brooklyn.core.effector.AddSensor;
 import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.entity.EntityInitializers;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.sensor.http.HttpRequestSensor;
 import org.apache.brooklyn.feed.AbstractCommandFeed;
@@ -72,6 +73,11 @@ public final class SshCommandSensor<T> extends AddSensor<T> {
         + "use '~' to always execute in the home dir, or 'custom-feed/' to 
execute in a custom-feed dir relative to the run dir");
     public static final MapConfigKey<Object> SENSOR_SHELL_ENVIRONMENT = 
BrooklynConfigKeys.SHELL_ENVIRONMENT;
 
+    public static final ConfigKey<Boolean> SUPPRESS_DUPLICATES = 
ConfigKeys.newBooleanConfigKey(
+            "suppressDuplicates", 
+            "Whether to publish the sensor value again, if it is the same as 
the previous value",
+            Boolean.FALSE);
+
     protected final String command;
     protected final String executionDir;
     protected final Map<String,Object> sensorEnv;
@@ -93,6 +99,8 @@ public final class SshCommandSensor<T> extends AddSensor<T> {
             LOG.debug("Adding SSH sensor {} to {}", name, entity);
         }
 
+        final Boolean suppressDuplicates = EntityInitializers.resolve(params, 
SUPPRESS_DUPLICATES);
+
         Supplier<Map<String,String>> envSupplier = new 
Supplier<Map<String,String>>() {
             @Override
             public Map<String, String> get() {
@@ -125,6 +133,7 @@ public final class SshCommandSensor<T> extends AddSensor<T> 
{
                 .period(period)
                 .env(envSupplier)
                 .command(commandSupplier)
+                .suppressDuplicates(Boolean.TRUE.equals(suppressDuplicates))
                 .checkSuccess(SshValueFunctions.exitStatusEquals(0))
                 .onFailureOrException(Functions.constant((T) null))
                 .onSuccess(Functions.compose(new Function<String, T>() {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/406581c5/core/src/test/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensorTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensorTest.java
 
b/core/src/test/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensorTest.java
index bf6ff1e..636c1c1 100644
--- 
a/core/src/test/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensorTest.java
+++ 
b/core/src/test/java/org/apache/brooklyn/core/sensor/http/HttpRequestSensorTest.java
@@ -27,10 +27,12 @@ import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.Attributes;
 import org.apache.brooklyn.core.entity.Entities;
 import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.entity.RecordingSensorEventListener;
 import org.apache.brooklyn.core.sensor.Sensors;
 import org.apache.brooklyn.core.test.entity.TestApplication;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.feed.http.HttpFeedTest;
+import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.test.http.RecordingHttpRequestHandler;
 import org.apache.brooklyn.test.http.TestHttpRequestHandler;
 import org.apache.brooklyn.test.http.TestHttpServer;
@@ -42,6 +44,7 @@ import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterables;
 
@@ -96,6 +99,32 @@ public class HttpRequestSensorTest {
         EntityAsserts.assertAttributeEqualsEventually(entity, SENSOR_STRING, 
"myValue");
     }
 
+    // "Integration" because takes a second
+    @Test(groups="Integration")
+    @SuppressWarnings("deprecation")
+    public void testHttpSensorSuppressingDuplicates() throws Exception {
+        RecordingSensorEventListener<String> listener = new 
RecordingSensorEventListener<>();
+        entity.subscriptions().subscribe(entity, SENSOR_STRING, listener);
+        
+        HttpRequestSensor<Integer> sensor = new 
HttpRequestSensor<Integer>(ConfigBag.newInstance()
+                .configure(HttpRequestSensor.SUPPRESS_DUPLICATES, true)
+                .configure(HttpRequestSensor.SENSOR_PERIOD, Duration.millis(1))
+                .configure(HttpRequestSensor.SENSOR_NAME, 
SENSOR_STRING.getName())
+                .configure(HttpRequestSensor.SENSOR_TYPE, STRING_TARGET_TYPE)
+                .configure(HttpRequestSensor.JSON_PATH, "$.myKey")
+                .configure(HttpRequestSensor.SENSOR_URI, serverUrl + 
"/myKey/myValue"));
+        sensor.apply((org.apache.brooklyn.api.entity.EntityLocal)entity);
+        entity.sensors().set(Attributes.SERVICE_UP, true);
+
+        EntityAsserts.assertAttributeEqualsEventually(entity, SENSOR_STRING, 
"myValue");
+        listener.assertHasEventEventually(Predicates.alwaysTrue());
+        
+        Asserts.succeedsContinually(new Runnable() {
+            @Override public void run() {
+                listener.assertEventCount(1);
+            }});
+    }
+
     // TODO Fails because doesn't pick up default value of `JSON_PATH`, which 
is `$`
     @Test(groups="Broken")
     @SuppressWarnings("deprecation")

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/406581c5/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
 
b/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
index 851a589..21046ad 100644
--- 
a/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
+++ 
b/software/base/src/main/java/org/apache/brooklyn/entity/java/JmxAttributeSensor.java
@@ -28,6 +28,7 @@ import org.apache.brooklyn.api.mgmt.Task;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.AddSensor;
+import org.apache.brooklyn.core.entity.EntityInitializers;
 import org.apache.brooklyn.core.sensor.DependentConfiguration;
 import org.apache.brooklyn.core.sensor.http.HttpRequestSensor;
 import org.apache.brooklyn.core.sensor.ssh.SshCommandSensor;
@@ -60,10 +61,15 @@ public final class JmxAttributeSensor<T> extends 
AddSensor<T> {
     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 static final ConfigKey<Boolean> SUPPRESS_DUPLICATES = 
ConfigKeys.newBooleanConfigKey(
+            "suppressDuplicates", 
+            "Whether to publish the sensor value again, if it is the same as 
the previous value",
+            Boolean.FALSE);
+
     protected final String objectName;
     protected final String attribute;
     protected final Object defaultValue;
-
+    
     public JmxAttributeSensor(final ConfigBag params) {
         super(params);
 
@@ -82,6 +88,8 @@ public final class JmxAttributeSensor<T> extends AddSensor<T> 
{
     public void apply(final EntityLocal entity) {
         super.apply(entity);
 
+        final Boolean suppressDuplicates = EntityInitializers.resolve(params, 
SUPPRESS_DUPLICATES);
+
         if (entity instanceof UsesJmx) {
             if (LOG.isDebugEnabled()) {
                 LOG.debug("Submitting task to add JMX sensor {} to {}", name, 
entity);
@@ -102,6 +110,7 @@ public final class JmxAttributeSensor<T> extends 
AddSensor<T> {
                                     .pollAttribute(new 
JmxAttributePollConfig<T>(sensor)
                                             .objectName(objectName)
                                             .attributeName(attribute)
+                                            
.suppressDuplicates(Boolean.TRUE.equals(suppressDuplicates))
                                             
.onFailureOrException(Functions.<T>constant((T) defaultValue)))
                                     .build();
                             entity.addFeed(feed);

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/406581c5/software/base/src/test/java/org/apache/brooklyn/entity/java/JmxAttributeSensorTest.java
----------------------------------------------------------------------
diff --git 
a/software/base/src/test/java/org/apache/brooklyn/entity/java/JmxAttributeSensorTest.java
 
b/software/base/src/test/java/org/apache/brooklyn/entity/java/JmxAttributeSensorTest.java
new file mode 100644
index 0000000..22e748e
--- /dev/null
+++ 
b/software/base/src/test/java/org/apache/brooklyn/entity/java/JmxAttributeSensorTest.java
@@ -0,0 +1,134 @@
+/*
+ * 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 org.apache.brooklyn.entity.java;
+
+import org.apache.brooklyn.api.entity.EntitySpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
+import org.apache.brooklyn.core.entity.Attributes;
+import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.entity.RecordingSensorEventListener;
+import org.apache.brooklyn.core.location.SimulatedLocation;
+import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.sensor.http.HttpRequestSensor;
+import org.apache.brooklyn.core.test.BrooklynAppUnitTestSupport;
+import org.apache.brooklyn.core.test.entity.TestEntity;
+import 
org.apache.brooklyn.entity.software.base.test.jmx.GeneralisedDynamicMBean;
+import org.apache.brooklyn.entity.software.base.test.jmx.JmxService;
+import org.apache.brooklyn.feed.jmx.JmxFeedTest.TestEntityWithJmx;
+import org.apache.brooklyn.feed.jmx.JmxHelper;
+import org.apache.brooklyn.test.Asserts;
+import org.apache.brooklyn.util.core.config.ConfigBag;
+import org.apache.brooklyn.util.time.Duration;
+import org.testng.annotations.AfterMethod;
+import org.testng.annotations.BeforeMethod;
+import org.testng.annotations.Test;
+
+import com.google.common.base.Predicates;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+public class JmxAttributeSensorTest extends BrooklynAppUnitTestSupport {
+    final static AttributeSensor<String> SENSOR_STRING = 
Sensors.newStringSensor("aString");
+    final static AttributeSensor<Object> SENSOR_OBJ = 
Sensors.newSensor(Object.class, "anObj");
+    final static String STRING_TARGET_TYPE = "java.lang.String";
+    final static String OBJECT_TARGET_TYPE = "java.lang.Object";
+
+    private TestEntity entity;
+
+    private JmxService jmxService;
+    private JmxHelper jmxHelper;
+    
+    private String objectName = "Brooklyn:type=MyTestMBean,name=myname";
+    private String attributeName = "myattrib";
+
+    @BeforeMethod(alwaysRun=true)
+    @Override
+    public void setUp() throws Exception {
+        super.setUp();
+        
+        // Create an entity and configure it with the above JMX service
+        entity = 
app.createAndManageChild(EntitySpec.create(TestEntity.class).impl(TestEntityWithJmx.class).additionalInterfaces(UsesJmx.class));
+        app.start(ImmutableList.of(new SimulatedLocation()));
+
+        jmxHelper = new JmxHelper(entity);
+        jmxService = new JmxService(entity);
+    }
+    
+    @AfterMethod(alwaysRun=true)
+    public void tearDown() throws Exception {
+        try {
+            if (jmxHelper != null) jmxHelper.disconnect();
+            if (jmxService != null) jmxService.shutdown();
+        } finally {
+            super.tearDown();
+        }
+    }
+
+    @Test
+    public void testSensor() throws Exception {
+        GeneralisedDynamicMBean mbean = 
jmxService.registerMBean(ImmutableMap.of(attributeName, 42), objectName);
+
+        JmxAttributeSensor<Integer> sensor = new 
JmxAttributeSensor<Integer>(ConfigBag.newInstance()
+                .configure(JmxAttributeSensor.SENSOR_PERIOD, 
Duration.millis(10))
+                .configure(JmxAttributeSensor.SENSOR_NAME, 
SENSOR_STRING.getName())
+                .configure(JmxAttributeSensor.SENSOR_TYPE, STRING_TARGET_TYPE)
+                .configure(JmxAttributeSensor.OBJECT_NAME, objectName)
+                .configure(JmxAttributeSensor.ATTRIBUTE, attributeName));
+        sensor.apply(entity);
+        entity.sensors().set(Attributes.SERVICE_UP, true);
+
+        EntityAsserts.assertAttributeEqualsEventually(entity, SENSOR_STRING, 
"42");
+        
+        // Change the value and check it updates
+        mbean.updateAttributeValue(attributeName, 64);
+        EntityAsserts.assertAttributeEqualsEventually(entity, SENSOR_STRING, 
"64");
+    }
+
+    // "Integration" because takes a second 
+    @Test(groups="Integration")
+    public void testSensorSupressingDuplicates() throws Exception {
+        GeneralisedDynamicMBean mbean = 
jmxService.registerMBean(ImmutableMap.of(attributeName, 42), objectName);
+
+        RecordingSensorEventListener<String> listener = new 
RecordingSensorEventListener<>();
+        entity.subscriptions().subscribe(entity, SENSOR_STRING, listener);
+        
+        JmxAttributeSensor<Integer> sensor = new 
JmxAttributeSensor<Integer>(ConfigBag.newInstance()
+                .configure(HttpRequestSensor.SUPPRESS_DUPLICATES, true)
+                .configure(JmxAttributeSensor.SENSOR_PERIOD, 
Duration.millis(10))
+                .configure(JmxAttributeSensor.SENSOR_NAME, 
SENSOR_STRING.getName())
+                .configure(JmxAttributeSensor.SENSOR_TYPE, STRING_TARGET_TYPE)
+                .configure(JmxAttributeSensor.OBJECT_NAME, objectName)
+                .configure(JmxAttributeSensor.ATTRIBUTE, attributeName));
+        sensor.apply(entity);
+        entity.sensors().set(Attributes.SERVICE_UP, true);
+
+        EntityAsserts.assertAttributeEqualsEventually(entity, SENSOR_STRING, 
"42");
+        listener.assertHasEventEventually(Predicates.alwaysTrue());
+        
+        Asserts.succeedsContinually(new Runnable() {
+            @Override public void run() {
+                listener.assertEventCount(1);
+            }});
+        EntityAsserts.assertAttributeEqualsEventually(entity, SENSOR_STRING, 
"42");
+        
+        // Change the value and check it updates
+        mbean.updateAttributeValue(attributeName, 64);
+        EntityAsserts.assertAttributeEqualsEventually(entity, SENSOR_STRING, 
"64");
+    }
+}

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/406581c5/software/winrm/src/main/java/org/apache/brooklyn/core/sensor/windows/WinRmCommandSensor.java
----------------------------------------------------------------------
diff --git 
a/software/winrm/src/main/java/org/apache/brooklyn/core/sensor/windows/WinRmCommandSensor.java
 
b/software/winrm/src/main/java/org/apache/brooklyn/core/sensor/windows/WinRmCommandSensor.java
index ecc0d59..2fcc315 100644
--- 
a/software/winrm/src/main/java/org/apache/brooklyn/core/sensor/windows/WinRmCommandSensor.java
+++ 
b/software/winrm/src/main/java/org/apache/brooklyn/core/sensor/windows/WinRmCommandSensor.java
@@ -18,18 +18,16 @@
  */
 package org.apache.brooklyn.core.sensor.windows;
 
-import com.google.common.annotations.Beta;
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.base.Preconditions;
-import com.google.common.base.Supplier;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+
 import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntityInitializer;
 import org.apache.brooklyn.api.entity.EntityLocal;
 import org.apache.brooklyn.config.ConfigKey;
 import org.apache.brooklyn.core.config.ConfigKeys;
 import org.apache.brooklyn.core.effector.AddSensor;
-import org.apache.brooklyn.core.entity.BrooklynConfigKeys;
+import org.apache.brooklyn.core.entity.EntityInitializers;
 import org.apache.brooklyn.core.entity.EntityInternal;
 import org.apache.brooklyn.core.sensor.http.HttpRequestSensor;
 import org.apache.brooklyn.feed.CommandPollConfig;
@@ -42,13 +40,15 @@ import 
org.apache.brooklyn.util.core.internal.winrm.WinRmTool;
 import org.apache.brooklyn.util.core.json.ShellEnvironmentSerializer;
 import org.apache.brooklyn.util.core.task.Tasks;
 import org.apache.brooklyn.util.exceptions.Exceptions;
-import org.apache.brooklyn.util.os.Os;
 import org.apache.brooklyn.util.text.Strings;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
+import com.google.common.annotations.Beta;
+import com.google.common.base.Function;
+import com.google.common.base.Functions;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Supplier;
 
 /** 
  * Configurable {@link EntityInitializer} which adds an WinRm sensor feed 
running the <code>command</code> supplied
@@ -70,6 +70,11 @@ public final class WinRmCommandSensor<T> extends 
AddSensor<T> {
         + "use '~' to always execute in the home dir, or 'custom-feed/' to 
execute in a custom-feed dir relative to the run dir");
     public static final ConfigKey<Map<String, String>> SENSOR_ENVIRONMENT = 
WinRmTool.ENVIRONMENT;
 
+    public static final ConfigKey<Boolean> SUPPRESS_DUPLICATES = 
ConfigKeys.newBooleanConfigKey(
+            "suppressDuplicates", 
+            "Whether to publish the sensor value again, if it is the same as 
the previous value",
+            Boolean.FALSE);
+
     protected final String command;
     protected final String executionDir;
     protected final Map<String,String> sensorEnv;
@@ -91,6 +96,8 @@ public final class WinRmCommandSensor<T> extends AddSensor<T> 
{
             LOG.debug("Adding WinRM sensor {} to {}", name, entity);
         }
 
+        final Boolean suppressDuplicates = EntityInitializers.resolve(params, 
SUPPRESS_DUPLICATES);
+
         Supplier<Map<String,String>> envSupplier = new 
Supplier<Map<String,String>>() {
             @Override
             public Map<String, String> get() {
@@ -123,6 +130,7 @@ public final class WinRmCommandSensor<T> extends 
AddSensor<T> {
                 .period(period)
                 .env(envSupplier)
                 .command(commandSupplier)
+                .suppressDuplicates(Boolean.TRUE.equals(suppressDuplicates))
                 .checkSuccess(SshValueFunctions.exitStatusEquals(0))
                 .onFailureOrException(Functions.constant((T) null))
                 .onSuccess(Functions.compose(new Function<String, T>() {

http://git-wip-us.apache.org/repos/asf/brooklyn-server/blob/406581c5/software/winrm/src/test/java/org/apache/brooklyn/feed/windows/WinRmCommandSensorTest.java
----------------------------------------------------------------------
diff --git 
a/software/winrm/src/test/java/org/apache/brooklyn/feed/windows/WinRmCommandSensorTest.java
 
b/software/winrm/src/test/java/org/apache/brooklyn/feed/windows/WinRmCommandSensorTest.java
index dcadca0..7bf481c 100644
--- 
a/software/winrm/src/test/java/org/apache/brooklyn/feed/windows/WinRmCommandSensorTest.java
+++ 
b/software/winrm/src/test/java/org/apache/brooklyn/feed/windows/WinRmCommandSensorTest.java
@@ -22,18 +22,23 @@ import org.apache.brooklyn.api.entity.Entity;
 import org.apache.brooklyn.api.entity.EntitySpec;
 import org.apache.brooklyn.api.location.Location;
 import org.apache.brooklyn.api.location.LocationSpec;
+import org.apache.brooklyn.api.sensor.AttributeSensor;
 import org.apache.brooklyn.core.entity.EntityAsserts;
+import org.apache.brooklyn.core.entity.RecordingSensorEventListener;
 import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp;
 import org.apache.brooklyn.core.sensor.Sensors;
+import org.apache.brooklyn.core.sensor.http.HttpRequestSensor;
 import org.apache.brooklyn.core.sensor.windows.WinRmCommandSensor;
 import org.apache.brooklyn.core.test.entity.TestEntity;
 import org.apache.brooklyn.location.winrm.WinRmMachineLocation;
+import org.apache.brooklyn.test.Asserts;
 import org.apache.brooklyn.util.core.config.ConfigBag;
 import org.apache.brooklyn.util.core.internal.winrm.RecordingWinRmTool;
 import org.testng.annotations.AfterMethod;
 import org.testng.annotations.BeforeMethod;
 import org.testng.annotations.Test;
 
+import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 
@@ -78,4 +83,32 @@ public class WinRmCommandSensorTest extends 
RebindTestFixtureWithApp {
         RecordingWinRmTool.setCustomResponse(".*mycommand.*", new 
RecordingWinRmTool.CustomResponse(0, "myval2", ""));
         EntityAsserts.assertAttributeEqualsEventually(entity, 
Sensors.newStringSensor("mysensor"), "myval2");
     }
+    
+    // "Integration" because takes a second 
+    @Test(groups="Integration")
+    public void testSupressingDuplicates() throws Exception {
+        AttributeSensor<String> mySensor = Sensors.newStringSensor("mysensor");
+        
+        RecordingSensorEventListener<String> listener = new 
RecordingSensorEventListener<>();
+        app().subscriptions().subscribe(null, mySensor, listener);
+        
+        RecordingWinRmTool.setCustomResponse(".*mycommand.*", new 
RecordingWinRmTool.CustomResponse(0, "myval", ""));
+        
+        Entity entity = 
app().createAndManageChild(EntitySpec.create(TestEntity.class)
+                .addInitializer(new 
WinRmCommandSensor<String>(ConfigBag.newInstance(ImmutableMap.of(
+                        HttpRequestSensor.SUPPRESS_DUPLICATES, true,
+                        WinRmCommandSensor.SENSOR_PERIOD, "1ms",
+                        WinRmCommandSensor.SENSOR_COMMAND, "mycommand",
+                        WinRmCommandSensor.SENSOR_NAME, 
mySensor.getName())))));
+        
+        app().start(ImmutableList.of(loc));
+
+        EntityAsserts.assertAttributeEqualsEventually(entity, mySensor, 
"myval");
+        listener.assertHasEventEventually(Predicates.alwaysTrue());
+        
+        Asserts.succeedsContinually(new Runnable() {
+            @Override public void run() {
+                listener.assertEventCount(1);
+            }});
+    }
 }

Reply via email to