@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 reproduces functionality used in Monterey, for Venue entity being told of requestActor
  @Test
  public void testSubscribeToJmxNotificationAndEmitCorrespondingNotificationSensor()
      throws Exception {
    TestApplication app2 = new TestApplicationImpl();
    final EntityWithEmitter entity = new EntityWithEmitter(app2);
    Entities.startManagement(app2);
    try {
      app2.start(ImmutableList.of(new SimulatedLocation()));

      final List<SensorEvent<String>> received = Lists.newArrayList();
      app2.subscriptions()
          .subscribe(
              null,
              EntityWithEmitter.MY_NOTIF,
              new SensorEventListener<String>() {
                public void onEvent(SensorEvent<String> event) {
                  received.add(event);
                }
              });

      final StandardEmitterMBean mbean =
          jmxService.registerMBean(ImmutableList.of("one"), objectName);
      final AtomicInteger sequence = new AtomicInteger(0);

      jmxHelper.connect(TIMEOUT_MS);
      jmxHelper.addNotificationListener(
          jmxObjectName,
          new NotificationListener() {
            public void handleNotification(Notification notif, Object callback) {
              if (notif.getType().equals("one")) {
                entity.sensors().emit(EntityWithEmitter.MY_NOTIF, (String) notif.getUserData());
              }
            }
          });

      Asserts.succeedsEventually(
          ImmutableMap.of("timeout", TIMEOUT_MS),
          new Runnable() {
            public void run() {
              sendNotification(mbean, "one", sequence.getAndIncrement(), "abc");
              assertTrue(received.size() > 0, "received size should be bigger than 0");
              assertEquals(received.get(0).getValue(), "abc");
            }
          });
    } finally {
      Entities.destroyAll(app2.getManagementContext());
    }
  }
  @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);
  }