Repository: tomee Updated Branches: refs/heads/tomee-7.0.x e4ba57043 -> 03f34aa6c
Apply Jonathan Gallimore's JMX Patch to 7.0.5 Project: http://git-wip-us.apache.org/repos/asf/tomee/repo Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/03f34aa6 Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/03f34aa6 Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/03f34aa6 Branch: refs/heads/tomee-7.0.x Commit: 03f34aa6c97272e747a4408a001cd5bc44652ee1 Parents: e4ba570 Author: Jonathan S. Fisher <[email protected]> Authored: Sat Sep 15 10:26:42 2018 -0500 Committer: Jonathan S. Fisher <[email protected]> Committed: Sat Sep 15 10:26:42 2018 -0500 ---------------------------------------------------------------------- .../openejb/assembler/classic/Assembler.java | 87 ++++++++- .../monitoring/ConnectionFactoryMonitor.java | 167 +++++++++++++++++ .../openejb/monitoring/MBeanPojoWrapper.java | 162 ++++++++++++++++ .../GeronimoConnectionManagerFactory.java | 30 +++ .../classic/ConnectionFactoryJMXTest.java | 133 ++++++++++++++ .../assembler/classic/ResourcesJMXTest.java | 184 +++++++++++++++++++ 6 files changed, 756 insertions(+), 7 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tomee/blob/03f34aa6/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java index ac2d080..803744d 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java @@ -109,6 +109,7 @@ import org.apache.openejb.loader.ProvisioningUtil; import org.apache.openejb.loader.SystemInstance; import org.apache.openejb.monitoring.DynamicMBeanWrapper; import org.apache.openejb.monitoring.LocalMBeanServer; +import org.apache.openejb.monitoring.MBeanPojoWrapper; import org.apache.openejb.monitoring.ObjectNameBuilder; import org.apache.openejb.monitoring.remote.RemoteResourceMonitor; import org.apache.openejb.observer.Observes; @@ -178,11 +179,7 @@ import javax.enterprise.inject.spi.Bean; import javax.enterprise.inject.spi.BeanManager; import javax.enterprise.inject.spi.DefinitionException; import javax.enterprise.inject.spi.DeploymentException; -import javax.management.InstanceNotFoundException; -import javax.management.MBeanRegistrationException; -import javax.management.MBeanServer; -import javax.management.MalformedObjectNameException; -import javax.management.ObjectName; +import javax.management.*; import javax.naming.Binding; import javax.naming.Context; import javax.naming.InitialContext; @@ -2128,9 +2125,14 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A ExecutorService.class.cast(resourceAdapter.pool).shutdownNow(); } resourceAdapter.ra.stop(); + + // remove associated JMX object } catch (final Throwable t) { logger.fatal("ResourceAdapter Shutdown Failed: " + name, t); } + + removeResourceMBean(name, "ResourceAdapter"); + } else if (object instanceof ResourceAdapter) { final ResourceAdapter resourceAdapter = (ResourceAdapter) object; try { @@ -2144,6 +2146,9 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A } catch (final Throwable t) { logger.fatal("ResourceAdapter Shutdown Failed: " + name, t); } + + removeResourceMBean(name, "ResourceAdapter"); + } else if (DataSourceFactory.knows(object)) { logger.info("Closing DataSource: " + name); @@ -2162,14 +2167,41 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A } catch (final Exception e) { logger.debug("Not processing resource on destroy: " + className, e); } + + removeResourceMBean(name, "ConnectionFactory"); + } else if (DestroyableResource.class.isInstance(object)) { try { DestroyableResource.class.cast(object).destroyResource(); } catch (final RuntimeException e) { logger.error(e.getMessage(), e); } - } else if (logger.isDebugEnabled() && !DataSource.class.isInstance(object)) { - logger.debug("Not processing resource on destroy: " + className); + + removeResourceMBean(name, "Resource"); + } else if (!DataSource.class.isInstance(object)) { + removeResourceMBean(name, "Resource"); + + if (logger.isDebugEnabled()) { + logger.debug("Not processing resource on destroy: " + className); + } + } + } + + private void removeResourceMBean(String name, String type) { + final ObjectNameBuilder jmxName = new ObjectNameBuilder("openejb.management"); + jmxName.set("J2EEServer", "openejb"); + jmxName.set("J2EEApplication", null); + jmxName.set("j2eeType", ""); + jmxName.set("name",name); + + final MBeanServer server = LocalMBeanServer.get(); + try { + final ObjectName objectName = jmxName.set("j2eeType", type).build(); + if (server.isRegistered(objectName)) { + server.unregisterMBean(objectName); + } + } catch (final Exception e) { + logger.error("Unable to unregister MBean ", e); } } @@ -3218,6 +3250,7 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A unset.remove("threadPoolSize"); logUnusedProperties(unset, serviceInfo); + registerAsMBean(serviceInfo.id, "ResourceAdapter", resourceAdapter); service = new ResourceAdapterReference(resourceAdapter, threadPool, OPENEJB_RESOURCE_JNDI_PREFIX + serviceInfo.id); } else if (service instanceof ManagedConnectionFactory) { final ManagedConnectionFactory managedConnectionFactory = (ManagedConnectionFactory) service; @@ -3245,6 +3278,19 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A // create the connection manager final ConnectionManager connectionManager = (ConnectionManager) connectionManagerRecipe.create(); + + + String txSupport = "xa"; + try { + txSupport = (String) connectionManagerRecipe.getProperty("transactionSupport"); + } catch (Exception e) { + // ignore + } + + if (txSupport == null || txSupport.trim().length() == 0) { + txSupport = "xa"; + } + if (connectionManager == null) { throw new OpenEJBRuntimeException(messages.format("assembler.invalidConnectionManager", serviceInfo.id)); } @@ -3317,6 +3363,8 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A if (serviceInfo.unsetProperties == null || isTemplatizedResource(serviceInfo)) { logUnusedProperties(serviceRecipe, serviceInfo); } // else wait post construct + + registerAsMBean(serviceInfo.id, "Resource", service); } final ResourceCreated event = new ResourceCreated(service, serviceInfo.id); @@ -3324,6 +3372,31 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A return event.getReplacement() == null ? service : event.getReplacement(); } + private void registerAsMBean(final String name, final String type, Object resource) { + final MBeanServer server = LocalMBeanServer.get(); + + final ObjectNameBuilder jmxName = new ObjectNameBuilder("openejb.management"); + jmxName.set("J2EEServer", "openejb"); + jmxName.set("J2EEApplication", null); + jmxName.set("j2eeType", ""); + jmxName.set("name", name); + + try { + final ObjectName objectName = jmxName.set("j2eeType", type).build(); + if (server.isRegistered(objectName)) { + server.unregisterMBean(objectName); + } + + if (DynamicMBean.class.isInstance(resource)) { + server.registerMBean(resource, objectName); + } else { + server.registerMBean(new MBeanPojoWrapper(name, resource), objectName); + } + } catch (final Exception e) { + logger.error("Unable to register MBean ", e); + } + } + private void bindResource(final String id, final Object service, final boolean canReplace) throws OpenEJBException { final String name = OPENEJB_RESOURCE_JNDI_PREFIX + id; final Context jndiContext = containerSystem.getJNDIContext(); http://git-wip-us.apache.org/repos/asf/tomee/blob/03f34aa6/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ConnectionFactoryMonitor.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ConnectionFactoryMonitor.java b/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ConnectionFactoryMonitor.java new file mode 100644 index 0000000..3dad61f --- /dev/null +++ b/container/openejb-core/src/main/java/org/apache/openejb/monitoring/ConnectionFactoryMonitor.java @@ -0,0 +1,167 @@ +/* + * 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.openejb.monitoring; + +import org.apache.geronimo.connector.outbound.GenericConnectionManager; +import org.apache.geronimo.connector.outbound.connectionmanagerconfig.NoPool; +import org.apache.geronimo.connector.outbound.connectionmanagerconfig.PartitionedPool; +import org.apache.geronimo.connector.outbound.connectionmanagerconfig.PoolingSupport; +import org.apache.geronimo.connector.outbound.connectionmanagerconfig.SinglePool; + +public class ConnectionFactoryMonitor { + + private final String name; + private final GenericConnectionManager connectionManager; + private final String txSupport; + + public ConnectionFactoryMonitor(final String name, final GenericConnectionManager connectionManager, final String txSupport) { + this.name = name; + this.connectionManager = connectionManager; + this.txSupport = txSupport; + } + + private PoolingSupport getPooling() { + return connectionManager.getPooling(); + } + + @Managed + public int getMaxSize() { + final PoolingSupport pooling = getPooling(); + + if (PartitionedPool.class.isInstance(pooling)) { + return PartitionedPool.class.cast(pooling).getMaxSize(); + } else if (SinglePool.class.isInstance(pooling)) { + return SinglePool.class.cast(pooling).getMaxSize(); + } else if (NoPool.class.isInstance(pooling)) { + return 0; + } else { + return 0; + } + } + + @Managed + public int getMinSize() { + final PoolingSupport pooling = getPooling(); + + if (PartitionedPool.class.isInstance(pooling)) { + return 0; + } else if (SinglePool.class.isInstance(pooling)) { + return SinglePool.class.cast(pooling).getMinSize(); + } else if (NoPool.class.isInstance(pooling)) { + return 0; + } else { + return 0; + } + } + + @Managed + public int getBlockingTimeoutMilliseconds() { + return connectionManager.getBlockingTimeoutMilliseconds(); + } + + @Managed + public int getIdleTimeoutMinutes() { + return connectionManager.getIdleTimeoutMinutes(); + } + + @Managed + public boolean isMatchAll() { + final PoolingSupport pooling = getPooling(); + + if (PartitionedPool.class.isInstance(pooling)) { + return PartitionedPool.class.cast(pooling).isMatchAll(); + } else if (SinglePool.class.isInstance(pooling)) { + return SinglePool.class.cast(pooling).isMatchAll(); + } else { + return false; + } + } + + @Managed + public String getPartitionStrategy() { + final PoolingSupport pooling = getPooling(); + + if (PartitionedPool.class.isInstance(pooling)) { + if (PartitionedPool.class.cast(pooling).isPartitionByConnectionRequestInfo()) { + return PartitionStrategy.BY_CONNECTOR_PROPERTIES.toString(); + } + + if (PartitionedPool.class.cast(pooling).isPartitionBySubject()) { + return PartitionStrategy.BY_SUBJECT.toString(); + } + + return PartitionStrategy.UNKNOWN.toString(); + } else if (SinglePool.class.isInstance(pooling)) { + return PartitionStrategy.NONE.toString(); + } else if (NoPool.class.isInstance(pooling)) { + return PartitionStrategy.NONE.toString(); + } else { + return PartitionStrategy.NONE.toString(); + } + } + + @Managed + public String getTxSupport() { + return txSupport; + } + + @Managed + public int getPartitionCount() { + return connectionManager.getPartitionCount(); + } + + @Managed + public int getPartitionMaxSize() { + return connectionManager.getPartitionMaxSize(); + } + + @Managed + public int getPartitionMinSize() { + return connectionManager.getPartitionMinSize(); + } + + @Managed + public int getIdleConnectionCount() { + return connectionManager.getIdleConnectionCount(); + } + + @Managed + public int getConnectionCount() { + return connectionManager.getConnectionCount(); + } + + @Managed + public String getName() { + return name; + } + + public enum PartitionStrategy { + NONE("none"), BY_SUBJECT("by-subject"), BY_CONNECTOR_PROPERTIES("by-connector-properties"), UNKNOWN("unknown"); + + private final String name; + + PartitionStrategy(String name) { + this.name = name; + } + + @Override + public String toString() { + return name; + } + } + +} http://git-wip-us.apache.org/repos/asf/tomee/blob/03f34aa6/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanPojoWrapper.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanPojoWrapper.java b/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanPojoWrapper.java new file mode 100644 index 0000000..70367f86 --- /dev/null +++ b/container/openejb-core/src/main/java/org/apache/openejb/monitoring/MBeanPojoWrapper.java @@ -0,0 +1,162 @@ +package org.apache.openejb.monitoring; + +import org.apache.openejb.util.Duration; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.DynamicMBean; +import javax.management.IntrospectionException; +import javax.management.InvalidAttributeValueException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanNotificationInfo; +import javax.management.MBeanOperationInfo; +import javax.management.ReflectionException; +import java.beans.BeanInfo; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/* + * This class attempts to wrap a given class by using Bean introspection to get a list of attributes. + * The intention of the MBean generated is to provide a read-only view of resources available in the server. + * At the present time, this wrapper does not provide write support for attributes, and does not support + * method invocation. + */ +public class MBeanPojoWrapper implements DynamicMBean { + + private final Object delegate; + private final String name; + private MBeanInfo info; + private final Map<String, PropertyDescriptor> attributeMap = new HashMap<>(); + + private static final Set<Class<?>> SUPPORTED_PROPERTY_TYPES = new HashSet<Class<?>>() { + { + add(Integer.class); + add(Boolean.class); + add(Byte.class); + add(Short.class); + add(Float.class); + add(Long.class); + add(Double.class); + add(Integer.TYPE); + add(Boolean.TYPE); + add(Byte.TYPE); + add(Short.TYPE); + add(Float.TYPE); + add(Long.TYPE); + add(Double.TYPE); + add(String.class); + add(Duration.class); + } + }; + + public MBeanPojoWrapper(final String name, final Object delegate) { + this.name = name; + if (delegate == null) { + throw new NullPointerException("Delegate cannot be null"); + } + + this.delegate = delegate; + scan(delegate.getClass()); + } + + private void scan(Class clazz) { + final List<MBeanAttributeInfo> mBeanAttributeInfoList = new ArrayList<>(); + + try { + final BeanInfo beanInfo = Introspector.getBeanInfo(clazz); + + final PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); + + for (final PropertyDescriptor propertyDescriptor : propertyDescriptors) { + final String propertyName = propertyDescriptor.getName(); + Class<?> propertyType = propertyDescriptor.getPropertyType(); + + if (! isSupported(propertyType)) { + continue; + } + + attributeMap.put(propertyName, propertyDescriptor); + try { + mBeanAttributeInfoList.add(new MBeanAttributeInfo(propertyName, "", propertyDescriptor.getReadMethod(), null)); + } catch (IntrospectionException e) { + // no-op + } + } + } catch (java.beans.IntrospectionException e) { + // no-op + } + + // default constructor is mandatory + info = new MBeanInfo(name, + "Auto-created by OpenEJB", + mBeanAttributeInfoList.toArray(new MBeanAttributeInfo[attributeMap.size()]), + null, // default constructor is mandatory + new MBeanOperationInfo[0], + new MBeanNotificationInfo[0]); + } + + private static boolean isSupported(Class<?> type) { + return SUPPORTED_PROPERTY_TYPES.contains(type); + } + + + @Override + public Object getAttribute(final String attribute) throws AttributeNotFoundException, MBeanException, ReflectionException { + if (! attributeMap.containsKey(attribute)) { + throw new AttributeNotFoundException(); + } + + try { + return attributeMap.get(attribute).getReadMethod().invoke(delegate); + } catch (IllegalAccessException e) { + throw new MBeanException(e); + } catch (InvocationTargetException e) { + throw new MBeanException(e); + } + } + + @Override + public void setAttribute(final Attribute attribute) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { + // no-op + } + + @Override + public AttributeList getAttributes(final String[] attributes) { + final AttributeList list = new AttributeList(); + for (final String attribute : attributes) { + try { + list.add(new Attribute(attribute, getAttribute(attribute))); + } catch (final Exception ignore) { + // no-op + } + } + return list; + } + + @Override + public AttributeList setAttributes(final AttributeList attributes) { + // no-op - not supported + return null; + } + + @Override + public Object invoke(final String actionName, final Object[] params, final String[] signature) throws MBeanException, ReflectionException { + // no-op - not supported + return null; + } + + @Override + public MBeanInfo getMBeanInfo() { + return info; + } +} http://git-wip-us.apache.org/repos/asf/tomee/blob/03f34aa6/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoConnectionManagerFactory.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoConnectionManagerFactory.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoConnectionManagerFactory.java index cebe9cc..852dc32 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoConnectionManagerFactory.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/GeronimoConnectionManagerFactory.java @@ -38,9 +38,17 @@ import org.apache.geronimo.connector.outbound.connectionmanagerconfig.XATransact import org.apache.geronimo.transaction.manager.NamedXAResourceFactory; import org.apache.geronimo.transaction.manager.RecoverableTransactionManager; import org.apache.openejb.OpenEJBRuntimeException; +import org.apache.openejb.monitoring.ConnectionFactoryMonitor; +import org.apache.openejb.monitoring.LocalMBeanServer; +import org.apache.openejb.monitoring.ManagedMBean; +import org.apache.openejb.monitoring.ObjectNameBuilder; import org.apache.openejb.util.Duration; +import org.apache.openejb.util.LogCategory; +import org.apache.openejb.util.Logger; import org.apache.openejb.util.reflection.Reflections; +import javax.management.MBeanServer; +import javax.management.ObjectName; import javax.resource.ResourceException; import javax.resource.spi.ManagedConnection; import javax.resource.spi.ManagedConnectionFactory; @@ -64,6 +72,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReadWriteLock; public class GeronimoConnectionManagerFactory { + private final Logger logger = Logger.getInstance(LogCategory.OPENEJB_STARTUP, GeronimoConnectionManagerFactory.class); private String name; private ClassLoader classLoader; @@ -260,6 +269,27 @@ public class GeronimoConnectionManagerFactory { mcf, name, classLoader); } + + final ConnectionFactoryMonitor cfm = new ConnectionFactoryMonitor(name, mgr, transactionSupport); + final MBeanServer server = LocalMBeanServer.get(); + + final ObjectNameBuilder jmxName = new ObjectNameBuilder("openejb.management"); + jmxName.set("J2EEServer", "openejb"); + jmxName.set("J2EEApplication", null); + jmxName.set("j2eeType", ""); + jmxName.set("name", name); + + try { + final ObjectName objectName = jmxName.set("j2eeType", "ConnectionFactory").build(); + if (server.isRegistered(objectName)) { + server.unregisterMBean(objectName); + } + + server.registerMBean(new ManagedMBean(cfm), objectName); + } catch (final Exception e) { + logger.error("Unable to register MBean ", e); + } + return mgr; } http://git-wip-us.apache.org/repos/asf/tomee/blob/03f34aa6/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/ConnectionFactoryJMXTest.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/ConnectionFactoryJMXTest.java b/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/ConnectionFactoryJMXTest.java new file mode 100644 index 0000000..5490fa7 --- /dev/null +++ b/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/ConnectionFactoryJMXTest.java @@ -0,0 +1,133 @@ +/** + * + * 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.openejb.assembler.classic; + +import junit.framework.TestCase; +import org.apache.openejb.OpenEJB; +import org.apache.openejb.config.ConfigurationFactory; +import org.apache.openejb.config.EjbModule; +import org.apache.openejb.jee.EjbJar; +import org.apache.openejb.jee.StatelessBean; +import org.apache.openejb.client.LocalInitialContextFactory; +import org.apache.openejb.monitoring.LocalMBeanServer; + +import javax.annotation.Resource; +import javax.jms.Connection; +import javax.jms.ConnectionFactory; +import javax.management.AttributeNotFoundException; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.MBeanException; +import javax.management.ObjectName; +import javax.management.ReflectionException; +import javax.naming.Context; +import javax.naming.InitialContext; +import java.util.Properties; + +/** + * @version $Rev$ $Date$ + */ +public class ConnectionFactoryJMXTest extends TestCase { + + public void test() throws Exception { + final ConfigurationFactory config = new ConfigurationFactory(); + final Assembler assembler = new Assembler(); + + // System services + assembler.createProxyFactory(config.configureService(ProxyFactoryInfo.class)); + assembler.createTransactionManager(config.configureService(TransactionServiceInfo.class)); + assembler.createSecurityService(config.configureService(SecurityServiceInfo.class)); + + // Fake connection factory + assembler.createResource(config.configureService("Default JMS Resource Adapter", ResourceInfo.class)); + final ResourceInfo resourceInfo = config.configureService("Default JMS Connection Factory", ResourceInfo.class); + resourceInfo.id = "CF"; + resourceInfo.properties.setProperty("TransactionSupport", "xa"); + resourceInfo.properties.setProperty("MaxConnections", "5"); + assembler.createResource(resourceInfo); + + // generate ejb jar application + final EjbJar ejbJar = new EjbJar(); + ejbJar.addEnterpriseBean(new StatelessBean("fakeBean", FakeStatelessBean.class)); + final EjbModule ejbModule = new EjbModule(getClass().getClassLoader(), "FakeEjbJar", "fake.jar", ejbJar, null); + + // configure and deploy it + final EjbJarInfo info = config.configureApplication(ejbModule); + assembler.createEjbJar(info); + + check(new ObjectName("openejb.management:J2EEServer=openejb,J2EEApplication=<empty>,j2eeType=ConnectionFactory,name=CF"), 0, 0); + + final Properties p = new Properties(); + p.setProperty(Context.INITIAL_CONTEXT_FACTORY, LocalInitialContextFactory.class.getName()); + final FakeStateless fakeBeanLocal = (FakeStateless) new InitialContext(p).lookup("fakeBeanLocal"); + fakeBeanLocal.doIt(); + + OpenEJB.destroy(); + + // ensure the bean is removed when the resource is undeployed + assertFalse(LocalMBeanServer.get().isRegistered(new ObjectName("openejb.management:J2EEServer=openejb,J2EEApplication=<empty>,j2eeType=ConnectionFactory,name=CF"))); + } + + private static void check(ObjectName on, final int connectionCount, final int idleCount) throws InstanceNotFoundException, IntrospectionException, ReflectionException, MBeanException, AttributeNotFoundException { + assertNotNull(LocalMBeanServer.get().getMBeanInfo(on)); + + assertEquals(5000, LocalMBeanServer.get().getAttribute(on, "BlockingTimeoutMilliseconds")); + assertEquals(connectionCount, LocalMBeanServer.get().getAttribute(on, "ConnectionCount")); + assertEquals(idleCount, LocalMBeanServer.get().getAttribute(on, "IdleConnectionCount")); + assertEquals(15, LocalMBeanServer.get().getAttribute(on, "IdleTimeoutMinutes")); + assertEquals(false, LocalMBeanServer.get().getAttribute(on, "MatchAll")); + assertEquals(10, LocalMBeanServer.get().getAttribute(on, "MaxSize")); + assertEquals(0, LocalMBeanServer.get().getAttribute(on, "MinSize")); + assertEquals("CF", LocalMBeanServer.get().getAttribute(on, "Name")); + assertEquals(1, LocalMBeanServer.get().getAttribute(on, "PartitionCount")); + assertEquals(10, LocalMBeanServer.get().getAttribute(on, "PartitionMaxSize")); + assertEquals(0, LocalMBeanServer.get().getAttribute(on, "PartitionMinSize")); + assertEquals("none", LocalMBeanServer.get().getAttribute(on, "PartitionStrategy")); + assertEquals("xa", LocalMBeanServer.get().getAttribute(on, "TxSupport")); + } + + public interface FakeStateless { + public void doIt(); + } + + public static class FakeStatelessBean implements FakeStateless { + + @Resource + private ConnectionFactory cf; + + @Override + public void doIt() { + try { + final Connection connection = cf.createConnection(); + + // check we see the connection and it is not idle + check( + new ObjectName("openejb.management:J2EEServer=openejb,J2EEApplication=<empty>,j2eeType=ConnectionFactory,name=CF"), + 1, + 0 + ); + + connection.close(); + } catch (Exception e) { + fail("Unexpected exception thrown " + e); + } + + + } + } +} http://git-wip-us.apache.org/repos/asf/tomee/blob/03f34aa6/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/ResourcesJMXTest.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/ResourcesJMXTest.java b/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/ResourcesJMXTest.java new file mode 100644 index 0000000..6b81600 --- /dev/null +++ b/container/openejb-core/src/test/java/org/apache/openejb/assembler/classic/ResourcesJMXTest.java @@ -0,0 +1,184 @@ +/** + * + * 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.openejb.assembler.classic; + +import junit.framework.TestCase; +import org.apache.openejb.OpenEJB; +import org.apache.openejb.config.ConfigurationFactory; +import org.apache.openejb.monitoring.LocalMBeanServer; + +import javax.management.*; +import javax.resource.ResourceException; +import javax.resource.spi.*; +import javax.resource.spi.endpoint.MessageEndpoint; +import javax.resource.spi.endpoint.MessageEndpointFactory; +import javax.transaction.xa.XAResource; +import java.util.Properties; + +/** + * @version $Rev$ $Date$ + */ +public class ResourcesJMXTest extends TestCase { + public void test() throws Exception { + final ConfigurationFactory config = new ConfigurationFactory(); + final Assembler assembler = new Assembler(); + + // System services + assembler.createProxyFactory(config.configureService(ProxyFactoryInfo.class)); + assembler.createTransactionManager(config.configureService(TransactionServiceInfo.class)); + assembler.createSecurityService(config.configureService(SecurityServiceInfo.class)); + + // FakeRA + final ResourceInfo resourceInfo = new ResourceInfo(); + resourceInfo.service = "Resource"; + resourceInfo.className = FakeRA.class.getName(); + resourceInfo.id = "FakeRA"; + resourceInfo.properties = new Properties(); + assembler.createResource(resourceInfo); + + // FakeRA container + final ContainerInfo containerInfo = config.configureService(MdbContainerInfo.class); + containerInfo.id = "FakeContainer"; + containerInfo.displayName = "Fake Container"; + containerInfo.properties.setProperty("ResourceAdapter", "FakeRA"); + containerInfo.properties.setProperty("MessageListenerInterface", FakeMessageListener.class.getName()); + containerInfo.properties.setProperty("ActivationSpecClass", FakeActivationSpec.class.getName()); + assembler.createContainer(containerInfo); + + final ResourceInfo testResource = new ResourceInfo(); + testResource.id = "testResource"; + testResource.className = FakeResource.class.getName(); + + final Properties p = new Properties(); + p.put("host", "localhost"); + p.put("port", "12345"); + p.put("parameter", "test param"); + testResource.properties = p; + + assembler.createResource(testResource); + + { + ObjectName on = new ObjectName("openejb.management:J2EEServer=openejb,J2EEApplication=<empty>,j2eeType=ResourceAdapter,name=FakeRA"); + assertNotNull(LocalMBeanServer.get().getMBeanInfo(on)); + assertEquals("faketest", LocalMBeanServer.get().getAttribute(on, "name")); + assertEquals(10, LocalMBeanServer.get().getAttribute(on, "priority")); + } + { + ObjectName on = new ObjectName("openejb.management:J2EEServer=openejb,J2EEApplication=<empty>,j2eeType=Resource,name=testResource"); + assertNotNull(LocalMBeanServer.get().getMBeanInfo(on)); + assertEquals("localhost", LocalMBeanServer.get().getAttribute(on, "host")); + assertEquals(12345, LocalMBeanServer.get().getAttribute(on, "port")); + assertEquals("test param", LocalMBeanServer.get().getAttribute(on, "parameter")); + } + + OpenEJB.destroy(); + + assertFalse(LocalMBeanServer.get().isRegistered(new ObjectName("openejb.management:J2EEServer=openejb,J2EEApplication=<empty>,j2eeType=ResourceAdapter,name=FakeRA"))); + assertFalse(LocalMBeanServer.get().isRegistered(new ObjectName("openejb.management:J2EEServer=openejb,J2EEApplication=<empty>,j2eeType=Resource,name=testResource"))); + } + + public interface FakeMessageListener { + void doIt(Properties properties); + } + + public static class FakeRA implements ResourceAdapter { + + private String name = "faketest"; + private int priority = 10; + + + public void start(final BootstrapContext bootstrapContext) throws ResourceAdapterInternalException { + } + + public void stop() { + } + + public void endpointActivation(final MessageEndpointFactory messageEndpointFactory, final ActivationSpec activationSpec) throws ResourceException { + final MessageEndpoint endpoint = messageEndpointFactory.createEndpoint(null); + } + + public void endpointDeactivation(final MessageEndpointFactory messageEndpointFactory, final ActivationSpec activationSpec) { + } + + public XAResource[] getXAResources(final ActivationSpec[] activationSpecs) throws ResourceException { + return new XAResource[0]; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public int getPriority() { + return priority; + } + + public void setPriority(int priority) { + this.priority = priority; + } + } + + public static class FakeActivationSpec implements ActivationSpec { + private FakeRA fakeRA; + + public void validate() throws InvalidPropertyException { + } + + public FakeRA getResourceAdapter() { + return fakeRA; + } + + public void setResourceAdapter(final ResourceAdapter resourceAdapter) { + this.fakeRA = (FakeRA) resourceAdapter; + } + } + + public static class FakeResource { + private String host; + private int port; + private String parameter; + + public String getHost() { + return host; + } + + public void setHost(String host) { + this.host = host; + } + + public int getPort() { + return port; + } + + public void setPort(int port) { + this.port = port; + } + + public String getParameter() { + return parameter; + } + + public void setParameter(String parameter) { + this.parameter = parameter; + } + } + +}
