/*************************************************** * * * Mobicents: The Open Source VoIP Platform * * * * Distributable under LGPL license. * * See terms of license at gnu.org. * * * ***************************************************/ package org.mobicents.slee.container.management.jmx; import java.util.Map; import java.util.StringTokenizer; import java.util.concurrent.ConcurrentHashMap; import javax.management.MBeanNotificationInfo; import javax.management.NotCompliantMBeanException; import javax.slee.ComponentID; import javax.slee.InvalidArgumentException; import javax.slee.UnrecognizedComponentException; import javax.slee.facilities.Level; import javax.slee.facilities.TraceLevel; import javax.slee.facilities.Tracer; import javax.slee.management.ManagementException; import javax.slee.management.NotificationSource; import javax.slee.management.TraceMBean; import javax.slee.management.UnrecognizedNotificationSourceException; import javax.transaction.SystemException; import org.apache.log4j.Logger; import org.mobicents.slee.runtime.facilities.TraceFacilityImpl; import org.mobicents.slee.runtime.facilities.TracerImpl; import org.mobicents.slee.runtime.facilities.TracerStorage; import org.mobicents.slee.runtime.transaction.SleeTransactionManager; import org.mobicents.slee.runtime.transaction.TransactionalAction; /** * Implementation of the Trace MBean. * * @author M. Ranganathan * @author baranowb * @author martins */ @SuppressWarnings("deprecation") public class TraceMBeanImpl extends MobicentsServiceMBeanSupport implements TraceMBeanImplMBean { private static final Logger logger = Logger.getLogger(TraceMBeanImpl.class); private final TraceFacilityImpl traceFacility; private final SleeTransactionManager sleeTransactionManager; /** * Creates the trace mbean. * * @throws NotCompliantMBeanException */ public TraceMBeanImpl(SleeTransactionManager sleeTransactionManager) throws NotCompliantMBeanException { super(TraceMBeanImplMBean.class); this.traceFacility = new TraceFacilityImpl(this); this.sleeTransactionManager = sleeTransactionManager; } /** * * @return the traceFacility */ public TraceFacilityImpl getTraceFacility() { return traceFacility; } @Override public String toString() { return "Trace MBean Impl : " + "\n+-- Tracers: " + tracerStorage.toString(); } /* * (non-Javadoc) * * @see * javax.slee.management.TraceMBean#setTraceLevel(javax.slee.ComponentID, * javax.slee.facilities.Level) */ public void setTraceLevel(ComponentID componentId, Level level) throws NullPointerException, UnrecognizedComponentException, ManagementException { if (componentId == null) throw new NullPointerException("null component Id"); this.traceFacility.checkComponentID(componentId); this.traceFacility.setTraceLevel(componentId, level); } /* * (non-Javadoc) * * @see * javax.slee.management.TraceMBean#getTraceLevel(javax.slee.ComponentID) */ public Level getTraceLevel(ComponentID componentId) throws NullPointerException, UnrecognizedComponentException, ManagementException { if (componentId == null) throw new NullPointerException(" null component Id "); Level level = this.traceFacility.getTraceLevel(componentId); return level; } /* * (non-Javadoc) * * @see javax.management.NotificationBroadcaster#getNotificationInfo() */ public MBeanNotificationInfo[] getNotificationInfo() { if (this.traceFacility == null) return null; String[] notificationTypes = this.traceFacility.getNotificationTypes(); MBeanNotificationInfo[] mbeanNotificationInfo = new MBeanNotificationInfo[] { new MBeanNotificationInfo(notificationTypes, TraceMBean.TRACE_NOTIFICATION_TYPE, "SLEE Spec 1.0, #13.4. SBBs use the Trace Facility to generate trace messages intended for " + "consumption by external management clients, such as a network management console or a management policy engine.") }; return mbeanNotificationInfo; } /** * the JNDI name where this facility is be bound under the facilities * context. The name is fixed by the SLEE 1.0 spec, section 13.8 */ public static final String JNDI_NAME = "trace"; public TraceLevel getTraceLevel(NotificationSource src, String tracerName) throws NullPointerException, InvalidArgumentException, UnrecognizedNotificationSourceException, ManagementException { if(src == null) { throw new NullPointerException("NotificationSource must not be null!"); } if(!this.isNotificationSourceDefined(src)) { throw new UnrecognizedNotificationSourceException("Notification source not recognized: "+src); } TracerImpl.checkTracerName(tracerName, src); if(!this.isTracerDefined(src,tracerName)) { //FIXME: what is valid tracer name? JDOC contradicts that not existing tracer name is invalid this.createTracer(src,tracerName,false); } TracerStorage ts = this.tracerStorage.get(src); if (ts == null) { throw new ManagementException("NotificationSource has been uninstalled from SLEE. Can not create tracer."); } try { return ts.getTracerLevel(tracerName); } catch (Exception e) { throw new ManagementException("Failed to get trace level due to: ", e); } } public String[] getTracersSet(NotificationSource src) throws NullPointerException, UnrecognizedNotificationSourceException, ManagementException { if(src == null) { throw new NullPointerException("NotificationSource must nto be null!"); } if(!this.isNotificationSourceDefined(src)) { throw new UnrecognizedNotificationSourceException("Notification source not recognized: "+src); } TracerStorage ts = this.tracerStorage.get(src); if (ts == null) { throw new ManagementException("NotificationSource has been uninstalled from SLEE. Can not create tracer."); } return ts.getDefinedTracerNames(); } public String[] getTracersUsed(NotificationSource src) throws NullPointerException, UnrecognizedNotificationSourceException, ManagementException { if(src == null) { throw new NullPointerException("NotificationSource must nto be null!"); } if(!this.isNotificationSourceDefined(src)) { throw new UnrecognizedNotificationSourceException("Notification source not recognized: "+src); } TracerStorage ts = this.tracerStorage.get(src); if (ts == null) { throw new ManagementException("NotificationSource has been uninstalled from SLEE. Can not create tracer."); } return ts.getRequestedTracerNames(); } public void setTraceLevel(NotificationSource src, final String tracerName, TraceLevel lvl) throws NullPointerException, UnrecognizedNotificationSourceException, InvalidArgumentException, ManagementException { if(src == null) { throw new NullPointerException("NotificationSource must nto be null!"); } if(lvl == null) { throw new NullPointerException("TraceLevel must not be null!"); } if (!this.isNotificationSourceDefined(src)) { throw new UnrecognizedNotificationSourceException("Notification source not recognized: "+src); } TracerImpl.checkTracerName(tracerName, src); if(!this.isTracerDefined(src,tracerName)) { //FIXME: what is valid tracer name? JDOC contradicts that not existing tracer name is invalid this.createTracer(src,tracerName,false); } final TracerStorage ts = this.tracerStorage.get(src); if (ts == null) { throw new ManagementException("NotificationSource has been uninstalled from SLEE. Can not create tracer."); } try { try { if(sleeTransactionManager.getTransaction()!=null) { final TraceLevel _oldLevel=ts.getTracerLevel(tracerName); TransactionalAction action = new TransactionalAction() { TraceLevel oldLevel = _oldLevel; public void execute() { try { ts.setTracerLevel(oldLevel, tracerName); } catch (InvalidArgumentException e) { logger.error(e.getMessage(),e); } } }; sleeTransactionManager.addAfterRollbackAction(action); } } catch (SystemException e) { e.printStackTrace(); } ts.setTracerLevel(lvl, tracerName); } catch (Exception e) { throw new ManagementException("Failed to set trace level due to: ", e); } } public void unsetTraceLevel(NotificationSource src, final String tracerName) throws NullPointerException, UnrecognizedNotificationSourceException, InvalidArgumentException, ManagementException { if(src == null) { throw new NullPointerException("NotificationSource must nto be null!"); } if(!this.isNotificationSourceDefined(src)) { throw new UnrecognizedNotificationSourceException("Notification source not recognized: "+src); } TracerImpl.checkTracerName(tracerName, src); if(!this.isTracerDefined(src,tracerName)) { //FIXME: what is valid tracer name? JDOC contradicts that not existing tracer name is invalid this.createTracer(src,tracerName,false); } final TracerStorage ts = this.tracerStorage.get(src); if (ts == null) { throw new ManagementException("NotificationSource has been uninstalled from SLEE. Can not create tracer."); } try { try { if(sleeTransactionManager.getTransaction()!=null) { final TraceLevel _oldLevel=ts.getTracerLevel(tracerName); TransactionalAction action = new TransactionalAction() { TraceLevel oldLevel = _oldLevel; public void execute() { try { ts.setTracerLevel(oldLevel, tracerName); } catch (InvalidArgumentException e) { logger.error(e.getMessage(),e); } } }; sleeTransactionManager.addAfterRollbackAction(action); } } catch (SystemException e) { e.printStackTrace(); } ts.unsetTracerLevel(tracerName); } catch (Exception e) { throw new ManagementException("Failed to unset trace level due to: ", e); } } //Non MBEAN methods // 1.1 TracerImpl are. We define internal private class to hide details :) private Map<NotificationSource, TracerStorage> tracerStorage = new ConcurrentHashMap<NotificationSource, TracerStorage>(); /** * This checks if tracer name is ok. It must not be null; * * @param split * @throws IllegalArgumentException */ public static void checkTracerName(String tracerName, NotificationSource notificationSource) throws IllegalArgumentException { if (tracerName.compareTo("") == 0) { // This is root return; } // String[] splitName = tracerName.split("\\."); StringTokenizer stringTokenizer = new StringTokenizer(tracerName, ".", true); int fqdnPartIndex = 0; // if(splitName.length==0) // { // throw new IllegalArgumentException("Passed tracer:" + tracerName + // ", name for source: " + notificationSource + ", is illegal"); // } String lastToken = null; while (stringTokenizer.hasMoreTokens()) { String token = stringTokenizer.nextToken(); if (lastToken == null) { // this is start lastToken = token; } if (lastToken.compareTo(token) == 0 && token.compareTo(".") == 0) { throw new IllegalArgumentException("Passed tracer:" + tracerName + ", name for source: " + notificationSource + ", is illegal"); } if (token.compareTo(".") != 0) { for (int charIndex = 0; charIndex < token.length(); charIndex++) { Character c = token.charAt(charIndex); if (Character.isLetter(c) || Character.isDigit(c)) { // Its ok? } else { throw new IllegalArgumentException("Passed tracer:" + tracerName + " Token[" + token + "], name for source: " + notificationSource + ", is illegal, contains illegal character: " + charIndex); } } fqdnPartIndex++; } lastToken = token; } if (lastToken.compareTo(".") == 0) { throw new IllegalArgumentException("Passed tracer:" + tracerName + ", name for source: " + notificationSource + ", is illegal"); } } public void registerNotificationSource(final NotificationSource src) { if (!this.tracerStorage.containsKey(src)) { TracerStorage ts = new TracerStorage(src, this); this.tracerStorage.put(src, ts); } } /** * This method shoudl be called on on removal of notification source from * slee * * @param src */ public void deregisterNotificationSource(final NotificationSource src) { this.tracerStorage.remove(src); } public boolean isNotificationSourceDefined(NotificationSource src) { return this.tracerStorage.containsKey(src); } public boolean isTracerDefined(NotificationSource src, String tracerName) throws ManagementException { TracerStorage ts = this.tracerStorage.get(src); if (ts == null) { throw new ManagementException("NotificationSource has been uninstalled from SLEE. Can not create tracer."); } return ts.isTracerDefined(tracerName); } /** * This method creates tracer for specified source, with specified name. * boolean flag indicates that tracer has been requested by src, else, its * just management operation. This method can me invoked multiple times. * Only difference is boolean flag. * * @param src * - notification source * @param tracerName * - tracer name * @param createdBySource * - flag indicating that src requested this tracer. In case * tracer already exists (created by mgmt operation) and this * method is invoked from NotificationSource this flag is set to * true. This alters state of tracer. It can not be changed back * @return Tracer object. Either newly created or one that previously * existed. * */ public Tracer createTracer(NotificationSource src, String tracerName, boolean createdBySource) throws ManagementException { TracerStorage ts = this.tracerStorage.get(src); if (ts == null) { throw new ManagementException("NotificationSource has been uninstalled from SLEE. Can not create tracer."); } try { return ts.createTracer(tracerName, createdBySource); } catch (Throwable e) { throw new ManagementException("",e); } } }