/**
   * Handles adding a new Notification.
   *
   * @param notice The Notification to add.
   * @throws org.exolab.castor.xml.MarshalException if any.
   * @throws org.exolab.castor.xml.ValidationException if any.
   * @throws java.io.IOException if any.
   * @throws java.lang.ClassNotFoundException if any.
   */
  public synchronized void addNotification(final Notification notice)
      throws MarshalException, ValidationException, IOException, ClassNotFoundException {
    // remove any existing notice with the same name
    m_notifications.removeNotification(getNotification(notice.getName()));

    m_notifications.addNotification(notice);
    saveCurrent();
  }
  /**
   * getNotificationNames
   *
   * @return a {@link java.util.List} object.
   * @throws java.io.IOException if any.
   * @throws org.exolab.castor.xml.MarshalException if any.
   * @throws org.exolab.castor.xml.ValidationException if any.
   */
  public List<String> getNotificationNames()
      throws IOException, MarshalException, ValidationException {
    update();

    List<String> notificationNames = new ArrayList<String>();

    for (Notification curNotif : m_notifications.getNotificationCollection()) {
      notificationNames.add(curNotif.getName());
    }

    return notificationNames;
  }
  /**
   * getNotifications
   *
   * @return a {@link java.util.Map} object.
   * @throws java.io.IOException if any.
   * @throws org.exolab.castor.xml.MarshalException if any.
   * @throws org.exolab.castor.xml.ValidationException if any.
   */
  public Map<String, Notification> getNotifications()
      throws IOException, MarshalException, ValidationException {
    update();

    Map<String, Notification> newMap = new HashMap<String, Notification>();

    Notification notices[] = m_notifications.getNotification();
    for (int i = 0; i < notices.length; i++) {
      newMap.put(notices[i].getName(), notices[i]);
    }

    return Collections.unmodifiableMap(newMap);
  }
  /**
   * saveCurrent
   *
   * @throws org.exolab.castor.xml.MarshalException if any.
   * @throws org.exolab.castor.xml.ValidationException if any.
   * @throws java.io.IOException if any.
   * @throws java.lang.ClassNotFoundException if any.
   */
  public synchronized void saveCurrent()
      throws MarshalException, ValidationException, IOException, ClassNotFoundException {
    m_notifications.setHeader(rebuildHeader());

    // Marshal to a string first, then write the string to the file. This
    // way the original configuration
    // isn't lost if the XML from the marshal is hosed.
    StringWriter stringWriter = new StringWriter();
    Marshaller.marshal(m_notifications, stringWriter);
    String xmlString = stringWriter.toString();
    saveXML(xmlString);

    update();
  }
  /**
   * hasUei
   *
   * @param uei a {@link java.lang.String} object.
   * @return a boolean.
   * @throws java.io.IOException if any.
   * @throws org.exolab.castor.xml.MarshalException if any.
   * @throws org.exolab.castor.xml.ValidationException if any.
   */
  public boolean hasUei(final String uei)
      throws IOException, MarshalException, ValidationException {
    update();

    for (Notification notif : m_notifications.getNotificationCollection()) {
      if (uei.equals(notif.getUei()) || "MATCH-ANY-UEI".equals(notif.getUei())) {
        return true;
      } else if (notif.getUei().charAt(0) == '~') {
        if (uei.matches(notif.getUei().substring(1))) {
          return true;
        }
      }
    }

    return false;
  }
  /**
   * getNotifForEvent
   *
   * @param event a {@link org.opennms.netmgt.xml.event.Event} object.
   * @return an array of {@link org.opennms.netmgt.config.notifications.Notification} objects.
   * @throws java.io.IOException if any.
   * @throws org.exolab.castor.xml.MarshalException if any.
   * @throws org.exolab.castor.xml.ValidationException if any.
   */
  public Notification[] getNotifForEvent(final Event event)
      throws IOException, MarshalException, ValidationException {
    update();
    List<Notification> notifList = new ArrayList<Notification>();
    boolean matchAll = getConfigManager().getNotificationMatch();
    ThreadCategory log = this.log();

    // This if statement will check to see if notification should be suppressed for this event.

    if (event == null) {
      log.warn("unable to get notification for null event!");
      return null;
    } else if (event.getLogmsg() != null && !(event.getLogmsg().getNotify())) {
      if (log.isDebugEnabled())
        log.debug("Event " + event.getUei() + " is configured to suppress notifications.");
      return null;
    }

    for (Notification curNotif : m_notifications.getNotificationCollection()) {
      if (log.isDebugEnabled())
        log.debug("Checking " + event.getUei() + " against " + curNotif.getUei());

      if (event.getUei().equals(curNotif.getUei()) || "MATCH-ANY-UEI".equals(curNotif.getUei())) {
        // Match!
      } else if (curNotif.getUei().charAt(0) == '~') {
        if (event.getUei().matches(curNotif.getUei().substring(1))) {
          // Match!
        } else {
          if (log.isDebugEnabled())
            log.debug(
                "Notification regex "
                    + curNotif.getUei()
                    + " failed to match event UEI: "
                    + event.getUei());
          continue;
        }
      } else {
        if (log.isDebugEnabled())
          log.debug("Event UEI " + event.getUei() + " did not match " + curNotif.getUei());
        continue;
      }

      /** Check if event severity matches pattern in notification */
      if (log.isDebugEnabled())
        log.debug(
            "Checking event severity: "
                + event.getSeverity()
                + " against notification severity: "
                + curNotif.getEventSeverity());
      // parameter is optional, return true if not set
      if (curNotif.getEventSeverity() == null) {
        // Skip matching on severity
      } else if (event
          .getSeverity()
          .toLowerCase()
          .matches(curNotif.getEventSeverity().toLowerCase())) {
        // Severities match
      } else {
        if (log.isDebugEnabled())
          log.debug(
              "Event severity: "
                  + event.getSeverity()
                  + " did not match notification severity: "
                  + curNotif.getEventSeverity());
        continue;
      }

      // The notice has to be "on"
      // The notice has to match a severity if configured - currHasSeverity should be true if there
      // is no severity rule
      // The notice has to match the UEI of the event or MATCH-ANY-UEI
      // If all those things are true:
      // Then the service has to match if configured, the interface if configured, and the node if
      // configured.

      if (curNotif.getStatus().equals("on")) {
        if (nodeInterfaceServiceValid(curNotif, event)) {
          boolean parmsmatched = getConfigManager().matchNotificationParameters(event, curNotif);

          if (!parmsmatched) {
            if (log.isDebugEnabled())
              log.debug(
                  "Event "
                      + event.getUei()
                      + " did not match parameters for notice "
                      + curNotif.getName());
            continue;
          }
          // Add this notification to the return value
          notifList.add(curNotif);

          if (log.isDebugEnabled())
            log.debug("Event " + event.getUei() + " matched notice " + curNotif.getName());

          if (!matchAll) break;
        } else {
          if (log.isDebugEnabled())
            log.debug("Node/interface/service combination in the event was invalid");
        }
      } else {
        if (log.isDebugEnabled()) log.debug("Current notification is turned off.");
      }
    }

    if (!notifList.isEmpty()) {
      return notifList.toArray(new Notification[0]);
    } else {
      return null;
    }
  }
 /**
  * parseXML
  *
  * @param stream a {@link java.io.InputStream} object.
  * @throws org.exolab.castor.xml.MarshalException if any.
  * @throws org.exolab.castor.xml.ValidationException if any.
  */
 public synchronized void parseXML(final InputStream stream)
     throws MarshalException, ValidationException {
   m_notifications = CastorUtils.unmarshal(Notifications.class, stream, true);
   oldHeader = m_notifications.getHeader();
 }
 /**
  * parseXML
  *
  * @param reader a {@link java.io.Reader} object.
  * @throws org.exolab.castor.xml.MarshalException if any.
  * @throws org.exolab.castor.xml.ValidationException if any.
  */
 @Deprecated
 public synchronized void parseXML(final Reader reader)
     throws MarshalException, ValidationException {
   m_notifications = CastorUtils.unmarshal(Notifications.class, reader, true);
   oldHeader = m_notifications.getHeader();
 }
 /**
  * removeNotification
  *
  * @param name a {@link java.lang.String} object.
  * @throws org.exolab.castor.xml.MarshalException if any.
  * @throws org.exolab.castor.xml.ValidationException if any.
  * @throws java.io.IOException if any.
  * @throws java.lang.ClassNotFoundException if any.
  */
 public synchronized void removeNotification(final String name)
     throws MarshalException, ValidationException, IOException, ClassNotFoundException {
   m_notifications.removeNotification(getNotification(name));
   saveCurrent();
 }