/* * JBoss, Home of Professional Open Source. * Copyright 2008, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY 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 along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jboss.management.mejb; import org.jboss.logging.Logger; import org.jboss.management.j2ee.J2EEDomain; import org.jboss.mx.util.MBeanServerLocator; import javax.ejb.CreateException; import javax.ejb.EJBException; import javax.ejb.SessionBean; import javax.ejb.SessionContext; import javax.management.*; import javax.management.j2ee.ManagementHome; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; import java.rmi.RemoteException; import java.util.Set; /** * Management Session Bean to enable the client to manage the * server its is deployed on. This is the implementation of the * JSR-77 specification MEJB. * * @author <a href="mailto:marc.fleury@jboss.org">Marc Fleury</a> * @author Andreas Schaefer * @author Scott.Stark@jboss.org * @version $Revision: 81025 $ * @ejb:bean name="MEJB" * display-name="JBoss Management EJB (MEJB)" * type="Stateless" * jndi-name="ejb/mgmt/MEJB" * @ejb:interface extends="javax.management.j2ee.Management" * @ejb:home generate="none" * remote-class="javax.management.j2ee.ManagementHome" * @ejb:env-entry description="JNDI-Name of the MBeanServer to be used to look it up. If 'null' the first of all listed local MBeanServer is taken" * name="Server-Name" * value="null" * @ejb:transaction type="Supports" */ public class ManagementBean implements SessionBean { // ------------------------------------------------------------------------- // Static // ------------------------------------------------------------------------- /** * Logger to log. Can be used because this EJB is specific to JBoss */ private static Logger log = Logger.getLogger(ManagementBean.class); // ------------------------------------------------------------------------- // Members // ------------------------------------------------------------------------- private SessionContext mContext; /** * Reference to the MBeanServer all the methods of this Connector are * forwarded to */ private MBeanServer mbeanServer; /** * JMX Name of the HA Management Service used in a Cluster */ private ObjectName mManagementService; // ------------------------------------------------------------------------- // Methods // ------------------------------------------------------------------------- /** * @throws RemoteException Necessary for a EJB * @ejb:interface-method view-type="remote" */ public Object getAttribute(ObjectName pName, String pAttribute) throws MBeanException, AttributeNotFoundException, InstanceNotFoundException, ReflectionException, RemoteException { try { if (mManagementService == null) { return mbeanServer.getAttribute(pName, pAttribute); } else { return mbeanServer.invoke(mManagementService, "getAttribute", new Object[]{ pName, pAttribute }, new String[]{ ObjectName.class.getName(), String.class.getName() }); } } // The CTS expects an AttributeNotFoundException, but ModelMBeanInfoSupport // throws IllegalArgumentException - we need to rethrow to make the CTS happy. catch (RuntimeOperationsException e) { if (e.getTargetException() instanceof IllegalArgumentException) { throw new AttributeNotFoundException("MBean attribute not found: " + pAttribute); } throw e; } } /** * @throws RemoteException Necessary for a EJB * @ejb:interface-method view-type="remote" */ public AttributeList getAttributes(ObjectName pName, String[] pAttributes) throws InstanceNotFoundException, ReflectionException, RemoteException { if (mManagementService == null) { return mbeanServer.getAttributes(pName, pAttributes); } else { try { return (AttributeList) mbeanServer.invoke(mManagementService, "getAttributes", new Object[]{ pName, pAttributes }, new String[]{ ObjectName.class.getName(), String[].class.getName() }); } catch (MBeanException me) { log.error("getAttributes() got exception from cluster service", me); // Should never happens return null; } } } /** * @throws RemoteException Necessary for a EJB * @ejb:interface-method view-type="remote" */ public String getDefaultDomain() throws RemoteException { if (mManagementService == null) { return J2EEDomain.getDomainName(); } else { try { return (String) mbeanServer.getAttribute(mManagementService, "DefaultDomain"); } catch (JMException jme) { // Should never happen log.error("getDefaultDomain() got exception from cluster service", jme); return null; } } } /** * @throws RemoteException Necessary for a EJB * @ejb:interface-method view-type="remote" */ public Integer getMBeanCount() throws RemoteException { if (mManagementService == null) { try { Set mbeans = this.queryNames(new ObjectName("*:*"), null); return new Integer(mbeans.size()); } catch (Exception e) { } return new Integer(0); } else { try { return (Integer) mbeanServer.invoke(mManagementService, "getMBeanCount", new Object[]{}, new String[]{}); } catch (JMException jme) { log.error("getMBeanCount() got exception from cluster service", jme); // Should never happen return null; } } } /** * @throws RemoteException Necessary for a EJB * @ejb:interface-method view-type="remote" */ public MBeanInfo getMBeanInfo(ObjectName pName) throws IntrospectionException, InstanceNotFoundException, ReflectionException, RemoteException { if (mManagementService == null) { return mbeanServer.getMBeanInfo(pName); } else { try { return (MBeanInfo) mbeanServer.invoke(mManagementService, "getMBeanInfo", new Object[]{ pName }, new String[]{ ObjectName.class.getName() }); } catch (MBeanException me) { log.error("getMBeanInfo() got exception from cluster service", me); // Should never happen return null; } } } /** * @throws RemoteException Necessary for a EJB * @ejb:interface-method view-type="remote" */ public javax.management.j2ee.ListenerRegistration getListenerRegistry() throws RemoteException { return new ListenerRegistration((ManagementHome) mContext.getEJBObject().getEJBHome(), new String[]{}); } /** * @throws RemoteException Necessary for a EJB * @ejb:interface-method view-type="remote" */ public Object invoke(ObjectName pName, String pOperationName, Object[] pParams, String[] pSignature) throws InstanceNotFoundException, MBeanException, ReflectionException, RemoteException { // Convert start(), startRecursive() and stop() to the // internal methods: mejbStart(), mejbStartRecursive() and mejbStop if (pOperationName.equals("start")) { pOperationName = "mejbStart"; } else if (pOperationName.equals("startRecursive")) { pOperationName = "mejbStartRecursive"; } else if (pOperationName.equals("stop")) { pOperationName = "mejbStop"; } if (mManagementService == null) { return mbeanServer.invoke(pName, pOperationName, pParams, pSignature); } else { return mbeanServer.invoke(mManagementService, "invoke", new Object[]{ pName, pOperationName, pParams, pSignature }, new String[]{ ObjectName.class.getName(), String.class.getName(), Object[].class.getName(), String[].class.getName() }); } } /** * @throws RemoteException Necessary for a EJB * @ejb:interface-method view-type="remote" */ public boolean isRegistered(ObjectName pName) throws RemoteException { if (mManagementService == null) { return mbeanServer.isRegistered(pName); } else { try { Boolean lCheck = (Boolean) mbeanServer.invoke(mManagementService, "isRegistered", new Object[]{ pName }, new String[]{ ObjectName.class.getName() }); if (lCheck != null) { return lCheck.booleanValue(); } } catch (JMException jme) { log.error("isRegistered() got exception from cluster service", jme); // Should never happen } return false; } } /** * @throws RemoteException Necessary for a EJB * @ejb:interface-method view-type="remote" */ public Set queryNames(ObjectName pName, QueryExp pQuery) throws RemoteException { if (mManagementService == null) { return mbeanServer.queryNames(pName, pQuery); } else { try { return (Set) mbeanServer.invoke(mManagementService, "queryNames", new Object[]{ pName, pQuery }, new String[]{ ObjectName.class.getName(), QueryExp.class.getName() }); } catch (JMException jme) { log.error("queryNames() got exception from cluster service", jme); // Should never happen return null; } } } /** * @throws RemoteException Necessary for a EJB * @ejb:interface-method view-type="remote" */ public void setAttribute(ObjectName pName, Attribute pAttribute) throws AttributeNotFoundException, InstanceNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException, RemoteException { if (mManagementService == null) { mbeanServer.setAttribute(pName, pAttribute); } else { mbeanServer.invoke(mManagementService, "setAttribute", new Object[]{ pName, pAttribute }, new String[]{ ObjectName.class.getName(), String.class.getName() }); } } /** * @throws RemoteException Necessary for a EJB * @ejb:interface-method view-type="remote" */ public AttributeList setAttributes(ObjectName pName, AttributeList pAttributes) throws InstanceNotFoundException, ReflectionException, RemoteException { if (mManagementService == null) { return mbeanServer.setAttributes(pName, pAttributes); } else { try { return (AttributeList) mbeanServer.invoke(mManagementService, "setAttributes", new Object[]{ pName, pAttributes }, new String[]{ ObjectName.class.getName(), AttributeList.class.getName() }); } catch (MBeanException me) { log.error("setAttributes() got exception from cluster service", me); // Should never happen return null; } } } /** * @throws RemoteException Necessary for a EJB * @ejb:interface-method view-type="remote" */ public ObjectInstance createMBean(String pClass, ObjectName pName, Object[] pParameters, String[] pSignature) throws InstanceAlreadyExistsException, MBeanException, MBeanRegistrationException, NotCompliantMBeanException, ReflectionException, RemoteException { if (mManagementService == null) { return mbeanServer.createMBean(pClass, pName, pParameters, pSignature); } else { try { return (ObjectInstance) mbeanServer.invoke(mManagementService, "createMBean", new Object[]{ pClass, pName, pParameters, pSignature }, new String[]{ String.class.getName(), ObjectName.class.getName(), Object[].class.getName(), String[].class.getName() }); } catch (InstanceNotFoundException infe) { log.error("createMBean() got exception from cluster service", infe); // Should never happen return null; } } } /** * @throws RemoteException Necessary for a EJB * @ejb:interface-method view-type="remote" */ public void unregisterMBean(ObjectName pName) throws InstanceNotFoundException, MBeanRegistrationException, RemoteException { if (mManagementService == null) { mbeanServer.unregisterMBean(pName); } else { try { mbeanServer.invoke(mManagementService, "unregisterMBean", new Object[]{ pName }, new String[]{ ObjectName.class.getName() }); } // Should never happen catch (MBeanException me) { log.error("unregisterMBean() got exception from cluster service", me); } catch (ReflectionException re) { log.error("unregisterMBean() got exception from cluster service", re); } } } /** * @throws RemoteException Necessary for a EJB * @ejb:interface-method view-type="remote" */ public void addNotificationListener(ObjectName pBroadcaster, ObjectName pListener, NotificationFilter pFilter, Object pHandback) throws InstanceNotFoundException, RemoteException { if (mManagementService == null) { mbeanServer.addNotificationListener(pBroadcaster, pListener, pFilter, pHandback); } else { try { mbeanServer.invoke(mManagementService, "addNotificationListener", new Object[]{ pBroadcaster, pListener, pFilter, pHandback }, new String[]{ ObjectName.class.getName(), ObjectName.class.getName(), NotificationFilter.class.getName(), Object.class.getName() }); } // Should never happen catch (MBeanException me) { log.error("addNotificationListener() got exception from cluster service", me); } catch (ReflectionException re) { log.error("addNotificationListener() got exception from cluster service", re); } } } /** * @throws RemoteException Necessary for a EJB * @ejb:interface-method view-type="remote" */ public void removeNotificationListener(ObjectName pBroadcaster, ObjectName pListener) throws InstanceNotFoundException, ListenerNotFoundException, RemoteException { if (mManagementService == null) { mbeanServer.removeNotificationListener(pBroadcaster, pListener); } else { try { mbeanServer.invoke(mManagementService, "removeNotificationListener", new Object[]{ pBroadcaster, pListener }, new String[]{ ObjectName.class.getName(), ObjectName.class.getName() }); } // Should never happen catch (MBeanException me) { log.error("removeNotificationListener() got exception from cluster service", me); } catch (ReflectionException re) { log.error("removeNotificationListener() got exception from cluster service", re); } } } /** * Create the Session Bean which takes the first available * MBeanServer as target server * * @throws CreateException * @ejb:create-method */ public void ejbCreate() throws CreateException { if (mbeanServer == null) { try { Context jndiCtx = new InitialContext(); String serverName = (String) jndiCtx.lookup("java:comp/env/Server-Name"); serverName = serverName.trim(); if (serverName == null || serverName.length() == 0 || serverName.equals("null")) { try { mbeanServer = MBeanServerLocator.locateJBoss(); } catch (IllegalStateException e) { throw new CreateException("No local JMX MBeanServer available"); } } else { Object lServer = jndiCtx.lookup(serverName); if (lServer != null) { if (lServer instanceof MBeanServer) { mbeanServer = (MBeanServer) lServer; } else { throw new CreateException("Server: " + lServer + " reference by Server-Name: " + serverName + " is not of type MBeanServer"); } } else { throw new CreateException("Server-Name " + serverName + " does not reference an Object in JNDI"); } } } catch (NamingException ne) { throw new EJBException(ne); } } // Check to see if a HA-Management Service is available to be used try { ObjectName haManagement = new ObjectName("jboss:service=HAManagement"); ObjectInstance oi = mbeanServer.getObjectInstance(haManagement); mManagementService = oi.getObjectName(); } catch (Exception e) { log.debug("ejbCreate() failed to locate jboss:service=HAManagement", e); } } /** * Describes the instance and its content for debugging purpose * * @return Debugging information about the instance and its content */ public String toString() { return "Management [ " + " ]"; } // ------------------------------------------------------------------------- // Framework Callbacks // ------------------------------------------------------------------------- /** * Set the associated session context. The container invokes this method on * an instance after the instance has been created. * <p>This method is called with no transaction context. * * @param aContext A SessionContext interface for the instance. The instance * should store the reference to the context in an instance variable. * @throws EJBException Should something go wrong while seting the context, * an EJBException will be thrown. */ public void setSessionContext(SessionContext aContext) throws EJBException { mContext = aContext; } /** * The activate method is called when the instance is activated from its * "passive" state. The instance should acquire any resource that it has * released earlier in the ejbPassivate() method. * <p>This method is called with no transaction context. * * @throws EJBException Thrown by the method to indicate a failure caused * by a system-level error */ public void ejbActivate() throws EJBException { } /** * The passivate method is called before the instance enters the "passive" * state. The instance should release any resources that it can re-acquire * later in the ejbActivate() method. * <p>After the passivate method completes, the instance must be in a state * that allows the container to use the Java Serialization protocol to * externalize and store away the instance's state. * <p>This method is called with no transaction context. * * @throws EJBException Thrown by the method to indicate a failure caused * by a system-level error */ public void ejbPassivate() throws EJBException { } /** * A container invokes this method before it ends the life of the session * object. This happens as a result of a client's invoking a remove * operation, or when a container decides to terminate the session object * after a timeout. * <p>This method is called with no transaction context. * * @throws EJBException Thrown by the method to indicate a failure caused * by a system-level error */ public void ejbRemove() throws EJBException { } }