/* * JBoss, Home of Professional Open Source * Copyright 2010, Red Hat, Inc. and/or its affiliates, * and individual contributors as indicated by the @author tags. * See the copyright.txt in the distribution for a * full listing of individual contributors. * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU Lesser General Public License, v. 2.1. * This program is distributed in the hope that it will be useful, but WITHOUT A * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. * You should have received a copy of the GNU Lesser General Public License, * v.2.1 along with this distribution; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, * MA 02110-1301, USA. * * (C) 2010, * @author JBoss, by Red Hat. */ package com.arjuna.ats.arjuna.tools.osb.api.proxy; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import javax.management.JMException; import javax.management.JMX; import javax.management.MBeanServer; import javax.management.MBeanServerConnection; import javax.management.NotificationListener; import javax.management.ObjectName; import javax.management.remote.JMXConnector; import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXConnectorServer; import javax.management.remote.JMXConnectorServerFactory; import javax.management.remote.JMXServiceURL; import com.arjuna.ats.arjuna.tools.osb.api.mbeans.ParticipantStoreBeanMBean; import com.arjuna.ats.arjuna.tools.osb.api.mbeans.RecoveryStoreBeanMBean; import com.arjuna.ats.arjuna.tools.osb.util.JMXServer; /** * Miscellaneous methods for obtaining remote proxies to the JBossTS Recovery and Participant stores */ public class StoreManagerProxy { // class and bean names of MBeans representing the JBossTS recovery and participant stores public static final String RECOVERY_BEAN_NAME = "jboss.jta:type=com.arjuna.ats.arjuna.tools.osb.api.mbeans.RecoveryStoreBean,name=store1"; public static final String PARTICIPANT_BEAN_NAME = "jboss.jta:type=com.arjuna.ats.arjuna.tools.osb.api.mbeans.ParticipantStoreBean,name=store1"; // public static final String SERVICE_URL = "service:jmx:rmi:///jndi/rmi://localhost:9999/server"; private static Map<String, StoreManagerProxy> proxies = Collections.synchronizedMap(new HashMap<String, StoreManagerProxy>()); private static JMXConnectorServer jmxCServer; private MBeanServerConnection mbsc; // MBean server implementing the object store MBeans private JMXConnector jmxc; private RecoveryStoreProxy rsProxy; // proxy for the recovery store private ParticipantStoreProxy psProxy; // proxy for the participant store private ObjectName recoveryStoreON; // object name of the recover store MBean private ObjectName participantStoreON; // object name of the participant store MBean private NotificationListener recoveryListener = null; private NotificationListener participantListener = null; /** * Construct a holder for Participant and Recovery Store proxies. There is one instance for each connection * to a JVM. In practice there will only ever be one instance. * * @param serviceUrl the url for the MBean server to connect to. Use default to connect to the local MBean Server * @param listener optionally register a listener for notifications * @throws JMException if there are JMX errors during registration of MBeans and notification listeners * @throws IOException if there are errors on the connection to the MBean Server */ private StoreManagerProxy(String serviceUrl, NotificationListener listener) throws JMException, IOException { if ("default".equals(serviceUrl)) { mbsc = JMXServer.getAgent().getServer(); } else { // create an RMI connector JMXServiceURL url = new JMXServiceURL(serviceUrl); // connect to the target MBean server jmxc = JMXConnectorFactory.connect(url, null); mbsc = jmxc.getMBeanServerConnection(); } recoveryStoreON = ObjectName.getInstance(RECOVERY_BEAN_NAME); participantStoreON = ObjectName.getInstance(PARTICIPANT_BEAN_NAME); rsProxy = new RecoveryStoreProxy(JMX.newMBeanProxy( mbsc, recoveryStoreON, RecoveryStoreBeanMBean.class, true)); psProxy = new ParticipantStoreProxy(JMX.newMBeanProxy( mbsc, participantStoreON, ParticipantStoreBeanMBean.class, true)); if (listener != null) { mbsc.addNotificationListener(recoveryStoreON, listener, null, null); mbsc.addNotificationListener(participantStoreON, listener, null, null); } } /** * Mechanism for JMX clients to remove listeners and to close the JMX connection if the client * create one * @throws JMException if there are errors removing listeners * @throws IOException if there are errors removing listeners or closing the JMX connection */ private void close() throws JMException, IOException { System.out.println("Remove notification listener..."); // Remove notification listener on RecoveryStore MBean if (this.recoveryListener != null) mbsc.removeNotificationListener(recoveryStoreON, recoveryListener); if (this.participantListener != null) mbsc.removeNotificationListener(participantStoreON, participantListener); recoveryListener = participantListener = null; // close the connection to the JMX server if (jmxc != null) { jmxc.close(); jmxc = null; } } /** * Helper method for remote clients to connect to an MBean Server * * @param serviceUrl the url on which the target MBean Server resides * @throws IOException if the serviceUrl is invalid or if the connection cannot be started */ public static void startServerConnector(String serviceUrl) throws IOException { jmxCServer = JMXConnectorServerFactory.newJMXConnectorServer( new JMXServiceURL(serviceUrl), null, JMXServer.getAgent().getServer()); // accept JMX connections jmxCServer.start(); } public static void stopServerConnector() throws IOException { jmxCServer.stop(); } /** * MBean registration helper method * @param name MBean object name * @param bean MBean implementation * @param register whether to register or unregister the MBean * @return true if the bean was successfully registered or unregistered */ public static boolean registerBean(ObjectName name, Object bean, boolean register) { try { MBeanServer mbs = JMXServer.getAgent().getServer(); boolean isRegistered = mbs.isRegistered(name); System.out.println((register ? "" : "un") + "registering bean " + name); if (register && isRegistered) { System.out.println(name + " is already registered"); return true; } else if (!register && !isRegistered) { System.out.println(name + " is not registered"); return true; } else if (register) { mbs.registerMBean(bean, name); } else { mbs.unregisterMBean(name); } return true; } catch (JMException e) { System.out.println("MBean registration error: " + e.getMessage()); return false; } } // Obtain a JMX proxy to the ObjectStoreAPI private static synchronized StoreManagerProxy getProxy(String serviceUrl, NotificationListener listener) throws IOException, JMException { if (serviceUrl == null) serviceUrl = "default"; if (!proxies.containsKey(serviceUrl)) proxies.put(serviceUrl, new StoreManagerProxy(serviceUrl, listener)); return proxies.get(serviceUrl); } /** * release proxies to the object stores * @throws JMException if there are errors removing listeners * @throws IOException if there are errors removing listeners or closing the JMX connection */ public static void releaseProxy() throws JMException, IOException { releaseProxy("default"); } /** * release proxies to the object stores * * @param serviceUrl the service url of the MBean Server where the proxies are located * @throws JMException if there are errors removing listeners * @throws IOException if there are errors removing listeners or closing the JMX connection */ public static void releaseProxy(String serviceUrl) throws JMException, IOException { StoreManagerProxy psm = proxies.remove(serviceUrl); if (psm != null) psm.close(); } /** * Get a recovery store proxy from the local MBeanServer * @return a proxy for the target RecoveryStore * @throws JMException if there are JMX errors during registration of MBeans * @throws IOException if there are errors on the connection to the MBean Server */ public static synchronized RecoveryStoreProxy getRecoveryStore() throws IOException, JMException { return getRecoveryStore(null); } /** * Get a recovery store proxy from the local MBeanServer * @param listener listener an optional notification listener (use null if one is not required) * @return a proxy for the target RecoveryStore * @throws JMException if there are JMX errors during registration of MBeans and notification listeners * @throws IOException if there are errors on the connection to the MBean Server */ public static synchronized RecoveryStoreProxy getRecoveryStore(NotificationListener listener) throws IOException, JMException { return getProxy("default", listener).rsProxy; } /** * Get a RecoveryStore proxy. * * @param serviceUrl the location of the MBean Server * @param listener an optional notification listener (use null if one is not required) * @return a proxy for the target RecoveryStore * @throws JMException if there are JMX errors during registration of MBeans and notification listeners * @throws IOException if there are errors on the connection to the MBean Server */ public static synchronized RecoveryStoreProxy getRecoveryStore(String serviceUrl, NotificationListener listener) throws IOException, JMException { return getProxy(serviceUrl, listener).rsProxy; } /** * Get a participant store proxy from the local MBeanServer * @return a proxy for the target ParticipantStore * @throws JMException if there are JMX errors during registration of MBeans * @throws IOException if there are errors on the connection to the MBean Server */ public static synchronized ParticipantStoreProxy getParticipantStore() throws IOException, JMException { return getParticipantStore(null); } /** * Get a participant store proxy from the local MBeanServer * @param listener listener an optional notification listener (use null if one is not required) * @return a proxy for the target ParticipantStore * @throws JMException if there are JMX errors during registration of MBeans and notification listeners * @throws IOException if there are errors on the connection to the MBean Server */ public static synchronized ParticipantStoreProxy getParticipantStore(NotificationListener listener) throws IOException, JMException { return getProxy("default", listener).psProxy; } /** * Get a participant store proxy. * * @param serviceUrl the location of the MBean Server * @param listener an optional notification listener (use null if one is not required) * @return a proxy for the target ParticipantStore * @throws JMException if there are JMX errors during registration of MBeans and notification listeners * @throws IOException if there are errors on the connection to the MBean Server */ public static synchronized ParticipantStoreProxy getParticipantStore(String serviceUrl, NotificationListener listener) throws IOException, JMException { return getProxy(serviceUrl, listener).psProxy; } }