@Test
  public void testJmxNotificationSubscriptionForSensorParsingNotification() throws Exception {
    final String one = "notification.one", two = "notification.two";
    final StandardEmitterMBean mbean =
        jmxService.registerMBean(ImmutableList.of(one, two), objectName);
    final AtomicInteger sequence = new AtomicInteger(0);

    feed =
        JmxFeed.builder()
            .entity(entity)
            .subscribeToNotification(
                new JmxNotificationSubscriptionConfig<Integer>(intAttribute)
                    .objectName(objectName)
                    .notificationFilter(JmxNotificationFilters.matchesType(one))
                    .onNotification(
                        new Function<Notification, Integer>() {
                          public Integer apply(Notification notif) {
                            return (Integer) notif.getUserData();
                          }
                        }))
            .build();

    // Notification updates the sensor
    // Note that subscription is done async, so can't just send notification immediately during
    // test.
    Asserts.succeedsEventually(
        ImmutableMap.of("timeout", TIMEOUT_MS),
        new Runnable() {
          public void run() {
            sendNotification(mbean, one, sequence.getAndIncrement(), 123);
            assertEquals(entity.getAttribute(intAttribute), (Integer) 123);
          }
        });
  }
  @Test
  public void testJmxNotificationMultipleSubscriptionUsingListener() throws Exception {
    final String one = "notification.one";
    final String two = "notification.two";
    final StandardEmitterMBean mbean =
        jmxService.registerMBean(ImmutableList.of(one, two), objectName);
    final AtomicInteger sequence = new AtomicInteger(0);

    feed =
        JmxFeed.builder()
            .entity(entity)
            .subscribeToNotification(
                new JmxNotificationSubscriptionConfig<Integer>(intAttribute)
                    .objectName(objectName)
                    .notificationFilter(JmxNotificationFilters.matchesTypes(one, two)))
            .build();

    // Notification updates the sensor
    // Note that subscription is done async, so can't just send notification immediately during
    // test.
    Asserts.succeedsEventually(
        ImmutableMap.of("timeout", TIMEOUT_MS),
        new Runnable() {
          public void run() {
            sendNotification(mbean, one, sequence.getAndIncrement(), 123);
            assertEquals(entity.getAttribute(intAttribute), (Integer) 123);
          }
        });

    // And wildcard means other notifications also received
    sendNotification(mbean, two, sequence.getAndIncrement(), 456);
    assertSensorEventually(intAttribute, 456, TIMEOUT_MS);
  }
  @Test
  public void testJmxOperationWithArgPolledForSensor() throws Exception {
    // This is awful syntax...
    MBeanParameterInfo paramInfo =
        new MBeanParameterInfo("param1", String.class.getName(), "my param1");
    MBeanParameterInfo[] paramInfos = new MBeanParameterInfo[] {paramInfo};
    MBeanOperationInfo opInfo =
        new MBeanOperationInfo(
            opName, "my descr", paramInfos, String.class.getName(), MBeanOperationInfo.ACTION);
    GeneralisedDynamicMBean mbean =
        jmxService.registerMBean(
            Collections.emptyMap(),
            ImmutableMap.of(
                opInfo,
                new Function<Object[], String>() {
                  public String apply(Object[] args) {
                    return args[0] + "suffix";
                  }
                }),
            objectName);

    feed =
        JmxFeed.builder()
            .entity(entity)
            .pollOperation(
                new JmxOperationPollConfig<String>(stringAttribute)
                    .objectName(objectName)
                    .operationName(opName)
                    .operationParams(ImmutableList.of("myprefix")))
            .build();

    assertSensorEventually(stringAttribute, "myprefix" + "suffix", TIMEOUT_MS);
  }
 @AfterMethod(alwaysRun = true)
 public void tearDown() throws Exception {
   if (feed != null) feed.stop();
   if (jmxHelper != null) jmxHelper.disconnect();
   if (jmxService != null) jmxService.shutdown();
   if (app != null) Entities.destroyAll(app.getManagementContext());
   feed = null;
 }
  @Test
  public void testJmxOperationPolledForSensor() throws Exception {
    // This is awful syntax...
    final int opReturnVal = 123;
    final AtomicInteger invocationCount = new AtomicInteger();
    MBeanOperationInfo opInfo =
        new MBeanOperationInfo(
            opName,
            "my descr",
            new MBeanParameterInfo[0],
            Integer.class.getName(),
            MBeanOperationInfo.ACTION);
    GeneralisedDynamicMBean mbean =
        jmxService.registerMBean(
            Collections.emptyMap(),
            ImmutableMap.of(
                opInfo,
                new Function<Object[], Integer>() {
                  public Integer apply(Object[] args) {
                    invocationCount.incrementAndGet();
                    return opReturnVal;
                  }
                }),
            objectName);

    feed =
        JmxFeed.builder()
            .entity(entity)
            .pollOperation(
                new JmxOperationPollConfig<Integer>(intAttribute)
                    .objectName(objectName)
                    .operationName(opName))
            .build();

    Asserts.succeedsEventually(
        ImmutableMap.of("timeout", TIMEOUT_MS),
        new Runnable() {
          public void run() {
            assertTrue(invocationCount.get() > 0, "invocationCount=" + invocationCount);
            assertEquals(entity.getAttribute(intAttribute), (Integer) opReturnVal);
          }
        });
  }
  @Test
  public void testJmxAttributeOfTypeTabularDataProviderConvertedToMap() throws Exception {
    // Create the CompositeType and TabularData
    CompositeType compositeType =
        new CompositeType(
            "typeName",
            "description",
            new String[] {"myint", "mystring", "mybool"}, // item names
            new String[] {
              "myint", "mystring", "mybool"
            }, // item descriptions, can't be null or empty string
            new OpenType<?>[] {SimpleType.INTEGER, SimpleType.STRING, SimpleType.BOOLEAN});
    TabularType tt =
        new TabularType("typeName", "description", compositeType, new String[] {"myint"});
    TabularDataSupport tds = new TabularDataSupport(tt);
    tds.put(
        new CompositeDataSupport(
            compositeType,
            new String[] {"mybool", "myint", "mystring"},
            new Object[] {true, 1234, "on"}));

    // Create MBean
    GeneralisedDynamicMBean mbean =
        jmxService.registerMBean(ImmutableMap.of(attributeName, tds), objectName);

    feed =
        JmxFeed.builder()
            .entity(entity)
            .pollAttribute(
                new JmxAttributePollConfig<Map>(mapAttribute)
                    .objectName(objectName)
                    .attributeName(attributeName)
                    .onSuccess((Function) JmxValueFunctions.tabularDataToMap()))
            .build();

    // Starts with value defined when registering...
    assertSensorEventually(
        mapAttribute,
        ImmutableMap.of("myint", 1234, "mystring", "on", "mybool", Boolean.TRUE),
        TIMEOUT_MS);
  }
  @Test
  public void testJmxAttributePollerReturnsMBeanAttribute() throws Exception {
    GeneralisedDynamicMBean mbean =
        jmxService.registerMBean(ImmutableMap.of(attributeName, 42), objectName);

    feed =
        JmxFeed.builder()
            .entity(entity)
            .pollAttribute(
                new JmxAttributePollConfig<Integer>(intAttribute)
                    .objectName(objectName)
                    .period(50)
                    .attributeName(attributeName))
            .build();

    // Starts with value defined when registering...
    assertSensorEventually(intAttribute, 42, TIMEOUT_MS);

    // Change the value and check it updates
    mbean.updateAttributeValue(attributeName, 64);
    assertSensorEventually(intAttribute, 64, TIMEOUT_MS);
  }