package org.mobicents.slee.container.management.jmx; import java.io.Serializable; import java.lang.reflect.Constructor; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; import javax.management.StandardMBean; import javax.slee.InvalidArgumentException; import javax.slee.management.ManagementException; import javax.slee.management.NotificationSource; import javax.slee.management.ProfileTableUsageMBean; import javax.slee.management.ResourceManagementMBean; import javax.slee.management.UsageParameterSetNameAlreadyExistsException; import javax.slee.usage.UnrecognizedUsageParameterSetNameException; import javax.slee.usage.UsageNotificationManagerMBean; import org.apache.log4j.Logger; import org.mobicents.slee.container.SleeContainer; import org.mobicents.slee.container.component.SleeComponentWithUsageParametersInterface; /** * Abstract class code for a "parent" usage mbean, such as the * {@link ResourceManagementMBean} or {@link ProfileTableUsageMBean} * * @author martins * */ public abstract class AbstractUsageMBeanImplParent extends StandardMBean implements UsageMBeanImplParent, Serializable { /** * */ private static final long serialVersionUID = 1L; protected abstract Logger getLogger(); /** * the object name used to register this mbean */ private ObjectName objectName; /** * the child name param usage mbeans registred by this mbean */ private ConcurrentHashMap<String, UsageMBeanImpl> usageMBeans = new ConcurrentHashMap<String, UsageMBeanImpl>(); /** * the default usage mbean */ private UsageMBeanImpl defaultUsageMBean; /** * the usage notification manager mbean */ private UsageNotificationManagerMBeanImpl notificationManager; /** * the container */ private final SleeContainer sleeContainer; /** * the component */ private final SleeComponentWithUsageParametersInterface component; /** * the notification source used by the usage mbeans */ private final NotificationSource notificationSource; /** * */ private boolean closed = false; /** * Creates a new instance of an abstract usage mbean * @param mBeanInterfaceClass the class poiting to the interface this mbean implements * @param component the component related with this mbean * @param notificationSource the notification source to be used in notifications sent by the notification manager mbean * @param sleeContainer "the" container * @throws NotCompliantMBeanException * @throws MalformedObjectNameException * @throws NullPointerException */ public AbstractUsageMBeanImplParent(Class<?> mBeanInterfaceClass, SleeComponentWithUsageParametersInterface component, NotificationSource notificationSource, SleeContainer sleeContainer) throws NotCompliantMBeanException, MalformedObjectNameException, NullPointerException { super(mBeanInterfaceClass); this.sleeContainer = sleeContainer; this.component = component; this.notificationSource = notificationSource; } /** * Retrieves the object name of this mbean * * @return */ public ObjectName getObjectName() { return objectName; } /** * Sets the object name of this mbean * * @param objectName */ public void setObjectName(ObjectName objectName) { this.objectName = objectName; } /** * Removes the mbean * */ public void remove() { Logger logger = getLogger(); if (logger.isDebugEnabled()) { logger.debug("Closing " + toString()); } final MBeanServer mbeanServer = sleeContainer.getMBeanServer(); try { mbeanServer.unregisterMBean(getObjectName()); } catch (Exception e) { logger.error("failed to remove " + toString(), e); } // remove all usage param if (logger.isDebugEnabled()) { logger .debug("Removing all named usage parameters of " + toString()); } for (String name : usageMBeans.keySet()) { try { _removeUsageParameterSet(name,false); } catch (Throwable e) { logger.error(e.getMessage(), e); } } // also remove the default try { removeUsageParameterSet(); } catch (Throwable e) { logger.error(e.getMessage(), e); } } /** * * * @throws ManagementException */ public void close() throws ManagementException { ensureMBeanIsNotClosed(); closed = true; } public void open() { closed = false; } /** * * @throws ManagementException */ protected void ensureMBeanIsNotClosed() throws ManagementException { if (closed) { throw new ManagementException("closed"); } } /** * Creates the default usage param (and its mbean) * * @throws NullPointerException * @throws InvalidArgumentException * @throws UsageParameterSetNameAlreadyExistsException * @throws ManagementException */ public void createUsageParameterSet() throws NullPointerException, InvalidArgumentException, UsageParameterSetNameAlreadyExistsException, ManagementException { _createUsageParameterSet(null, false); } /** * Creates the usage param (and its mbean) for the specified name * * @param paramSetName * @throws NullPointerException * @throws InvalidArgumentException * @throws UsageParameterSetNameAlreadyExistsException * @throws ManagementException */ public void createUsageParameterSet(String paramSetName) throws NullPointerException, InvalidArgumentException, UsageParameterSetNameAlreadyExistsException, ManagementException { if (paramSetName == null) throw new NullPointerException("usage param set is null"); if (paramSetName.length() == 0) throw new InvalidArgumentException( "The lenght of the Usage Parameter Set Name is zero!"); if (!isValidUsageParameterName(paramSetName)) throw new InvalidArgumentException( "The lenght of the Usage Parameter Set Name is zero!"); _createUsageParameterSet(paramSetName, true); } private synchronized void _createUsageParameterSet(String name, boolean failIfSbbHasNoUsageParamSet) throws NullPointerException, UsageParameterSetNameAlreadyExistsException, ManagementException { ensureMBeanIsNotClosed(); Logger logger = getLogger(); // get usage parameter class Class<?> usageParameterClass = component.getUsageParametersConcreteClass(); // check if the usage parameter name set already exists if (name != null && this.usageMBeans.containsKey(name)) { throw new UsageParameterSetNameAlreadyExistsException("name " + name + " already exists for " + this); } UsageMBeanImpl usageMbean = null; UsageNotificationManagerMBeanImpl usageNotificationManagerMBean = null; Thread currentThread = Thread.currentThread(); ClassLoader currentThreadClassLoader = currentThread .getContextClassLoader(); try { // change class loader currentThread.setContextClassLoader(component.getClassLoader()); // create the actual usage parameter instance and map it in the // mbean InstalledUsageParameterSet installedUsageParameterSet = (InstalledUsageParameterSet) usageParameterClass.newInstance(); // create and register the usage mbean Class<?> usageParameterMBeanClass = component .getUsageParametersMBeanImplConcreteClass(); Constructor<?> constructor = usageParameterMBeanClass .getConstructor(new Class[] { Class.class, NotificationSource.class }); ObjectName usageParameterMBeanObjectName = generateUsageParametersMBeanObjectName(name); usageMbean = (UsageMBeanImpl) constructor.newInstance(new Object[] { component.getUsageParametersMBeanConcreteInterface(), notificationSource }); usageMbean.setObjectName(usageParameterMBeanObjectName); usageMbean.setParent(this); sleeContainer.getMBeanServer().registerMBean(usageMbean, usageParameterMBeanObjectName); // set the usage param data related with the mbean installedUsageParameterSet.setName(name); installedUsageParameterSet.setUsageMBean(usageMbean); usageMbean.setUsageParameter(installedUsageParameterSet); // store the mbean if (name != null) { this.usageMBeans.put(name, usageMbean); } else { // default mbean this.defaultUsageMBean = usageMbean; // create notification manager Class<?> usageNotificationManagerMBeanClass = component .getUsageNotificationManagerMBeanImplConcreteClass(); constructor = usageNotificationManagerMBeanClass .getConstructor(new Class[] { Class.class, NotificationSource.class,SleeComponentWithUsageParametersInterface.class}); usageNotificationManagerMBean = (UsageNotificationManagerMBeanImpl) constructor .newInstance(new Object[] { component .getUsageNotificationManagerMBeanConcreteInterface(), notificationSource ,component}); ObjectName usageNotificationManagerMBeanObjectName = generateUsageNotificationManagerMBeanObjectName(); usageNotificationManagerMBean .setObjectName(usageNotificationManagerMBeanObjectName); sleeContainer.getMBeanServer().registerMBean( usageNotificationManagerMBean, usageNotificationManagerMBeanObjectName); this.notificationManager = usageNotificationManagerMBean; } } catch (Throwable e) { if (logger.isDebugEnabled()) { logger.debug("Error creating usage param set named "+name,e); } if (usageMbean != null) { if (name != null) { this.usageMBeans.remove(name); } else { this.defaultUsageMBean = null; } try { sleeContainer.getMBeanServer().unregisterMBean( usageMbean.getObjectName()); } catch (Throwable f) { logger.error("failed to unregister usage parameter mbean " + usageMbean.getObjectName()); } } if (usageNotificationManagerMBean != null) { this.notificationManager = null; try { sleeContainer.getMBeanServer().unregisterMBean( usageNotificationManagerMBean.getObjectName()); } catch (Throwable f) { logger .error("failed to unregister usage notification manager mbean " + usageNotificationManagerMBean .getObjectName()); } } throw new ManagementException(e.getMessage(), e); } finally { currentThread.setContextClassLoader(currentThreadClassLoader); } } /* * verifies a name for an usage mbean */ private boolean isValidUsageParameterName(String str) { for (int i = 0; i < str.length(); i++) { char c = str.charAt(i); if (!(Character.isDigit(c) || Character.isLetter(c) || (c <= '\u007e' && c >= '\u0020'))) { return false; } } return true; } /** * Retrieves the object name for the default usage param mbean * * @return * @throws ManagementException */ public ObjectName getUsageMBean() throws ManagementException { try { return _getUsageMBean(null); } catch (UnrecognizedUsageParameterSetNameException e) { throw new ManagementException( "default usage parameter name not found", e); } } /** * Retrieves the object name for the usage param mbean with the specified * name * * @param paramSetName * @return * @throws NullPointerException * @throws UnrecognizedUsageParameterSetNameException * @throws ManagementException */ public ObjectName getUsageMBean(String paramSetName) throws NullPointerException, UnrecognizedUsageParameterSetNameException, ManagementException { if (paramSetName == null) throw new NullPointerException("Sbb usage param set is null"); return _getUsageMBean(paramSetName); } private synchronized ObjectName _getUsageMBean(String name) throws ManagementException, UnrecognizedUsageParameterSetNameException { ensureMBeanIsNotClosed(); Logger logger = getLogger(); if (logger.isDebugEnabled()) { logger.debug("_getUsageMBean( name = "+name+")"); } UsageMBeanImpl usageMBeanImpl = null; if (name != null) { usageMBeanImpl = usageMBeans.get(name); } else { usageMBeanImpl = defaultUsageMBean; } if (usageMBeanImpl == null) { throw new UnrecognizedUsageParameterSetNameException(name); } else { return usageMBeanImpl.getObjectName(); } } /** * Retrieves the object name of the {@link UsageNotificationManagerMBean} * * @return * @throws ManagementException */ public ObjectName getUsageNotificationManagerMBean() throws ManagementException { ensureMBeanIsNotClosed(); return notificationManager.getObjectName(); } /** * Retrieves the names of the usage params, which exist in this mbean * * @return * @throws ManagementException */ public String[] getUsageParameterSets() throws ManagementException { ensureMBeanIsNotClosed(); return getUsageParameterNamesSet().toArray(new String[0]); } /** * * @return */ public Set<String> getUsageParameterNamesSet() { return usageMBeans.keySet(); } /** * Removes the default usage param (and its mbean) * * @throws ManagementException * @throws UnrecognizedUsageParameterSetNameException */ private void removeUsageParameterSet() throws ManagementException, UnrecognizedUsageParameterSetNameException { _removeUsageParameterSet(null,false); } /** * Removes the usage param (and its mbean) for the specified name * * @param paramSetName * @throws NullPointerException * @throws UnrecognizedUsageParameterSetNameException * @throws ManagementException */ public void removeUsageParameterSet(String paramSetName) throws NullPointerException, UnrecognizedUsageParameterSetNameException, ManagementException { if (paramSetName == null) throw new NullPointerException("usage param set is null"); _removeUsageParameterSet(paramSetName,true); } private synchronized void _removeUsageParameterSet(String name, boolean ensureMBeanIsNotClosed) throws UnrecognizedUsageParameterSetNameException, ManagementException { Logger logger = getLogger(); if (logger.isDebugEnabled()) { logger.debug("_removeUsageParameterSet( name = "+name+")"); } UsageMBeanImpl usageMbean = null; try { if (name != null) { // remove from this mbean map usageMbean = this.usageMBeans.remove(name); } else { usageMbean = defaultUsageMBean; defaultUsageMBean = null; } if (usageMbean == null) { throw new UnrecognizedUsageParameterSetNameException(name); } sleeContainer.getMBeanServer().unregisterMBean( usageMbean.getObjectName()); if (name == null) { removeNotificationManager(); } } catch (Throwable e) { // rollback changes if (usageMbean != null) { if (name != null) { // remove from this mbean map usageMbean = this.usageMBeans.put(name, usageMbean); } else { defaultUsageMBean = usageMbean; } try { sleeContainer.getMBeanServer().registerMBean(usageMbean, usageMbean.getObjectName()); } catch (Throwable f) { logger.error("failed to re-register usage parameter mbean " + usageMbean.getObjectName()); } } // note: removal rollback of notification manager is done by the // removeNotificationManager() method throw new ManagementException(e.getMessage(), e); } } /** * Resets all usage params * * @throws ManagementException */ public void resetAllUsageParameters() throws ManagementException { ensureMBeanIsNotClosed(); try { for (UsageMBeanImpl usageMBeanImpl : usageMBeans.values()) { usageMBeanImpl.resetAllUsageParameters(); } } catch (Throwable e) { throw new ManagementException(e.getMessage(), e); } } private void removeNotificationManager() throws ManagementException { try { sleeContainer.getMBeanServer().unregisterMBean( notificationManager.getObjectName()); notificationManager = null; } catch (Throwable e) { // rollback changes try { sleeContainer.getMBeanServer().registerMBean( notificationManager, notificationManager.getObjectName()); } catch (Throwable f) { getLogger().error( "failed to re-register usage parameter mbean " + notificationManager.getObjectName()); } throw new ManagementException(e.getMessage(), e); } } /** * Generates the usage mbean object name for the specified usage param name * * @param name * @return * @throws MalformedObjectNameException * @throws NullPointerException */ protected abstract ObjectName generateUsageParametersMBeanObjectName( String name) throws MalformedObjectNameException, NullPointerException; /** * Generates the usage mbean object name for the default usage param * * @return * @throws MalformedObjectNameException * @throws NullPointerException */ protected abstract ObjectName generateUsageNotificationManagerMBeanObjectName() throws MalformedObjectNameException, NullPointerException; /** * Retrieves the usage notification manager mbean */ public UsageNotificationManagerMBeanImpl getUsageNotificationManagerMBean( NotificationSource notificationSource) { return notificationManager; } /** * Convenience method to retrieve the default * {@link InstalledUsageParameterSet} * * @return */ public InstalledUsageParameterSet getDefaultInstalledUsageParameterSet() { if (defaultUsageMBean != null) { return defaultUsageMBean.getUsageParameter(); } else { return null; } } /** * Convenience method to retrieve the {@link InstalledUsageParameterSet} for * the specified param set name. * * @param name * @return */ public InstalledUsageParameterSet getInstalledUsageParameterSet(String name) { if (name == null) { return getDefaultInstalledUsageParameterSet(); } else { UsageMBeanImpl usageMBean = usageMBeans.get(name); if (usageMBean == null) { return null; } else { return usageMBean.getUsageParameter(); } } } /* * To be defined by concrete mbean, for a proper logging (non-Javadoc) * * @see java.lang.Object#toString() */ public abstract String toString(); }