/*************************************************** * * * Mobicents: The Open Source JSLEE Platform * * * * Distributable under LGPL license. * * See terms of license at gnu.org. * * * *************************************************** * * Created on Nov 18, 2004 * * AlarmMBeanImpl.java * */ package org.mobicents.slee.container.management.jmx; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.atomic.AtomicLong; import javax.management.MBeanNotificationInfo; import javax.management.NotCompliantMBeanException; import javax.slee.ComponentID; import javax.slee.SbbID; import javax.slee.UnrecognizedComponentException; import javax.slee.facilities.AlarmLevel; import javax.slee.facilities.Level; import javax.slee.management.Alarm; import javax.slee.management.AlarmNotification; import javax.slee.management.ManagementException; import javax.slee.management.NotificationSource; import javax.slee.management.UnrecognizedNotificationSourceException; import javax.transaction.SystemException; import org.apache.log4j.Logger; import org.mobicents.slee.runtime.facilities.MNotificationSource; import org.mobicents.slee.runtime.transaction.SleeTransactionManager; import org.mobicents.slee.runtime.transaction.TransactionalAction; /** * Implementation of the Alarm MBean: The implementation of the JMX interface to * the SLEE alarm facility * * @author baranowb * @author Tim * */ @SuppressWarnings("deprecation") public class AlarmMBeanImpl extends MobicentsServiceMBeanSupport implements AlarmMBeanImplMBean { public static String JNDI_NAME = "alarm"; private static Logger log = Logger.getLogger(AlarmMBeanImpl.class); private Map<AlarmPlaceHolder, NotificationSource> placeHolderToNotificationSource = new HashMap<AlarmPlaceHolder, NotificationSource>(); private Map<String, AlarmPlaceHolder> alarmIdToAlarm = new HashMap<String, AlarmPlaceHolder>(); private final SleeTransactionManager sleeTransactionManager; private final TraceMBeanImpl traceMBean; /** * @param sleeTransactionManager * @param traceMBean */ public AlarmMBeanImpl(SleeTransactionManager sleeTransactionManager, TraceMBeanImpl traceMBean) throws NotCompliantMBeanException { super(AlarmMBeanImplMBean.class); this.sleeTransactionManager = sleeTransactionManager; this.traceMBean = traceMBean; } public boolean clearAlarm(String alarmID) throws NullPointerException, ManagementException { if (alarmID == null) { throw new NullPointerException("AlarmID must not be null"); } AlarmPlaceHolder aph = alarmIdToAlarm.remove(alarmID); placeHolderToNotificationSource.remove(aph); if (aph == null) { return false; } else { // we clear? try { generateNotification(aph, true); } catch (Exception e) { throw new ManagementException("Failed to clear alarm due to: " + e); } return true; } } public int clearAlarms(NotificationSource notificationSource) throws NullPointerException, UnrecognizedNotificationSourceException, ManagementException { if (notificationSource == null) { throw new NullPointerException("NotificationSource must not be null"); } mandateSource(notificationSource); int count = 0; try { Map<AlarmPlaceHolder, NotificationSource> copy = new HashMap<AlarmPlaceHolder, NotificationSource>(); copy.putAll(this.placeHolderToNotificationSource); for (Map.Entry<AlarmPlaceHolder, NotificationSource> e : copy.entrySet()) { if (e.getValue().equals(notificationSource)) { if (clearAlarm(e.getKey().getAlarm().getAlarmID())) { count++; } } } } catch (Exception e) { throw new ManagementException("Failed to get alarm id list due to: ", e); } return count; } public int clearAlarms(NotificationSource notificationSource, String alarmType) throws NullPointerException, UnrecognizedNotificationSourceException, ManagementException { if (notificationSource == null) { throw new NullPointerException("NotificationSource must not be null"); } if (alarmType == null) { throw new NullPointerException("AlarmType must not be null"); } mandateSource(notificationSource); int count = 0; try { Map<AlarmPlaceHolder, NotificationSource> copy = new HashMap<AlarmPlaceHolder, NotificationSource>(); copy.putAll(this.placeHolderToNotificationSource); for (Map.Entry<AlarmPlaceHolder, NotificationSource> e : copy.entrySet()) { if (e.getValue().equals(notificationSource) && e.getKey().getAlarmType().compareTo(alarmType) == 0) { if (clearAlarm(e.getKey().getAlarm().getAlarmID())) { count++; } } } } catch (Exception e) { throw new ManagementException("Failed to get alarm id list due to: ", e); } return count; } public String[] getAlarms() throws ManagementException { try { Set<String> ids = alarmIdToAlarm.keySet(); return ids.toArray(new String[ids.size()]); } catch (Exception e) { throw new ManagementException("Failed to get list of active alarms due to.", e); } } public String[] getAlarms(NotificationSource notificationSource) throws NullPointerException, UnrecognizedNotificationSourceException, ManagementException { if (notificationSource == null) { throw new NullPointerException("NotificationSource must not be null"); } mandateSource(notificationSource); try { List<String> ids = new ArrayList<String>(); Map<AlarmPlaceHolder, NotificationSource> copy = new HashMap<AlarmPlaceHolder, NotificationSource>(); copy.putAll(this.placeHolderToNotificationSource); for (Map.Entry<AlarmPlaceHolder, NotificationSource> e : copy.entrySet()) { if (e.getValue().equals(notificationSource)) { ids.add(e.getKey().getAlarm().getAlarmID()); } } return ids.toArray(new String[ids.size()]); } catch (Exception e) { throw new ManagementException("Failed to get alarm id list due to: ", e); } } public Alarm getDescriptor(String alarmID) throws NullPointerException, ManagementException { if (alarmID == null) { throw new NullPointerException("AlarmID must not be null"); } AlarmPlaceHolder aph = this.alarmIdToAlarm.get(alarmID); if (aph == null) return null; return aph.getAlarm(); } public Alarm[] getDescriptors(String[] alarmIDs) throws NullPointerException, ManagementException { if (alarmIDs == null) { throw new NullPointerException("AlarmID[] must not be null"); } List<Alarm> alarms = new ArrayList<Alarm>(); try { for (String id : alarmIDs) { Alarm a = getDescriptor(id); if (a != null) alarms.add(a); } return alarms.toArray(new Alarm[alarms.size()]); } catch (Exception e) { throw new ManagementException("Failed to get desciptors.", e); } } public boolean isActive(String alarmID) throws NullPointerException, ManagementException { return this.alarmIdToAlarm.containsKey(alarmID); } // NON MBEAN - used only internal, those methods are not exposed via jmx public boolean isSourceOwnerOfAlarm(MNotificationSource notificationSource, String alarmID) { AlarmPlaceHolder aph = this.alarmIdToAlarm.get(alarmID); if (aph == null) return false; return aph.getNotificationSource().getNotificationSource().equals(notificationSource.getNotificationSource()); } public boolean isAlarmAlive(String alarmID) { return this.alarmIdToAlarm.containsKey(alarmID); } public boolean isAlarmAlive(MNotificationSource notificationSource, String alarmType, String instanceID) { AlarmPlaceHolder aph = new AlarmPlaceHolder(notificationSource, alarmType, instanceID); // return this.placeHolderToAlarm.containsKey(aph); return this.alarmIdToAlarm.containsValue(aph); } public String getAlarmId(MNotificationSource notificationSource, String alarmType, String instanceID) { AlarmPlaceHolder localAPH = new AlarmPlaceHolder(notificationSource, alarmType, instanceID); Alarm a = null; for (Map.Entry<String, AlarmPlaceHolder> e : this.alarmIdToAlarm.entrySet()) { if (e.getValue().equals(localAPH)) { a = e.getValue().getAlarm(); break; } } if (a != null) return a.getAlarmID(); else return null; } /** * THis methods raises alarm. It MUST not receive AlarmLevel.CLEAR, it has * to be filtered. * * @param notificationSource * @param alarmType * @param instanceID * @param level * @param message * @param cause * @return - AlarmId */ public String raiseAlarm(MNotificationSource notificationSource, String alarmType, String instanceID, AlarmLevel level, String message, Throwable cause) { synchronized (notificationSource) { if (isAlarmAlive(notificationSource, alarmType, instanceID)) { // Alarm a = this.placeHolderToAlarm.get(new // AlarmPlaceHolder(notificationSource, alarmType, instanceID)); Alarm a = null; // unconveniant.... try { AlarmPlaceHolder localAPH = new AlarmPlaceHolder(notificationSource, alarmType, instanceID); for (Map.Entry<String, AlarmPlaceHolder> e : this.alarmIdToAlarm.entrySet()) { if (e.getValue().equals(localAPH)) { a = e.getValue().getAlarm(); break; } } } catch (Exception e) { // ignore } if (a != null) { return a.getAlarmID(); } else { return this.raiseAlarm(notificationSource, alarmType, instanceID, level, message, cause); } } else { Alarm a = new Alarm(UUID.randomUUID().toString(), notificationSource.getNotificationSource(), alarmType, instanceID, level, message, cause, System.currentTimeMillis()); AlarmPlaceHolder aph = new AlarmPlaceHolder(notificationSource, alarmType, instanceID, a); this.alarmIdToAlarm.put(a.getAlarmID(), aph); // this.placeHolderToAlarm.put(aph, a); this.placeHolderToNotificationSource.put(aph, aph.getNotificationSource().getNotificationSource()); generateNotification(aph, false); return a.getAlarmID(); } } } private void generateNotification(AlarmPlaceHolder aph, boolean isCleared) { Alarm alarm = aph.getAlarm(); AlarmLevel generalLevel = isCleared ? AlarmLevel.CLEAR : alarm.getAlarmLevel(); AlarmNotification notification = new AlarmNotification(aph.getNotificationSource().getNotificationSource().getAlarmNotificationType(), this, alarm.getAlarmID(), aph.getNotificationSource() .getNotificationSource(), alarm.getAlarmType(), alarm.getInstanceID(), generalLevel, alarm.getMessage(), alarm.getCause(), aph.getNotificationSource().getNextSequence(), System .currentTimeMillis()); super.sendNotification(notification); } /** * This method is requried - in case component is removed on call to method with its noti source we must throw unknown notification source exception - even thought alarms MAY be present? * @throws UnrecognizedNotificationSourceException */ private void mandateSource(NotificationSource src) throws UnrecognizedNotificationSourceException { if(!traceMBean.isNotificationSourceDefined(src)) { throw new UnrecognizedNotificationSourceException("Notification source is not present: "+src); } } class AlarmPlaceHolder { private MNotificationSource notificationSource; private String alarmType; private String instanceID; private Alarm alarm; public AlarmPlaceHolder(MNotificationSource notificationSource, String alarmType, String instanceID) { super(); this.notificationSource = notificationSource; this.alarmType = alarmType; this.instanceID = instanceID; } public AlarmPlaceHolder(MNotificationSource notificationSource, String alarmType, String instanceID, Alarm a) { this.notificationSource = notificationSource; this.alarmType = alarmType; this.instanceID = instanceID; this.alarm = a; } public MNotificationSource getNotificationSource() { return notificationSource; } public String getAlarmType() { return alarmType; } public String getInstanceID() { return instanceID; } public Alarm getAlarm() { return alarm; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + getOuterType().hashCode(); result = prime * result + ((alarmType == null) ? 0 : alarmType.hashCode()); result = prime * result + ((instanceID == null) ? 0 : instanceID.hashCode()); result = prime * result + ((notificationSource == null) ? 0 : notificationSource.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; AlarmPlaceHolder other = (AlarmPlaceHolder) obj; if (!getOuterType().equals(other.getOuterType())) return false; if (alarmType == null) { if (other.alarmType != null) return false; } else if (!alarmType.equals(other.alarmType)) return false; if (instanceID == null) { if (other.instanceID != null) return false; } else if (!instanceID.equals(other.instanceID)) return false; if (notificationSource == null) { if (other.notificationSource != null) return false; } else if (!notificationSource.equals(other.notificationSource)) return false; return true; } private AlarmMBeanImpl getOuterType() { return AlarmMBeanImpl.this; } } // 1.0 part, required for compatibility. /** * Represents a component registered with the alarm facility. Basically just * stores notification sequence number * * @author Tim */ class RegisteredComp { public AtomicLong seqNo = new AtomicLong(0); public long getSeqNo() { return seqNo.getAndIncrement(); } } private Map<ComponentID, RegisteredComp> registeredComps = new ConcurrentHashMap<ComponentID, RegisteredComp>(); // 1.0 methods public boolean isRegisteredAlarmComponent(ComponentID alarmSource) { // FIXME: in 1.0 we allow only SbbID as componetns return this.registeredComps.containsKey(alarmSource); } public void createAlarm(ComponentID alarmSource, Level alarmLevel, String alarmType, String message, Throwable cause, long timestamp) throws UnrecognizedComponentException { if (log.isDebugEnabled()) { log.debug("alarmSource:" + alarmSource + " alarmLevel:" + alarmLevel + " alarmType:" + alarmType + " message:" + message + " cause:" + cause + " timeStamp:" + timestamp); } if (alarmSource == null || alarmLevel == null || alarmType == null || message == null) throw new NullPointerException("Null parameter"); if (alarmLevel.isOff()) throw new IllegalArgumentException("Invalid alarm level"); RegisteredComp comp = registeredComps.get(alarmSource); if (comp == null) throw new UnrecognizedComponentException("Component not registered"); // TODO I'm not sure if we should log the alarm too // Add the notication type if not already in set. See note in // declaration about why we are using a map, not a set // if (!this.notificationTypes.containsKey(alarmType)) // this.notificationTypes.put(alarmType, alarmType); // Create the alarm notification and propagate to the Alarm MBean AlarmNotification notification = new AlarmNotification(this, alarmType, alarmSource, alarmLevel, message, cause, comp.getSeqNo(), timestamp); super.sendNotification(notification); } public void registerComponent(final SbbID sbbID) throws SystemException { if (log.isDebugEnabled()) { log.debug("Registering component with alarm facility: " + sbbID); } registeredComps.put(sbbID, new RegisteredComp()); TransactionalAction action = new TransactionalAction() { public void execute() { registeredComps.remove(sbbID); } }; sleeTransactionManager.addAfterRollbackAction(action); } public void unRegisterComponent(final SbbID sbbID) throws SystemException { final RegisteredComp registeredComp = this.registeredComps.remove(sbbID); if (registeredComp != null) { TransactionalAction action = new TransactionalAction() { public void execute() { registeredComps.put(sbbID, registeredComp); } }; sleeTransactionManager.addAfterRollbackAction(action); } } // NOTIFICATION PART /* * (non-Javadoc) * * @see javax.management.NotificationBroadcaster#getNotificationInfo() */ public MBeanNotificationInfo[] getNotificationInfo() { return null; } }