package org.jolokia.backend.executor; /* * Copyright 2009-2013 Roland Huss * * Licensed 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. */ import java.io.IOException; import java.util.*; import javax.management.*; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; import static org.testng.Assert.*; /** * @author roland * @since 23.01.13 */ public class AbstractMBeanServerExecutorTest { TestExecutor executor; @BeforeMethod public void setup() throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException, InterruptedException, InstanceNotFoundException, IOException { executor = new TestExecutor(); } @Test public void jolokiaServer() throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException { assertNotNull(executor.getJolokiaMBeanServer()); AbstractMBeanServerExecutor executorNull = new AbstractMBeanServerExecutor() { @Override protected Set<MBeanServerConnection> getMBeanServers() { return null; } }; assertNull(executorNull.getJolokiaMBeanServer()); } @Test public void eachNull() throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanException, IOException, ReflectionException { executor.each(null, new MBeanServerExecutor.MBeanEachCallback() { public void callback(MBeanServerConnection pConn, ObjectName pName) throws ReflectionException, InstanceNotFoundException, IOException, MBeanException { checkHiddenMBeans(pConn, pName); } }); } @Test public void eachObjectName() throws MalformedObjectNameException, MBeanException, IOException, ReflectionException, NotCompliantMBeanException, InstanceAlreadyExistsException { for (final ObjectName name : new ObjectName[] { new ObjectName("test:type=one"), new ObjectName("test:type=two") }) { executor.each(name,new MBeanServerExecutor.MBeanEachCallback() { public void callback(MBeanServerConnection pConn, ObjectName pName) throws ReflectionException, InstanceNotFoundException, IOException, MBeanException { assertEquals(pName,name); checkHiddenMBeans(pConn,pName); } }); } } @Test public void updateChangeTest() throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException, InstanceNotFoundException, InterruptedException, IOException { executor.registerForMBeanNotifications(); try { assertTrue(executor.hasMBeansListChangedSince(0),"updatedSince: When 0 is given, always return true"); long time = currentTime(); assertFalse(executor.hasMBeansListChangedSince(time), "No update yet"); for (int id = 1; id <=2; id++) { time = currentTime(); executor.addMBean(id); try { assertTrue(executor.hasMBeansListChangedSince(0),"updatedSince: For 0, always return true"); assertTrue(executor.hasMBeansListChangedSince(time),"MBean has been added in the same second, hence it has been updated"); // Wait at a least a second time = currentTime() + 1; assertFalse(executor.hasMBeansListChangedSince(time),"No updated since the last call"); } finally { executor.rmMBean(id); } } } finally { executor.unregisterFromMBeanNotifications(); } } @Test public void destroyWithoutPriorRegistration() throws NoSuchFieldException, IllegalAccessException { // Should always work, even when no registration has happened. Non exisiting listeners will be simplu ignored, since we didnt do any registration before executor.unregisterFromMBeanNotifications(); } private long currentTime() { return System.currentTimeMillis() / 1000; } @Test public void call() throws MalformedObjectNameException, MBeanException, InstanceAlreadyExistsException, NotCompliantMBeanException, IOException, ReflectionException, AttributeNotFoundException, InstanceNotFoundException { String name = getAttribute(executor,"test:type=one","Name"); assertEquals(name,"jolokia"); } private String getAttribute(AbstractMBeanServerExecutor pExecutor, String name, String attribute) throws IOException, ReflectionException, MBeanException, MalformedObjectNameException, AttributeNotFoundException, InstanceNotFoundException { return (String) pExecutor.call(new ObjectName(name),new MBeanServerExecutor.MBeanAction<Object>() { public Object execute(MBeanServerConnection pConn, ObjectName pName, Object... extraArgs) throws ReflectionException, InstanceNotFoundException, IOException, MBeanException, AttributeNotFoundException { return pConn.getAttribute(pName, (String) extraArgs[0]); } },attribute); } @Test(expectedExceptions = InstanceNotFoundException.class,expectedExceptionsMessageRegExp = ".*test:type=bla.*") public void callWithInvalidObjectName() throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanException, IOException, ReflectionException, AttributeNotFoundException, InstanceNotFoundException { getAttribute(executor,"test:type=bla","Name"); } @Test(expectedExceptions = AttributeNotFoundException.class,expectedExceptionsMessageRegExp = ".*Bla.*") public void callWithInvalidAttributeName() throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanException, IOException, ReflectionException, AttributeNotFoundException, InstanceNotFoundException { getAttribute(executor,"test:type=one","Bla"); } @Test public void queryNames() throws IOException, MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException { Set<ObjectName> names = executor.queryNames(null); assertTrue(names.contains(new ObjectName("test:type=one"))); assertTrue(names.contains(new ObjectName("test:type=two"))); assertEquals(names.size(), 3); } private void checkHiddenMBeans(MBeanServerConnection pConn, ObjectName pName) throws MBeanException, InstanceNotFoundException, ReflectionException, IOException { try { if (!pName.equals(new ObjectName("JMImplementation:type=MBeanServerDelegate"))) { assertEquals(pConn.getAttribute(pName,"Name"),"jolokia"); } } catch (AttributeNotFoundException e) { fail("Name should be accessible on all MBeans"); } catch (MalformedObjectNameException e) { // wont happen } try { pConn.getAttribute(pName, "Age"); fail("No access to hidden MBean allowed"); } catch (AttributeNotFoundException exp) { // Expected } } class TestExecutor extends AbstractMBeanServerExecutor { private MBeanServer jolokiaMBeanServer; private final Set<MBeanServerConnection> servers; private final MBeanServer otherMBeanServer; private Testing jOne = new Testing(), oTwo = new Testing(); private Hidden hidden = new Hidden(); TestExecutor() throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException, InterruptedException, InstanceNotFoundException, IOException { jolokiaMBeanServer = MBeanServerFactory.newMBeanServer(); otherMBeanServer = MBeanServerFactory.newMBeanServer(); servers = new LinkedHashSet<MBeanServerConnection>(Arrays.asList(jolokiaMBeanServer, otherMBeanServer)); jolokiaMBeanServer.registerMBean(jOne, new ObjectName("test:type=one")); otherMBeanServer.registerMBean(hidden, new ObjectName("test:type=one")); otherMBeanServer.registerMBean(oTwo, new ObjectName("test:type=two")); } @Override protected Set<MBeanServerConnection> getMBeanServers() { return servers; } @Override protected MBeanServerConnection getJolokiaMBeanServer() { return jolokiaMBeanServer; } void addMBean(int id) throws MalformedObjectNameException, NotCompliantMBeanException, InstanceAlreadyExistsException, MBeanRegistrationException { MBeanServer server = getMBeanServerShuffled(id); server.registerMBean(new Testing(),new ObjectName("test:type=update,id=" + id)); } void rmMBean(int id) throws MalformedObjectNameException, MBeanRegistrationException, InstanceNotFoundException { MBeanServer server = getMBeanServerShuffled(id); server.unregisterMBean(new ObjectName("test:type=update,id=" + id)); } private MBeanServer getMBeanServerShuffled(int pId) { if (pId % 2 == 0) { return jolokiaMBeanServer; } else { return otherMBeanServer; } } } public interface TestingMBean { String getName(); } public static class Testing implements TestingMBean { public String getName() { return "jolokia"; } } public interface HiddenMBean { int getAge(); } public static class Hidden implements HiddenMBean { public int getAge() { return 1; } } }