http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxFeedTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxFeedTest.java b/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxFeedTest.java new file mode 100644 index 0000000..3975e68 --- /dev/null +++ b/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxFeedTest.java @@ -0,0 +1,422 @@ +/* + * 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.feed.jmx; + +import static org.apache.brooklyn.test.TestUtils.executeUntilSucceeds; +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertTrue; + +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.Notification; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.StandardEmitterMBean; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +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.api.sensor.SensorEvent; +import org.apache.brooklyn.api.sensor.SensorEventListener; +import org.apache.brooklyn.core.entity.AbstractEntity; +import org.apache.brooklyn.core.entity.Attributes; +import org.apache.brooklyn.core.entity.Entities; +import org.apache.brooklyn.core.feed.ConfigToAttributes; +import org.apache.brooklyn.core.location.PortRanges; +import org.apache.brooklyn.core.location.SimulatedLocation; +import org.apache.brooklyn.core.sensor.BasicAttributeSensor; +import org.apache.brooklyn.core.sensor.BasicNotificationSensor; +import org.apache.brooklyn.core.sensor.Sensors; +import org.apache.brooklyn.core.test.entity.TestApplication; +import org.apache.brooklyn.core.test.entity.TestApplicationImpl; +import org.apache.brooklyn.core.test.entity.TestEntity; +import org.apache.brooklyn.core.test.entity.TestEntityImpl; +import org.apache.brooklyn.entity.java.JmxSupport; +import org.apache.brooklyn.entity.java.UsesJmx; +import org.apache.brooklyn.entity.java.UsesJmx.JmxAgentModes; +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.JmxAttributePollConfig; +import org.apache.brooklyn.feed.jmx.JmxFeed; +import org.apache.brooklyn.feed.jmx.JmxHelper; +import org.apache.brooklyn.feed.jmx.JmxNotificationFilters; +import org.apache.brooklyn.feed.jmx.JmxNotificationSubscriptionConfig; +import org.apache.brooklyn.feed.jmx.JmxOperationPollConfig; +import org.apache.brooklyn.feed.jmx.JmxValueFunctions; +import org.apache.brooklyn.test.Asserts; +import org.apache.brooklyn.test.TestUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import org.testng.collections.Lists; +import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +/** + * Test the operation of the {@link JmxFeed} class. + * <p> + * Also confirm some of the JMX setup done by {@link JmxSupport} and {@link JmxHelper}, + * based on ports in {@link UsesJmx}. + * <p> + * TODO tests of other JMX_AGENT_MODE are done in ActiveMqIntegrationTest; + * would be nice to promote some to live here + */ +public class JmxFeedTest { + + // FIXME Move out the JmxHelper tests into the JmxHelperTest class + + // FIXME Also test that setting poll period takes effect + + private static final Logger log = LoggerFactory.getLogger(JmxFeedTest.class); + + private static final int TIMEOUT_MS = 5000; + private static final int SHORT_WAIT_MS = 250; + + private JmxService jmxService; + private TestApplication app; + private TestEntity entity; + private JmxFeed feed; + private JmxHelper jmxHelper; + + private AttributeSensor<Integer> intAttribute = Sensors.newIntegerSensor("brooklyn.test.intAttribute", "Brooklyn testing int attribute"); + private AttributeSensor<String> stringAttribute = Sensors.newStringSensor("brooklyn.test.stringAttribute", "Brooklyn testing string attribute"); + private BasicAttributeSensor<Map> mapAttribute = new BasicAttributeSensor<Map>(Map.class, "brooklyn.test.mapAttribute", "Brooklyn testing map attribute"); + private String objectName = "Brooklyn:type=MyTestMBean,name=myname"; + private ObjectName jmxObjectName; + private String attributeName = "myattrib"; + private String opName = "myop"; + + public static class TestEntityWithJmx extends TestEntityImpl { + @Override public void init() { + setAttribute(Attributes.HOSTNAME, "localhost"); + setAttribute(UsesJmx.JMX_PORT, + LocalhostMachineProvisioningLocation.obtainPort(PortRanges.fromString("40123+"))); + // only supports no-agent, at the moment + setConfig(UsesJmx.JMX_AGENT_MODE, JmxAgentModes.NONE); + setAttribute(UsesJmx.RMI_REGISTRY_PORT, -1); // -1 means to use the JMX_PORT only + ConfigToAttributes.apply(this, UsesJmx.JMX_CONTEXT); + } + } + + @BeforeMethod(alwaysRun=true) + public void setUp() throws Exception { + jmxObjectName = new ObjectName(objectName); + + // Create an entity and configure it with the above JMX service + app = TestApplication.Factory.newManagedInstanceForTests(); + entity = app.createAndManageChild(EntitySpec.create(TestEntity.class).impl(TestEntityWithJmx.class)); + app.start(ImmutableList.of(new SimulatedLocation())); + + jmxHelper = new JmxHelper(entity); + + jmxService = new JmxService(entity); + } + + @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 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); + } + + @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 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(); + + TestUtils.executeUntilSucceeds(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 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); + } + + @Test + public void testJmxNotificationSubscriptionForSensor() 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))) + .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); + }}); + + // But other notification types are ignored + sendNotification(mbean, two, sequence.getAndIncrement(), -1); + + Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() { + public void run() { + assertEquals(entity.getAttribute(intAttribute), (Integer)123); + }}); + } + + @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 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.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.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()); + } + } + + public static class EntityWithEmitter extends AbstractEntity { + public static final BasicNotificationSensor<String> MY_NOTIF = new BasicNotificationSensor<String>(String.class, "test.myNotif", "My notif"); + + public EntityWithEmitter(Entity owner) { + super(owner); + } + public EntityWithEmitter(Map flags) { + super(flags); + } + public EntityWithEmitter(Map flags, Entity owner) { + super(flags, owner); + } + } + + private Notification sendNotification(StandardEmitterMBean mbean, String type, long seq, Object userData) { + Notification notif = new Notification(type, mbean, seq); + notif.setUserData(userData); + mbean.sendNotification(notif); + return notif; + } + + private <T> void assertSensorEventually(final AttributeSensor<T> sensor, final T expectedVal, long timeout) { + executeUntilSucceeds(ImmutableMap.of("timeout", timeout), new Callable<Void>() { + public Void call() { + assertEquals(entity.getAttribute(sensor), expectedVal); + return null; + }}); + } +}
http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxHelperTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxHelperTest.java b/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxHelperTest.java new file mode 100644 index 0000000..3470166 --- /dev/null +++ b/software/base/src/test/java/org/apache/brooklyn/feed/jmx/JmxHelperTest.java @@ -0,0 +1,311 @@ +/* + * 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.feed.jmx; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.assertFalse; +import static org.testng.Assert.fail; + +import java.io.IOException; +import java.util.List; + +import javax.management.DynamicMBean; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.Notification; +import javax.management.NotificationListener; +import javax.management.ObjectName; +import javax.management.StandardEmitterMBean; + +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.JmxHelper; +import org.apache.brooklyn.test.TestUtils; +import org.apache.brooklyn.util.collections.MutableMap; +import org.apache.brooklyn.util.exceptions.Exceptions; +import org.jclouds.util.Throwables2; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import org.testng.collections.Lists; + +import com.google.common.base.Function; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; + +public class JmxHelperTest { + + private static final Logger log = LoggerFactory.getLogger(JmxHelperTest.class); + + private static final String LOCALHOST_NAME = "localhost"; + + private static final int TIMEOUT_MS = 5000; + private static final int SHORT_WAIT_MS = 250; + + private JmxService jmxService; + private JmxHelper jmxHelper; + + private String objectName = "Brooklyn:type=MyTestMBean,name=myname"; + private String objectNameWithWildcard = "Brooklyn:type=MyTestMBean,name=mynam*"; + private ObjectName jmxObjectName; + private ObjectName jmxObjectNameWithWildcard; + private String attributeName = "myattrib"; + private String opName = "myop"; + + @BeforeMethod(alwaysRun=true) + public void setUp() throws Exception { + jmxObjectName = new ObjectName(objectName); + jmxObjectNameWithWildcard = new ObjectName(objectNameWithWildcard); + jmxService = newJmxServiceRetrying(LOCALHOST_NAME, 5); + jmxHelper = new JmxHelper(jmxService.getUrl()); + jmxHelper.setMinTimeBetweenReconnectAttempts(0); + jmxHelper.connect(TIMEOUT_MS); + } + + @AfterMethod(alwaysRun=true) + public void tearDown() throws Exception { + if (jmxHelper != null) jmxHelper.disconnect(); + if (jmxService != null) jmxService.shutdown(); + jmxHelper = null; + jmxService = null; + } + + @Test + public void testGetAttribute() throws Exception { + GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName); + assertEquals(jmxHelper.getAttribute(jmxObjectName, "myattr"), "myval"); + } + + @Test + public void testGetAttributeUsingObjectNameWildcard() throws Exception { + GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName); + assertEquals(jmxHelper.getAttribute(jmxObjectNameWithWildcard, "myattr"), "myval"); + } + + @Test + public void testSetAttribute() throws Exception { + DynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName); + + jmxHelper.setAttribute(jmxObjectName, "myattr", "abc"); + Object actual = jmxHelper.getAttribute(jmxObjectName, "myattr"); + assertEquals(actual, "abc"); + } + + @Test + public void testSetAttributeUsingObjectNameWildcard() throws Exception { + DynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName); + + jmxHelper.setAttribute(jmxObjectNameWithWildcard, "myattr", "abc"); + Object actual = jmxHelper.getAttribute(jmxObjectName, "myattr"); + assertEquals(actual, "abc"); + } + + @Test + public void testInvokeOperationWithNoArgs() throws Exception { + final String opReturnVal = "my result"; + MBeanOperationInfo opInfo = new MBeanOperationInfo(opName, "my descr", new MBeanParameterInfo[0], String.class.getName(), MBeanOperationInfo.ACTION); + Function<Object[], String> opImpl = new Function<Object[], String>() { + @Override public String apply(Object[] args) { + assertEquals(args.length, 0, "args="+args); + return opReturnVal; + } + }; + GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(), ImmutableMap.of(opInfo, opImpl), objectName); + + assertEquals(jmxHelper.operation(objectName, opName), opReturnVal); + } + + @Test + public void testInvokeOperationUsingObjectNameWildcard() throws Exception { + final String opReturnVal = "my result"; + MBeanOperationInfo opInfo = new MBeanOperationInfo(opName, "my descr", new MBeanParameterInfo[0], String.class.getName(), MBeanOperationInfo.ACTION); + Function<Object[], String> opImpl = new Function<Object[], String>() { + @Override public String apply(Object[] args) { + assertEquals(args.length, 0, "args="+args); + return opReturnVal; + } + }; + GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(), ImmutableMap.of(opInfo, opImpl), objectName); + + assertEquals(jmxHelper.operation(objectNameWithWildcard, opName), opReturnVal); + } + + @Test + public void testInvokeOperationWithArgs() throws Exception { + final String opReturnPrefix = "my result prefix/"; + String opParam1 = "my param 1"; + MBeanOperationInfo opInfo = new MBeanOperationInfo( + opName, + "my descr", + new MBeanParameterInfo[] {new MBeanParameterInfo("myParam1", String.class.getName(), "my param1 descr")}, + String.class.getName(), + MBeanOperationInfo.ACTION); + Function<Object[],String> opImpl = new Function<Object[],String>() { + public String apply(Object[] input) { + return opReturnPrefix+input[0]; + } + }; + GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(), ImmutableMap.of(opInfo, opImpl), objectName); + + assertEquals(jmxHelper.operation(objectName, opName, opParam1), opReturnPrefix+opParam1); + } + + @Test + public void testReconnectsOnJmxServerTemporaryFailure() throws Exception { + int port = jmxService.getJmxPort(); + GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName); + assertEquals(jmxHelper.getAttribute(jmxObjectName, "myattr"), "myval"); + + // Simulate temporary network-failure + jmxService.shutdown(); + + // Ensure that we have a failed query while the "network is down" + try { + jmxHelper.getAttribute(jmxObjectName, attributeName); + fail(); + } catch (Exception e) { + if (Throwables2.getFirstThrowableOfType(e, IOException.class) == null) { + throw e; + } + } + + // Simulate the network restarting + jmxService = new JmxService(LOCALHOST_NAME, port); + + GeneralisedDynamicMBean mbean2 = jmxService.registerMBean(MutableMap.of("myattr", "myval2"), objectName); + assertEquals(jmxHelper.getAttribute(jmxObjectName, "myattr"), "myval2"); + } + + @Test(expectedExceptions = {IllegalStateException.class}) + public void testJmxCheckInstanceExistsEventuallyThrowsIfNotFound() throws Exception { + jmxHelper.assertMBeanExistsEventually(new ObjectName("Brooklyn:type=DoesNotExist,name=doesNotExist"), 1L); + } + + @Test + public void testJmxObjectCheckExistsEventuallyReturnsIfFoundImmediately() throws Exception { + GeneralisedDynamicMBean mbean = jmxService.registerMBean(objectName); + jmxHelper.assertMBeanExistsEventually(jmxObjectName, 1L); + } + + @Test + public void testJmxObjectCheckExistsEventuallyTakingLongReturnsIfFoundImmediately() throws Exception { + GeneralisedDynamicMBean mbean = jmxService.registerMBean(objectName); + jmxHelper.assertMBeanExistsEventually(jmxObjectName, 1L); + } + + @Test + public void testJmxObjectCheckExistsEventuallyReturnsIfCreatedDuringPolling() throws Exception { + Thread t = new Thread(new Runnable() { + public void run() { + try { + Thread.sleep(SHORT_WAIT_MS); + GeneralisedDynamicMBean mbean = jmxService.registerMBean(objectName); + } catch (InterruptedException e) { + return; // graceful return + } catch (Exception e) { + throw Exceptions.propagate(e); + } + }}); + try { + t.start(); + + jmxHelper.assertMBeanExistsEventually(jmxObjectName, TIMEOUT_MS); + } finally { + t.interrupt(); + t.join(TIMEOUT_MS); + assertFalse(t.isAlive()); + } + } + + @Test + public void testSubscribeToJmxNotificationsDirectlyWithJmxHelper() throws Exception { + StandardEmitterMBean mbean = jmxService.registerMBean(ImmutableList.of("one"), objectName); + int sequence = 0; + final List<Notification> received = Lists.newArrayList(); + + jmxHelper.addNotificationListener(jmxObjectName, new NotificationListener() { + public void handleNotification(Notification notif, Object callback) { + received.add(notif); + }}); + + + final Notification notif = sendNotification(mbean, "one", sequence++, "abc"); + + TestUtils.executeUntilSucceeds(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() { + public void run() { + assertEquals(received.size(), 1); + assertNotificationsEqual(received.get(0), notif); + }}); + } + + // Visual-inspection test that LOG.warn happens only once; TODO setup a listener to the logging output + @Test + public void testMBeanNotFoundLoggedOnlyOncePerUrl() throws Exception { + ObjectName wrongObjectName = new ObjectName("DoesNotExist:type=DoesNotExist"); + + // Expect just one log message about: + // JMX object DoesNotExist:type=DoesNotExist not found at service:jmx:rmi://localhost:1099/jndi/rmi://localhost:9001/jmxrmi" + for (int i = 0; i < 10; i++) { + jmxHelper.findMBean(wrongObjectName); + } + + jmxService.shutdown(); + jmxHelper.disconnect(); + + jmxService = newJmxServiceRetrying(LOCALHOST_NAME, 5); + jmxHelper = new JmxHelper(jmxService.getUrl()); + jmxHelper.connect(); + + // Expect just one log message about: + // JMX object DoesNotExist:type=DoesNotExist not found at service:jmx:rmi://localhost:1099/jndi/rmi://localhost:9001/jmxrmi" + for (int i = 0; i < 10; i++) { + jmxHelper.findMBean(wrongObjectName); + } + } + + private JmxService newJmxServiceRetrying(String host, int retries) throws Exception { + Exception lastexception = null; + for (int i = 0; i < retries; i++) { + try { + return new JmxService(host, (int)(11000+(500*Math.random()))); + } catch (Exception e) { + log.debug("Unable to create JMX service during test - "+retries+" retries remaining"); + lastexception = e; + } + } + throw lastexception; + } + + private Notification sendNotification(StandardEmitterMBean mbean, String type, long seq, Object userData) { + Notification notif = new Notification(type, mbean, seq); + notif.setUserData(userData); + mbean.sendNotification(notif); + return notif; + } + + private void assertNotificationsEqual(Notification n1, Notification n2) { + assertEquals(n1.getType(), n2.getType()); + assertEquals(n1.getSequenceNumber(), n2.getSequenceNumber()); + assertEquals(n1.getUserData(), n2.getUserData()); + assertEquals(n1.getTimeStamp(), n2.getTimeStamp()); + assertEquals(n1.getMessage(), n2.getMessage()); + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/feed/jmx/RebindJmxFeedTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/org/apache/brooklyn/feed/jmx/RebindJmxFeedTest.java b/software/base/src/test/java/org/apache/brooklyn/feed/jmx/RebindJmxFeedTest.java new file mode 100644 index 0000000..f521932 --- /dev/null +++ b/software/base/src/test/java/org/apache/brooklyn/feed/jmx/RebindJmxFeedTest.java @@ -0,0 +1,148 @@ +/* + * 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.feed.jmx; + +import static org.testng.Assert.assertEquals; + +import java.util.Collection; + +import org.apache.brooklyn.api.entity.EntitySpec; +import org.apache.brooklyn.api.location.Location; +import org.apache.brooklyn.api.sensor.AttributeSensor; +import org.apache.brooklyn.api.sensor.Feed; +import org.apache.brooklyn.config.ConfigKey; +import org.apache.brooklyn.core.config.ConfigKeys; +import org.apache.brooklyn.core.entity.Attributes; +import org.apache.brooklyn.core.feed.ConfigToAttributes; +import org.apache.brooklyn.core.location.PortRanges; +import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp; +import org.apache.brooklyn.core.sensor.Sensors; +import org.apache.brooklyn.core.test.entity.TestEntity; +import org.apache.brooklyn.core.test.entity.TestEntityImpl; +import org.apache.brooklyn.entity.java.UsesJmx; +import org.apache.brooklyn.entity.java.UsesJmx.JmxAgentModes; +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.JmxAttributePollConfig; +import org.apache.brooklyn.feed.jmx.JmxFeed; +import org.apache.brooklyn.feed.jmx.JmxHelper; +import org.apache.brooklyn.test.EntityTestUtils; +import org.apache.brooklyn.util.collections.MutableMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testng.annotations.AfterMethod; +import org.testng.annotations.BeforeMethod; +import org.testng.annotations.Test; +import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Iterables; + +public class RebindJmxFeedTest extends RebindTestFixtureWithApp { + + private static final Logger log = LoggerFactory.getLogger(RebindJmxFeedTest.class); + + private static final String LOCALHOST_NAME = "localhost"; + + static final AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString", ""); + static final AttributeSensor<Integer> SENSOR_INT = Sensors.newIntegerSensor( "aLong", ""); + + static final String JMX_ATTRIBUTE_NAME = "myattr"; + static final String OBJECT_NAME = "Brooklyn:type=MyTestMBean,name=myname"; + + private JmxService jmxService; + + @BeforeMethod(alwaysRun=true) + @Override + public void setUp() throws Exception { + super.setUp(); + + // Create an entity and configure it with the above JMX service + //jmxService = newJmxServiceRetrying(LOCALHOST_NAME, 5); + } + + @AfterMethod(alwaysRun=true) + @Override + public void tearDown() throws Exception { + if (jmxService != null) jmxService.shutdown(); + super.tearDown(); + } + + @Test + public void testJmxFeedIsPersisted() throws Exception { + runJmxFeedIsPersisted(false); + } + + @Test + public void testJmxFeedIsPersistedWithPreCreatedJmxHelper() throws Exception { + runJmxFeedIsPersisted(true); + } + + protected void runJmxFeedIsPersisted(boolean preCreateJmxHelper) throws Exception { + TestEntity origEntity = origApp.createAndManageChild(EntitySpec.create(TestEntity.class).impl(MyEntityWithJmxFeedImpl.class) + .configure(MyEntityWithJmxFeedImpl.PRE_CREATE_JMX_HELPER, preCreateJmxHelper)); + origApp.start(ImmutableList.<Location>of()); + + jmxService = new JmxService(origEntity); + GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of(JMX_ATTRIBUTE_NAME, "myval"), OBJECT_NAME); + + EntityTestUtils.assertAttributeEqualsEventually(origEntity, SENSOR_STRING, "myval"); + assertEquals(origEntity.feeds().getFeeds().size(), 1); + + newApp = rebind(); + TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(newApp.getChildren()); + + Collection<Feed> newFeeds = newEntity.feeds().getFeeds(); + assertEquals(newFeeds.size(), 1); + + // Expect the feed to still be polling + newEntity.setAttribute(SENSOR_STRING, null); + EntityTestUtils.assertAttributeEqualsEventually(newEntity, SENSOR_STRING, "myval"); + } + + public static class MyEntityWithJmxFeedImpl extends TestEntityImpl { + public static final ConfigKey<Boolean> PRE_CREATE_JMX_HELPER = ConfigKeys.newBooleanConfigKey("test.rebindjmx.preCreateJmxHelper", "", false); + + @Override + public void start(Collection<? extends Location> locs) { + // TODO Auto-generated method stub + super.start(locs); + + setAttribute(Attributes.HOSTNAME, "localhost"); + setAttribute(UsesJmx.JMX_PORT, + LocalhostMachineProvisioningLocation.obtainPort(PortRanges.fromString("40123+"))); + // only supports no-agent, at the moment + setConfig(UsesJmx.JMX_AGENT_MODE, JmxAgentModes.NONE); + setAttribute(UsesJmx.RMI_REGISTRY_PORT, -1); // -1 means to use the JMX_PORT only + ConfigToAttributes.apply(this, UsesJmx.JMX_CONTEXT); + + JmxFeed.Builder feedBuilder = JmxFeed.builder() + .entity(this) + .pollAttribute(new JmxAttributePollConfig<String>(SENSOR_STRING) + .objectName(OBJECT_NAME) + .period(50) + .attributeName(JMX_ATTRIBUTE_NAME)); + if (getConfig(PRE_CREATE_JMX_HELPER)) { + JmxHelper jmxHelper = new JmxHelper(this); + feedBuilder.helper(jmxHelper); + } + addFeed(feedBuilder.build()); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeedTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeedTest.java b/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeedTest.java deleted file mode 100644 index 8f722b2..0000000 --- a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxFeedTest.java +++ /dev/null @@ -1,422 +0,0 @@ -/* - * 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.sensor.feed.jmx; - -import static org.apache.brooklyn.test.TestUtils.executeUntilSucceeds; -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertTrue; - -import java.util.Collections; -import java.util.List; -import java.util.Map; -import java.util.concurrent.Callable; -import java.util.concurrent.atomic.AtomicInteger; - -import javax.management.MBeanOperationInfo; -import javax.management.MBeanParameterInfo; -import javax.management.Notification; -import javax.management.NotificationListener; -import javax.management.ObjectName; -import javax.management.StandardEmitterMBean; -import javax.management.openmbean.CompositeDataSupport; -import javax.management.openmbean.CompositeType; -import javax.management.openmbean.OpenType; -import javax.management.openmbean.SimpleType; -import javax.management.openmbean.TabularDataSupport; -import javax.management.openmbean.TabularType; - -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.api.sensor.SensorEvent; -import org.apache.brooklyn.api.sensor.SensorEventListener; -import org.apache.brooklyn.core.entity.AbstractEntity; -import org.apache.brooklyn.core.entity.Attributes; -import org.apache.brooklyn.core.entity.Entities; -import org.apache.brooklyn.core.location.PortRanges; -import org.apache.brooklyn.core.location.SimulatedLocation; -import org.apache.brooklyn.core.sensor.BasicAttributeSensor; -import org.apache.brooklyn.core.sensor.BasicNotificationSensor; -import org.apache.brooklyn.core.sensor.Sensors; -import org.apache.brooklyn.core.test.entity.TestApplication; -import org.apache.brooklyn.core.test.entity.TestApplicationImpl; -import org.apache.brooklyn.core.test.entity.TestEntity; -import org.apache.brooklyn.core.test.entity.TestEntityImpl; -import org.apache.brooklyn.entity.java.JmxSupport; -import org.apache.brooklyn.entity.java.UsesJmx; -import org.apache.brooklyn.entity.java.UsesJmx.JmxAgentModes; -import org.apache.brooklyn.entity.software.base.test.jmx.GeneralisedDynamicMBean; -import org.apache.brooklyn.entity.software.base.test.jmx.JmxService; -import org.apache.brooklyn.sensor.feed.ConfigToAttributes; -import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig; -import org.apache.brooklyn.sensor.feed.jmx.JmxFeed; -import org.apache.brooklyn.sensor.feed.jmx.JmxHelper; -import org.apache.brooklyn.sensor.feed.jmx.JmxNotificationFilters; -import org.apache.brooklyn.sensor.feed.jmx.JmxNotificationSubscriptionConfig; -import org.apache.brooklyn.sensor.feed.jmx.JmxOperationPollConfig; -import org.apache.brooklyn.sensor.feed.jmx.JmxValueFunctions; -import org.apache.brooklyn.test.Asserts; -import org.apache.brooklyn.test.TestUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; -import org.testng.collections.Lists; -import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation; - -import com.google.common.base.Function; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; - -/** - * Test the operation of the {@link JmxFeed} class. - * <p> - * Also confirm some of the JMX setup done by {@link JmxSupport} and {@link JmxHelper}, - * based on ports in {@link UsesJmx}. - * <p> - * TODO tests of other JMX_AGENT_MODE are done in ActiveMqIntegrationTest; - * would be nice to promote some to live here - */ -public class JmxFeedTest { - - // FIXME Move out the JmxHelper tests into the JmxHelperTest class - - // FIXME Also test that setting poll period takes effect - - private static final Logger log = LoggerFactory.getLogger(JmxFeedTest.class); - - private static final int TIMEOUT_MS = 5000; - private static final int SHORT_WAIT_MS = 250; - - private JmxService jmxService; - private TestApplication app; - private TestEntity entity; - private JmxFeed feed; - private JmxHelper jmxHelper; - - private AttributeSensor<Integer> intAttribute = Sensors.newIntegerSensor("brooklyn.test.intAttribute", "Brooklyn testing int attribute"); - private AttributeSensor<String> stringAttribute = Sensors.newStringSensor("brooklyn.test.stringAttribute", "Brooklyn testing string attribute"); - private BasicAttributeSensor<Map> mapAttribute = new BasicAttributeSensor<Map>(Map.class, "brooklyn.test.mapAttribute", "Brooklyn testing map attribute"); - private String objectName = "Brooklyn:type=MyTestMBean,name=myname"; - private ObjectName jmxObjectName; - private String attributeName = "myattrib"; - private String opName = "myop"; - - public static class TestEntityWithJmx extends TestEntityImpl { - @Override public void init() { - setAttribute(Attributes.HOSTNAME, "localhost"); - setAttribute(UsesJmx.JMX_PORT, - LocalhostMachineProvisioningLocation.obtainPort(PortRanges.fromString("40123+"))); - // only supports no-agent, at the moment - setConfig(UsesJmx.JMX_AGENT_MODE, JmxAgentModes.NONE); - setAttribute(UsesJmx.RMI_REGISTRY_PORT, -1); // -1 means to use the JMX_PORT only - ConfigToAttributes.apply(this, UsesJmx.JMX_CONTEXT); - } - } - - @BeforeMethod(alwaysRun=true) - public void setUp() throws Exception { - jmxObjectName = new ObjectName(objectName); - - // Create an entity and configure it with the above JMX service - app = TestApplication.Factory.newManagedInstanceForTests(); - entity = app.createAndManageChild(EntitySpec.create(TestEntity.class).impl(TestEntityWithJmx.class)); - app.start(ImmutableList.of(new SimulatedLocation())); - - jmxHelper = new JmxHelper(entity); - - jmxService = new JmxService(entity); - } - - @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 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); - } - - @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 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(); - - TestUtils.executeUntilSucceeds(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 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); - } - - @Test - public void testJmxNotificationSubscriptionForSensor() 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))) - .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); - }}); - - // But other notification types are ignored - sendNotification(mbean, two, sequence.getAndIncrement(), -1); - - Asserts.succeedsEventually(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() { - public void run() { - assertEquals(entity.getAttribute(intAttribute), (Integer)123); - }}); - } - - @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 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.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.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()); - } - } - - public static class EntityWithEmitter extends AbstractEntity { - public static final BasicNotificationSensor<String> MY_NOTIF = new BasicNotificationSensor<String>(String.class, "test.myNotif", "My notif"); - - public EntityWithEmitter(Entity owner) { - super(owner); - } - public EntityWithEmitter(Map flags) { - super(flags); - } - public EntityWithEmitter(Map flags, Entity owner) { - super(flags, owner); - } - } - - private Notification sendNotification(StandardEmitterMBean mbean, String type, long seq, Object userData) { - Notification notif = new Notification(type, mbean, seq); - notif.setUserData(userData); - mbean.sendNotification(notif); - return notif; - } - - private <T> void assertSensorEventually(final AttributeSensor<T> sensor, final T expectedVal, long timeout) { - executeUntilSucceeds(ImmutableMap.of("timeout", timeout), new Callable<Void>() { - public Void call() { - assertEquals(entity.getAttribute(sensor), expectedVal); - return null; - }}); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxHelperTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxHelperTest.java b/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxHelperTest.java deleted file mode 100644 index 058947c..0000000 --- a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/JmxHelperTest.java +++ /dev/null @@ -1,311 +0,0 @@ -/* - * 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.sensor.feed.jmx; - -import static org.testng.Assert.assertEquals; -import static org.testng.Assert.assertFalse; -import static org.testng.Assert.fail; - -import java.io.IOException; -import java.util.List; - -import javax.management.DynamicMBean; -import javax.management.MBeanOperationInfo; -import javax.management.MBeanParameterInfo; -import javax.management.Notification; -import javax.management.NotificationListener; -import javax.management.ObjectName; -import javax.management.StandardEmitterMBean; - -import org.apache.brooklyn.entity.software.base.test.jmx.GeneralisedDynamicMBean; -import org.apache.brooklyn.entity.software.base.test.jmx.JmxService; -import org.apache.brooklyn.sensor.feed.jmx.JmxHelper; -import org.apache.brooklyn.test.TestUtils; -import org.apache.brooklyn.util.collections.MutableMap; -import org.apache.brooklyn.util.exceptions.Exceptions; -import org.jclouds.util.Throwables2; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; -import org.testng.collections.Lists; - -import com.google.common.base.Function; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; - -public class JmxHelperTest { - - private static final Logger log = LoggerFactory.getLogger(JmxHelperTest.class); - - private static final String LOCALHOST_NAME = "localhost"; - - private static final int TIMEOUT_MS = 5000; - private static final int SHORT_WAIT_MS = 250; - - private JmxService jmxService; - private JmxHelper jmxHelper; - - private String objectName = "Brooklyn:type=MyTestMBean,name=myname"; - private String objectNameWithWildcard = "Brooklyn:type=MyTestMBean,name=mynam*"; - private ObjectName jmxObjectName; - private ObjectName jmxObjectNameWithWildcard; - private String attributeName = "myattrib"; - private String opName = "myop"; - - @BeforeMethod(alwaysRun=true) - public void setUp() throws Exception { - jmxObjectName = new ObjectName(objectName); - jmxObjectNameWithWildcard = new ObjectName(objectNameWithWildcard); - jmxService = newJmxServiceRetrying(LOCALHOST_NAME, 5); - jmxHelper = new JmxHelper(jmxService.getUrl()); - jmxHelper.setMinTimeBetweenReconnectAttempts(0); - jmxHelper.connect(TIMEOUT_MS); - } - - @AfterMethod(alwaysRun=true) - public void tearDown() throws Exception { - if (jmxHelper != null) jmxHelper.disconnect(); - if (jmxService != null) jmxService.shutdown(); - jmxHelper = null; - jmxService = null; - } - - @Test - public void testGetAttribute() throws Exception { - GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName); - assertEquals(jmxHelper.getAttribute(jmxObjectName, "myattr"), "myval"); - } - - @Test - public void testGetAttributeUsingObjectNameWildcard() throws Exception { - GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName); - assertEquals(jmxHelper.getAttribute(jmxObjectNameWithWildcard, "myattr"), "myval"); - } - - @Test - public void testSetAttribute() throws Exception { - DynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName); - - jmxHelper.setAttribute(jmxObjectName, "myattr", "abc"); - Object actual = jmxHelper.getAttribute(jmxObjectName, "myattr"); - assertEquals(actual, "abc"); - } - - @Test - public void testSetAttributeUsingObjectNameWildcard() throws Exception { - DynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName); - - jmxHelper.setAttribute(jmxObjectNameWithWildcard, "myattr", "abc"); - Object actual = jmxHelper.getAttribute(jmxObjectName, "myattr"); - assertEquals(actual, "abc"); - } - - @Test - public void testInvokeOperationWithNoArgs() throws Exception { - final String opReturnVal = "my result"; - MBeanOperationInfo opInfo = new MBeanOperationInfo(opName, "my descr", new MBeanParameterInfo[0], String.class.getName(), MBeanOperationInfo.ACTION); - Function<Object[], String> opImpl = new Function<Object[], String>() { - @Override public String apply(Object[] args) { - assertEquals(args.length, 0, "args="+args); - return opReturnVal; - } - }; - GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(), ImmutableMap.of(opInfo, opImpl), objectName); - - assertEquals(jmxHelper.operation(objectName, opName), opReturnVal); - } - - @Test - public void testInvokeOperationUsingObjectNameWildcard() throws Exception { - final String opReturnVal = "my result"; - MBeanOperationInfo opInfo = new MBeanOperationInfo(opName, "my descr", new MBeanParameterInfo[0], String.class.getName(), MBeanOperationInfo.ACTION); - Function<Object[], String> opImpl = new Function<Object[], String>() { - @Override public String apply(Object[] args) { - assertEquals(args.length, 0, "args="+args); - return opReturnVal; - } - }; - GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(), ImmutableMap.of(opInfo, opImpl), objectName); - - assertEquals(jmxHelper.operation(objectNameWithWildcard, opName), opReturnVal); - } - - @Test - public void testInvokeOperationWithArgs() throws Exception { - final String opReturnPrefix = "my result prefix/"; - String opParam1 = "my param 1"; - MBeanOperationInfo opInfo = new MBeanOperationInfo( - opName, - "my descr", - new MBeanParameterInfo[] {new MBeanParameterInfo("myParam1", String.class.getName(), "my param1 descr")}, - String.class.getName(), - MBeanOperationInfo.ACTION); - Function<Object[],String> opImpl = new Function<Object[],String>() { - public String apply(Object[] input) { - return opReturnPrefix+input[0]; - } - }; - GeneralisedDynamicMBean mbean = jmxService.registerMBean(ImmutableMap.of(), ImmutableMap.of(opInfo, opImpl), objectName); - - assertEquals(jmxHelper.operation(objectName, opName, opParam1), opReturnPrefix+opParam1); - } - - @Test - public void testReconnectsOnJmxServerTemporaryFailure() throws Exception { - int port = jmxService.getJmxPort(); - GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of("myattr", "myval"), objectName); - assertEquals(jmxHelper.getAttribute(jmxObjectName, "myattr"), "myval"); - - // Simulate temporary network-failure - jmxService.shutdown(); - - // Ensure that we have a failed query while the "network is down" - try { - jmxHelper.getAttribute(jmxObjectName, attributeName); - fail(); - } catch (Exception e) { - if (Throwables2.getFirstThrowableOfType(e, IOException.class) == null) { - throw e; - } - } - - // Simulate the network restarting - jmxService = new JmxService(LOCALHOST_NAME, port); - - GeneralisedDynamicMBean mbean2 = jmxService.registerMBean(MutableMap.of("myattr", "myval2"), objectName); - assertEquals(jmxHelper.getAttribute(jmxObjectName, "myattr"), "myval2"); - } - - @Test(expectedExceptions = {IllegalStateException.class}) - public void testJmxCheckInstanceExistsEventuallyThrowsIfNotFound() throws Exception { - jmxHelper.assertMBeanExistsEventually(new ObjectName("Brooklyn:type=DoesNotExist,name=doesNotExist"), 1L); - } - - @Test - public void testJmxObjectCheckExistsEventuallyReturnsIfFoundImmediately() throws Exception { - GeneralisedDynamicMBean mbean = jmxService.registerMBean(objectName); - jmxHelper.assertMBeanExistsEventually(jmxObjectName, 1L); - } - - @Test - public void testJmxObjectCheckExistsEventuallyTakingLongReturnsIfFoundImmediately() throws Exception { - GeneralisedDynamicMBean mbean = jmxService.registerMBean(objectName); - jmxHelper.assertMBeanExistsEventually(jmxObjectName, 1L); - } - - @Test - public void testJmxObjectCheckExistsEventuallyReturnsIfCreatedDuringPolling() throws Exception { - Thread t = new Thread(new Runnable() { - public void run() { - try { - Thread.sleep(SHORT_WAIT_MS); - GeneralisedDynamicMBean mbean = jmxService.registerMBean(objectName); - } catch (InterruptedException e) { - return; // graceful return - } catch (Exception e) { - throw Exceptions.propagate(e); - } - }}); - try { - t.start(); - - jmxHelper.assertMBeanExistsEventually(jmxObjectName, TIMEOUT_MS); - } finally { - t.interrupt(); - t.join(TIMEOUT_MS); - assertFalse(t.isAlive()); - } - } - - @Test - public void testSubscribeToJmxNotificationsDirectlyWithJmxHelper() throws Exception { - StandardEmitterMBean mbean = jmxService.registerMBean(ImmutableList.of("one"), objectName); - int sequence = 0; - final List<Notification> received = Lists.newArrayList(); - - jmxHelper.addNotificationListener(jmxObjectName, new NotificationListener() { - public void handleNotification(Notification notif, Object callback) { - received.add(notif); - }}); - - - final Notification notif = sendNotification(mbean, "one", sequence++, "abc"); - - TestUtils.executeUntilSucceeds(ImmutableMap.of("timeout", TIMEOUT_MS), new Runnable() { - public void run() { - assertEquals(received.size(), 1); - assertNotificationsEqual(received.get(0), notif); - }}); - } - - // Visual-inspection test that LOG.warn happens only once; TODO setup a listener to the logging output - @Test - public void testMBeanNotFoundLoggedOnlyOncePerUrl() throws Exception { - ObjectName wrongObjectName = new ObjectName("DoesNotExist:type=DoesNotExist"); - - // Expect just one log message about: - // JMX object DoesNotExist:type=DoesNotExist not found at service:jmx:rmi://localhost:1099/jndi/rmi://localhost:9001/jmxrmi" - for (int i = 0; i < 10; i++) { - jmxHelper.findMBean(wrongObjectName); - } - - jmxService.shutdown(); - jmxHelper.disconnect(); - - jmxService = newJmxServiceRetrying(LOCALHOST_NAME, 5); - jmxHelper = new JmxHelper(jmxService.getUrl()); - jmxHelper.connect(); - - // Expect just one log message about: - // JMX object DoesNotExist:type=DoesNotExist not found at service:jmx:rmi://localhost:1099/jndi/rmi://localhost:9001/jmxrmi" - for (int i = 0; i < 10; i++) { - jmxHelper.findMBean(wrongObjectName); - } - } - - private JmxService newJmxServiceRetrying(String host, int retries) throws Exception { - Exception lastexception = null; - for (int i = 0; i < retries; i++) { - try { - return new JmxService(host, (int)(11000+(500*Math.random()))); - } catch (Exception e) { - log.debug("Unable to create JMX service during test - "+retries+" retries remaining"); - lastexception = e; - } - } - throw lastexception; - } - - private Notification sendNotification(StandardEmitterMBean mbean, String type, long seq, Object userData) { - Notification notif = new Notification(type, mbean, seq); - notif.setUserData(userData); - mbean.sendNotification(notif); - return notif; - } - - private void assertNotificationsEqual(Notification n1, Notification n2) { - assertEquals(n1.getType(), n2.getType()); - assertEquals(n1.getSequenceNumber(), n2.getSequenceNumber()); - assertEquals(n1.getUserData(), n2.getUserData()); - assertEquals(n1.getTimeStamp(), n2.getTimeStamp()); - assertEquals(n1.getMessage(), n2.getMessage()); - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/RebindJmxFeedTest.java ---------------------------------------------------------------------- diff --git a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/RebindJmxFeedTest.java b/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/RebindJmxFeedTest.java deleted file mode 100644 index 9ed0031..0000000 --- a/software/base/src/test/java/org/apache/brooklyn/sensor/feed/jmx/RebindJmxFeedTest.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * 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.sensor.feed.jmx; - -import static org.testng.Assert.assertEquals; - -import java.util.Collection; - -import org.apache.brooklyn.api.entity.EntitySpec; -import org.apache.brooklyn.api.location.Location; -import org.apache.brooklyn.api.sensor.AttributeSensor; -import org.apache.brooklyn.api.sensor.Feed; -import org.apache.brooklyn.config.ConfigKey; -import org.apache.brooklyn.core.config.ConfigKeys; -import org.apache.brooklyn.core.entity.Attributes; -import org.apache.brooklyn.core.location.PortRanges; -import org.apache.brooklyn.core.mgmt.rebind.RebindTestFixtureWithApp; -import org.apache.brooklyn.core.sensor.Sensors; -import org.apache.brooklyn.core.test.entity.TestEntity; -import org.apache.brooklyn.core.test.entity.TestEntityImpl; -import org.apache.brooklyn.entity.java.UsesJmx; -import org.apache.brooklyn.entity.java.UsesJmx.JmxAgentModes; -import org.apache.brooklyn.entity.software.base.test.jmx.GeneralisedDynamicMBean; -import org.apache.brooklyn.entity.software.base.test.jmx.JmxService; -import org.apache.brooklyn.sensor.feed.ConfigToAttributes; -import org.apache.brooklyn.sensor.feed.jmx.JmxAttributePollConfig; -import org.apache.brooklyn.sensor.feed.jmx.JmxFeed; -import org.apache.brooklyn.sensor.feed.jmx.JmxHelper; -import org.apache.brooklyn.test.EntityTestUtils; -import org.apache.brooklyn.util.collections.MutableMap; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.testng.annotations.AfterMethod; -import org.testng.annotations.BeforeMethod; -import org.testng.annotations.Test; -import org.apache.brooklyn.location.localhost.LocalhostMachineProvisioningLocation; - -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; - -public class RebindJmxFeedTest extends RebindTestFixtureWithApp { - - private static final Logger log = LoggerFactory.getLogger(RebindJmxFeedTest.class); - - private static final String LOCALHOST_NAME = "localhost"; - - static final AttributeSensor<String> SENSOR_STRING = Sensors.newStringSensor("aString", ""); - static final AttributeSensor<Integer> SENSOR_INT = Sensors.newIntegerSensor( "aLong", ""); - - static final String JMX_ATTRIBUTE_NAME = "myattr"; - static final String OBJECT_NAME = "Brooklyn:type=MyTestMBean,name=myname"; - - private JmxService jmxService; - - @BeforeMethod(alwaysRun=true) - @Override - public void setUp() throws Exception { - super.setUp(); - - // Create an entity and configure it with the above JMX service - //jmxService = newJmxServiceRetrying(LOCALHOST_NAME, 5); - } - - @AfterMethod(alwaysRun=true) - @Override - public void tearDown() throws Exception { - if (jmxService != null) jmxService.shutdown(); - super.tearDown(); - } - - @Test - public void testJmxFeedIsPersisted() throws Exception { - runJmxFeedIsPersisted(false); - } - - @Test - public void testJmxFeedIsPersistedWithPreCreatedJmxHelper() throws Exception { - runJmxFeedIsPersisted(true); - } - - protected void runJmxFeedIsPersisted(boolean preCreateJmxHelper) throws Exception { - TestEntity origEntity = origApp.createAndManageChild(EntitySpec.create(TestEntity.class).impl(MyEntityWithJmxFeedImpl.class) - .configure(MyEntityWithJmxFeedImpl.PRE_CREATE_JMX_HELPER, preCreateJmxHelper)); - origApp.start(ImmutableList.<Location>of()); - - jmxService = new JmxService(origEntity); - GeneralisedDynamicMBean mbean = jmxService.registerMBean(MutableMap.of(JMX_ATTRIBUTE_NAME, "myval"), OBJECT_NAME); - - EntityTestUtils.assertAttributeEqualsEventually(origEntity, SENSOR_STRING, "myval"); - assertEquals(origEntity.feeds().getFeeds().size(), 1); - - newApp = rebind(); - TestEntity newEntity = (TestEntity) Iterables.getOnlyElement(newApp.getChildren()); - - Collection<Feed> newFeeds = newEntity.feeds().getFeeds(); - assertEquals(newFeeds.size(), 1); - - // Expect the feed to still be polling - newEntity.setAttribute(SENSOR_STRING, null); - EntityTestUtils.assertAttributeEqualsEventually(newEntity, SENSOR_STRING, "myval"); - } - - public static class MyEntityWithJmxFeedImpl extends TestEntityImpl { - public static final ConfigKey<Boolean> PRE_CREATE_JMX_HELPER = ConfigKeys.newBooleanConfigKey("test.rebindjmx.preCreateJmxHelper", "", false); - - @Override - public void start(Collection<? extends Location> locs) { - // TODO Auto-generated method stub - super.start(locs); - - setAttribute(Attributes.HOSTNAME, "localhost"); - setAttribute(UsesJmx.JMX_PORT, - LocalhostMachineProvisioningLocation.obtainPort(PortRanges.fromString("40123+"))); - // only supports no-agent, at the moment - setConfig(UsesJmx.JMX_AGENT_MODE, JmxAgentModes.NONE); - setAttribute(UsesJmx.RMI_REGISTRY_PORT, -1); // -1 means to use the JMX_PORT only - ConfigToAttributes.apply(this, UsesJmx.JMX_CONTEXT); - - JmxFeed.Builder feedBuilder = JmxFeed.builder() - .entity(this) - .pollAttribute(new JmxAttributePollConfig<String>(SENSOR_STRING) - .objectName(OBJECT_NAME) - .period(50) - .attributeName(JMX_ATTRIBUTE_NAME)); - if (getConfig(PRE_CREATE_JMX_HELPER)) { - JmxHelper jmxHelper = new JmxHelper(this); - feedBuilder.helper(jmxHelper); - } - addFeed(feedBuilder.build()); - } - } -} http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java ---------------------------------------------------------------------- diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java index 8b544c4..f78ddba 100644 --- a/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java +++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/crate/CrateNodeImpl.java @@ -22,11 +22,11 @@ import org.apache.brooklyn.core.config.render.RendererHints; import org.apache.brooklyn.core.entity.Attributes; import org.apache.brooklyn.entity.java.JavaAppUtils; import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl; +import org.apache.brooklyn.feed.http.HttpFeed; +import org.apache.brooklyn.feed.http.HttpPollConfig; +import org.apache.brooklyn.feed.http.HttpValueFunctions; +import org.apache.brooklyn.feed.jmx.JmxFeed; import org.apache.brooklyn.sensor.enricher.Enrichers; -import org.apache.brooklyn.sensor.feed.http.HttpFeed; -import org.apache.brooklyn.sensor.feed.http.HttpPollConfig; -import org.apache.brooklyn.sensor.feed.http.HttpValueFunctions; -import org.apache.brooklyn.sensor.feed.jmx.JmxFeed; import org.apache.brooklyn.util.guava.Functionals; public class CrateNodeImpl extends SoftwareProcessImpl implements CrateNode{ http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java ---------------------------------------------------------------------- diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java index 3d8c982..c23c616 100644 --- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java +++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mariadb/MariaDbNodeImpl.java @@ -23,10 +23,10 @@ import org.slf4j.LoggerFactory; import org.apache.brooklyn.core.effector.EffectorBody; import org.apache.brooklyn.core.location.Locations; import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl; +import org.apache.brooklyn.feed.ssh.SshFeed; +import org.apache.brooklyn.feed.ssh.SshPollConfig; +import org.apache.brooklyn.feed.ssh.SshPollValue; import org.apache.brooklyn.location.ssh.SshMachineLocation; -import org.apache.brooklyn.sensor.feed.ssh.SshFeed; -import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig; -import org.apache.brooklyn.sensor.feed.ssh.SshPollValue; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.guava.Maybe; import org.apache.brooklyn.util.text.Identifiers; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java ---------------------------------------------------------------------- diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java index e106728..d6527ca 100644 --- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java +++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlClusterImpl.java @@ -39,9 +39,9 @@ import org.apache.brooklyn.core.entity.lifecycle.ServiceStateLogic.ServiceNotUpL import org.apache.brooklyn.core.sensor.DependentConfiguration; import org.apache.brooklyn.core.sensor.Sensors; import org.apache.brooklyn.entity.group.DynamicClusterImpl; +import org.apache.brooklyn.feed.function.FunctionFeed; +import org.apache.brooklyn.feed.function.FunctionPollConfig; import org.apache.brooklyn.sensor.enricher.Enrichers; -import org.apache.brooklyn.sensor.feed.function.FunctionFeed; -import org.apache.brooklyn.sensor.feed.function.FunctionPollConfig; import org.apache.brooklyn.util.collections.CollectionFunctionals; import org.apache.brooklyn.util.core.task.DynamicTasks; import org.apache.brooklyn.util.core.task.TaskBuilder; http://git-wip-us.apache.org/repos/asf/incubator-brooklyn/blob/daf40919/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java ---------------------------------------------------------------------- diff --git a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java index 71c73c6..5346fcb 100644 --- a/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java +++ b/software/database/src/main/java/org/apache/brooklyn/entity/database/mysql/MySqlNodeImpl.java @@ -24,12 +24,12 @@ import org.apache.brooklyn.api.entity.Entity; import org.apache.brooklyn.core.effector.EffectorBody; import org.apache.brooklyn.core.location.Locations; import org.apache.brooklyn.entity.software.base.SoftwareProcessImpl; +import org.apache.brooklyn.feed.ssh.SshFeed; +import org.apache.brooklyn.feed.ssh.SshPollConfig; +import org.apache.brooklyn.feed.ssh.SshPollValue; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.brooklyn.location.ssh.SshMachineLocation; -import org.apache.brooklyn.sensor.feed.ssh.SshFeed; -import org.apache.brooklyn.sensor.feed.ssh.SshPollConfig; -import org.apache.brooklyn.sensor.feed.ssh.SshPollValue; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.core.config.ConfigBag; import org.apache.brooklyn.util.guava.Maybe;
