private boolean isRuleMatchingFilter(final Notification notif, final String rule) {
   try {
     return FilterDaoFactory.getInstance().isRuleMatching(rule);
   } catch (FilterParseException e) {
     LOG.error("Invalid filter rule for notification {}: {}", notif.getName(), notif.getRule(), e);
     throw e;
   }
 }
  /**
   * Sets the status on an individual notification configuration and saves to xml.
   *
   * @param name The name of the notification.
   * @param status The status (either "on" or "off").
   * @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 updateStatus(final String name, final String status)
      throws MarshalException, ValidationException, IOException, ClassNotFoundException {
    if ("on".equals(status) || "off".equals(status)) {
      Notification notice = getNotification(name);
      notice.setStatus(status);

      saveCurrent();
    } else throw new IllegalArgumentException("Status must be on|off, not " + status);
  }
  /**
   * 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;
  }
  /**
   * 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;
  }
  /**
   * Adds additional parameters defined by the user in the notificaiton configuration XML.
   *
   * @param paramMap a {@link java.util.Map} object.
   * @param notification a {@link org.opennms.netmgt.config.notifications.Notification} object.
   */
  public static void addNotificationParams(
      final Map<String, String> paramMap, final Notification notification) {
    Collection<Parameter> parameters = notification.getParameterCollection();

    for (Parameter parameter : parameters) {
      paramMap.put(parameter.getName(), parameter.getValue());
    }
  }
  /**
   * 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();
  }
  /**
   * nodeInterfaceServiceValid
   *
   * @param notif a {@link org.opennms.netmgt.config.notifications.Notification} object.
   * @param event a {@link org.opennms.netmgt.xml.event.Event} object.
   * @return a boolean.
   */
  protected boolean nodeInterfaceServiceValid(final Notification notif, final Event event) {
    Assert.notNull(notif, "notif argument must not be null");
    Assert.notNull(event, "event argument must not be null");
    Assert.notNull(notif.getRule(), "getRule() on notif argument must not return null");

    /*
     *  If the event doesn't have a nodeId, interface, or service,
     *  return true since there is nothing on which to filter.
     */
    if (event.getNodeid() == 0 && event.getInterface() == null && event.getService() == null) {
      if ("MATCH-ANY-UEI".equals(notif.getUei())) {
        // TODO: Trim parentheses from the filter and trim whitespace from inside the
        // filter statement. This comparison is very brittle as it is.
        if ("ipaddr != '0.0.0.0'".equals(notif.getRule().toLowerCase())
            || "ipaddr iplike *.*.*.*".equals(notif.getRule().toLowerCase())) {
          return true;
        } else {
          return false;
        }
      }
      return true;
    }

    StringBuffer constraints = new StringBuffer();
    if (event.getNodeid() != 0) {
      constraints.append(" & (nodeId == " + event.getNodeid() + ")");
    }

    if (event.getInterface() != null && !"0.0.0.0".equals(event.getInterface())) {
      constraints.append(" & (ipAddr == '" + event.getInterface() + "')");
      if (event.getService() != null) {
        constraints.append(" & (serviceName == '" + event.getService() + "')");
      }
    }

    String rule = "((" + notif.getRule() + ")" + constraints + ")";

    return isRuleMatchingFilter(notif, rule);
  }
  /**
   * Build a commonly used event list where each event's uei is separated by a </br> tag.
   *
   * @param notice the notification that contains the ueis
   * @return a String representation for the UI
   */
  public String buildEventList(Notification notice) {
    if (notice == null) {
      return "";
    }

    StringBuffer buffer = new StringBuffer();
    for (Iterator iter = notice.getEventInfoCollection().iterator(); iter.hasNext(); ) {
      // create temp event object and use get()
      // NOTE: cannot do this until we also fill in the snmp data
      /*org.opennms.netmgt.xml.event.Event e = EventConfigurationManager.makeEvent(
      		(org.opennms.netmgt.config.notifications.EventInfo)iter.next());
      List events = EventConfigurationManager.get(e);
      */
      List events =
          EventConfigurationManager.getByEventInfo(
              (org.opennms.netmgt.config.notifications.EventInfo) iter.next());
      for (Iterator iter2 = events.iterator(); iter2.hasNext(); ) {
        buffer.append(((Event) iter2.next()).getEventLabel()).append("</br>");
      }
    }

    return buffer.toString();
  }
  /**
   * matchNotificationParameters
   *
   * @param event a {@link org.opennms.netmgt.xml.event.Event} object.
   * @param notification a {@link org.opennms.netmgt.config.notifications.Notification} object.
   * @return a boolean.
   */
  public boolean matchNotificationParameters(Event event, Notification notification) {
    ThreadCategory log = ThreadCategory.getInstance(getClass());

    boolean parmmatch = false;
    if (notification.getVarbind() != null && notification.getVarbind().getVbname() != null) {
      String notfValue = null;
      String notfName = notification.getVarbind().getVbname();

      if (notification.getVarbind().getVbvalue() != null) {
        notfValue = notification.getVarbind().getVbvalue();
      } else {
        if (log.isDebugEnabled()) {
          log.debug(
              "BroadcastEventProcessor:matchNotificationParameters:  Null value for varbind, assuming true.");
        }
        parmmatch = true;
      }

      for (final Parm parm : event.getParmCollection()) {
        final String parmName = parm.getParmName();
        final Value parmValue = parm.getValue();
        final String parmContent;
        if (parmValue == null) {
          continue;
        } else {
          parmContent = parmValue.getContent();
        }

        if (parmName.equals(notfName) && parmContent.startsWith(notfValue)) {
          parmmatch = true;
        }
      }
    } else if (notification.getVarbind() == null || notification.getVarbind().getVbname() == null) {
      parmmatch = true;
    }

    return parmmatch;
  }
  /**
   * This method inserts a row into the notifications table in the database. This row indicates that
   * the page has been sent out.
   *
   * @param queueID a {@link java.lang.String} object.
   * @param notification TODO
   * @param notifyId a int.
   * @param params a {@link java.util.Map} object.
   * @throws java.sql.SQLException if any.
   */
  public void insertNotice(
      final int notifyId,
      final Map<String, String> params,
      final String queueID,
      final Notification notification)
      throws SQLException {
    Connection connection = null;
    final DBUtils d = new DBUtils(getClass());
    try {
      connection = getConnection();
      d.watch(connection);
      final PreparedStatement statement =
          connection.prepareStatement(
              "INSERT INTO notifications ("
                  + "textmsg, numericmsg, notifyid, pagetime, nodeid, interfaceid, serviceid, eventid, "
                  + "eventuei, subject, queueID, notifConfigName) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
      d.watch(statement);

      // notifications textMsg field
      statement.setString(1, params.get(NotificationManager.PARAM_TEXT_MSG));

      // notifications numericMsg field
      String numMsg = params.get(NotificationManager.PARAM_NUM_MSG);
      if (numMsg != null && numMsg.length() > 256) {
        log().warn("numericmsg too long, it will be truncated");
        numMsg = numMsg.substring(0, 256);
      }
      statement.setString(2, numMsg);

      // notifications notifyID field
      statement.setInt(3, notifyId);

      // notifications pageTime field
      statement.setTimestamp(4, new Timestamp((new Date()).getTime()));

      // notifications nodeID field
      String node = params.get(NotificationManager.PARAM_NODE);
      if (node != null
          && !node.trim().equals("")
          && !node.equalsIgnoreCase("null")
          && !node.equalsIgnoreCase("%nodeid%")) {
        statement.setInt(5, Integer.parseInt(node));
      } else {
        statement.setNull(5, Types.INTEGER);
      }

      // notifications interfaceID field
      String ipaddr = params.get(NotificationManager.PARAM_INTERFACE);
      if (ipaddr != null
          && !ipaddr.trim().equals("")
          && !ipaddr.equalsIgnoreCase("null")
          && !ipaddr.equalsIgnoreCase("%interface%")) {
        statement.setString(6, ipaddr);
      } else {
        statement.setString(6, null);
      }

      // notifications serviceID field
      String service = params.get(NotificationManager.PARAM_SERVICE);
      if (service != null
          && !service.trim().equals("")
          && !service.equalsIgnoreCase("null")
          && !service.equalsIgnoreCase("%service%")) {
        statement.setInt(7, getServiceId(service));
      } else {
        statement.setNull(7, Types.INTEGER);
      }

      // eventID field
      final String eventID = params.get("eventID");
      if (eventID != null
          && !eventID.trim().equals("")
          && !eventID.trim().equals("0")
          && !eventID.equalsIgnoreCase("null")
          && !eventID.equalsIgnoreCase("%eventid%")) {
        statement.setInt(8, Integer.parseInt(eventID));
      } else {
        statement.setNull(8, Types.INTEGER);
      }

      statement.setString(9, params.get("eventUEI"));

      // notifications subject field
      statement.setString(10, params.get(NotificationManager.PARAM_SUBJECT));

      // the queue this will be sent on
      statement.setString(11, queueID);

      statement.setString(12, notification.getName());

      statement.executeUpdate();
    } finally {
      d.cleanUp();
    }
  }
  /**
   * 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;
    }
  }
  /**
   * replaceNotification
   *
   * @param oldName a {@link java.lang.String} object.
   * @param newNotice a {@link org.opennms.netmgt.config.notifications.Notification} 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 replaceNotification(final String oldName, final Notification newNotice)
      throws MarshalException, ValidationException, IOException, ClassNotFoundException {
    //   In order to preserve the order of the notices, we have to replace "in place".

    Notification notice = getNotification(oldName);
    if (notice != null) {
      notice.setWriteable(newNotice.getWriteable());
      notice.setName(newNotice.getName());
      notice.setDescription(newNotice.getDescription());
      notice.setUei(newNotice.getUei());
      notice.setRule(newNotice.getRule());
      notice.setDestinationPath(newNotice.getDestinationPath());
      notice.setNoticeQueue(newNotice.getNoticeQueue());
      notice.setTextMessage(newNotice.getTextMessage());
      notice.setSubject(newNotice.getSubject());
      notice.setNumericMessage(newNotice.getNumericMessage());
      notice.setStatus(newNotice.getStatus());
      notice.setVarbind(newNotice.getVarbind());
      notice.getParameterCollection().clear(); // Required to avoid NMS-5948
      for (Parameter parameter : newNotice.getParameterCollection()) {
        Parameter newParam = new Parameter();
        newParam.setName(parameter.getName());
        newParam.setValue(parameter.getValue());
        notice.addParameter(newParam);
      }
      saveCurrent();
    } else addNotification(newNotice);
  }