Java tutorial
/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2012-2014 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2014 The OpenNMS Group, Inc. * * OpenNMS(R) is a registered trademark of The OpenNMS Group, Inc. * * OpenNMS(R) is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published * by the Free Software Foundation, either version 3 of the License, * or (at your option) any later version. * * OpenNMS(R) is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with OpenNMS(R). If not, see: * http://www.gnu.org/licenses/ * * For more information contact: * OpenNMS(R) Licensing <license@opennms.org> * http://www.opennms.org/ * http://www.opennms.com/ *******************************************************************************/ package org.opennms.netmgt.eventd; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.function.Supplier; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.opennms.core.spring.BeanUtils; import org.opennms.netmgt.eventd.processor.expandable.EventTemplate; import org.opennms.netmgt.eventd.processor.expandable.ExpandableParameterResolver; import org.opennms.netmgt.events.api.EventConstants; import org.opennms.netmgt.xml.event.Event; import org.opennms.netmgt.xml.event.Parm; import org.opennms.netmgt.xml.event.Value; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.support.TransactionOperations; import com.codahale.metrics.Gauge; import com.codahale.metrics.MetricRegistry; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; /** * EventUtil is used primarily for the event parm expansion - has methods used * by all the event components to send in the event and the element to expanded * and have the 'expanded' value sent back * * @author <A HREF="mailto:sowmya@opennms.org">Sowmya Kumaraswamy </A> * @author <A HREF="mailto:weave@oculan.com">Brain Weaver </A> * @author <A HREF="http://www.opennms.org/">OpenNMS </A> */ public abstract class AbstractEventUtil implements EventUtil { private static final Logger LOG = LoggerFactory.getLogger(AbstractEventUtil.class); /** * The Event ID xml */ protected static final String TAG_EVENT_DB_ID = "eventid"; /** * The UEI xml tag */ protected static final String TAG_UEI = "uei"; /** * The event source xml tag */ protected static final String TAG_SOURCE = "source"; /** * The event descr xml tag */ protected static final String TAG_DESCR = "descr"; /** * The event logmsg xml tag */ protected static final String TAG_LOGMSG = "logmsg"; /** * The event time xml tag */ protected static final String TAG_TIME = "time"; /** * The event time xml tag, short format */ protected static final String TAG_SHORT_TIME = "shorttime"; /** * The event dpname xml tag */ protected static final String TAG_DPNAME = "dpname"; /** * The event nodeid xml tag */ protected static final String TAG_NODEID = "nodeid"; /** * The event nodelabel xml tag */ protected static final String TAG_NODELABEL = "nodelabel"; /** * The event nodelocation xml tag */ protected static final String TAG_NODELOCATION = "nodelocation"; /** * The event host xml tag */ protected static final String TAG_HOST = "host"; /** * The event interface xml tag */ protected static final String TAG_INTERFACE = "interface"; /** * The foreignsource for the event's nodeid xml tag */ protected static final String TAG_FOREIGNSOURCE = "foreignsource"; /** * The foreignid for the event's nodeid xml tag */ protected static final String TAG_FOREIGNID = "foreignid"; /** * The event ifindex xml tag */ protected static final String TAG_IFINDEX = "ifindex"; /** * The reverse DNS lookup of the interface */ protected static final String TAG_INTERFACE_RESOLVE = "interfaceresolve"; /** * The reverse DNS lookup of the interface */ protected static final String TAG_IFALIAS = "ifalias"; /** * The event snmp id xml tag */ protected static final String TAG_SNMP_ID = "id"; /** * The SNMP xml tag */ protected static final String TAG_SNMP = "snmp"; /** * The event snmp idtext xml tag */ protected static final String TAG_SNMP_IDTEXT = "idtext"; /** * The event snmp version xml tag */ protected static final String TAG_SNMP_VERSION = "version"; /** * The event snmp specific xml tag */ protected static final String TAG_SNMP_SPECIFIC = "specific"; /** * The event snmp generic xml tag */ protected static final String TAG_SNMP_GENERIC = "generic"; /** * The event snmp community xml tag */ protected static final String TAG_SNMP_COMMUNITY = "community"; /** * The event snmp host xml tag */ protected static final String TAG_SNMPHOST = "snmphost"; /** * The event service xml tag */ protected static final String TAG_SERVICE = "service"; /** * The event severity xml tag */ protected static final String TAG_SEVERITY = "severity"; /** * The event operinstruct xml tag */ protected static final String TAG_OPERINSTR = "operinstruct"; /** * The event mouseovertext xml tag */ protected static final String TAG_MOUSEOVERTEXT = "mouseovertext"; protected static final String TAG_TTICKET_ID = "tticketid"; /** * The string that starts the expansion for an asset field - used to lookup values * of asset fields by their names */ protected static final String ASSET_BEGIN = "asset["; /** * The string that ends the expansion of a parm */ protected static final String ASSET_END_SUFFIX = "]"; /** * The string that should be expanded to a list of all parm names */ protected static final String PARMS_NAMES = "parm[names-all]"; /** * The string that should be expanded to a list of all parm values */ protected static final String PARMS_VALUES = "parm[values-all]"; /** * The string that should be expanded to a list of all parms */ protected static final String PARMS_ALL = "parm[all]"; /** * The string that starts the expansion for a parm - used to lookup values * of parameters by their names */ protected static final String PARM_BEGIN = "parm["; /** * Pattern used to match and parse 'parm' tokens. */ protected static final Pattern PARM_REGEX = Pattern.compile("^parm\\[(.*)\\]$"); /** * The length of PARM_BEGIN */ protected static final int PARM_BEGIN_LENGTH = 5; /** * The string that should be expanded to the number of parms */ protected static final String NUM_PARMS_STR = "parm[##]"; /** * The string that starts a parm number - used to lookup values of * parameters by their position */ protected static final String PARM_NUM_PREFIX = "parm[#"; /** * The length of PARM_NUM_PREFIX */ protected static final int PARM_NUM_PREFIX_LENGTH = 6; /** * The string that starts a request for the name of a numbered parm */ protected static final String PARM_NAME_NUMBERED_PREFIX = "parm[name-#"; /** * The length of PARM_NAME_NUMBERED_PREFIX */ protected static final int PARM_NAME_NUMBERED_PREFIX_LENGTH = 11; /** * The string that ends the expansion of a parm */ protected static final String PARM_END_SUFFIX = "]"; /** * For expansion of the '%parms[all]%' - the parm name and value are added * as delimiter separated list of ' <parmName>= <value>' strings */ protected static final char NAME_VAL_DELIM = '='; /** */ protected static final char SPACE_DELIM = ' '; /** * The values and the corresponding attributes of an element are added * delimited by ATTRIB_DELIM */ protected static final char ATTRIB_DELIM = ','; /** * Substitute the actual percent sign */ protected static final String TAG_PERCENT_SIGN = "pctsign"; /** * The string that starts the expansion for a hardware field - used to lookup values * of hardware attributes by their index|name */ protected static final String HARDWARE_BEGIN = "hardware["; /** * The string that ends the expansion of a hardware */ protected static final String HARDWARE_END_SUFFIX = "]"; private static EventUtil m_instance = null; public static synchronized EventUtil getInstance() { if (m_instance == null) { return BeanUtils.getBean("eventDaemonContext", "eventUtil", EventUtil.class); } else { return m_instance; } } /** * Used only for unit testing. * * @param instance */ public static void setInstance(EventUtil instance) { m_instance = instance; } /** * <P> * This method is used to escape required values from strings that may * contain those values. If the passed string contains the passed value then * the character is reformatted into its <EM>%dd</EM> format. * </P> * * @param inStr * string that might contain the delimiter * @param delimchar * delimiter to escape * @return The string with the delimiter escaped as in URLs * @see #ATTRIB_DELIM */ public static String escape(String inStr, char delimchar) { // integer equivalent of the delimiter int delim = delimchar; // convert this to a '%<int>' string String delimEscStr = "%" + String.valueOf(delim); // the buffer to return StringBuffer outBuffer = new StringBuffer(inStr); int index = 0; int delimIndex = inStr.indexOf(delimchar, index); while (delimIndex != -1) { // delete the delimiter and add the escape string outBuffer.deleteCharAt(delimIndex); outBuffer.insert(delimIndex, delimEscStr); index = delimIndex + delimEscStr.length() + 1; delimIndex = outBuffer.toString().indexOf(delimchar, index); } return outBuffer.toString(); } @Autowired private TransactionOperations transactionOperations; private final LoadingCache<String, EventTemplate> eventTemplateCache; private final ExpandableParameterResolverRegistry resolverRegistry = new ExpandableParameterResolverRegistry(); public AbstractEventUtil() { this(null); } public AbstractEventUtil(MetricRegistry registry) { // Build the cache, and enable statistics collection if we've been given a metric registry final long maximumCacheSize = Long .parseLong(System.getProperty("org.opennms.eventd.eventTemplateCacheSize", "1000")); final CacheBuilder<Object, Object> cacheBuilder = CacheBuilder.newBuilder().maximumSize(maximumCacheSize); if (registry != null) { cacheBuilder.recordStats(); } eventTemplateCache = cacheBuilder.build(new CacheLoader<String, EventTemplate>() { public EventTemplate load(String key) throws Exception { return new EventTemplate(key, AbstractEventUtil.this); } }); if (registry != null) { // Expose the cache statistics via a series of gauges registry.register(MetricRegistry.name("eventutil.cache.capacity"), new Gauge<Long>() { @Override public Long getValue() { return maximumCacheSize; } }); registry.register(MetricRegistry.name("eventutil.cache.size"), new Gauge<Long>() { @Override public Long getValue() { return eventTemplateCache.size(); } }); registry.register(MetricRegistry.name("eventutil.cache.evictioncount"), new Gauge<Long>() { @Override public Long getValue() { return eventTemplateCache.stats().evictionCount(); } }); registry.register(MetricRegistry.name("eventutil.cache.avgloadpenalty"), new Gauge<Double>() { @Override public Double getValue() { return eventTemplateCache.stats().averageLoadPenalty(); } }); } } /** * Helper method. * * @param event * @return All event parameter values as a String. */ protected static String getAllParmValues(Event event) { String retParmVal = null; if (event.getParmCollection().size() < 1) { retParmVal = null; } else { StringBuffer ret = new StringBuffer(); for (Parm evParm : event.getParmCollection()) { Value parmValue = evParm.getValue(); if (parmValue == null) continue; String parmValueStr = EventConstants.getValueAsString(parmValue); if (parmValueStr == null) continue; if (ret.length() == 0) { ret.append(parmValueStr); } else { ret.append(SPACE_DELIM + parmValueStr); } } retParmVal = ret.toString(); } return retParmVal; } /** * Helper method. * @param event * @return The names of all the event parameters. */ protected static String getAllParmNames(Event event) { if (event.getParmCollection().size() <= 0) { return null; } else { StringBuffer ret = new StringBuffer(); for (Parm evParm : event.getParmCollection()) { String parmName = evParm.getParmName(); if (parmName == null) continue; if (ret.length() == 0) { ret.append(parmName.trim()); } else { ret.append(SPACE_DELIM + parmName.trim()); } } return ret.toString(); } } /** * Helper method. * * @param event * @return All event parameter values as a String */ protected static String getAllParamValues(final Event event) { if (event.getParmCollection().size() < 1) { return null; } else { final StringBuffer ret = new StringBuffer(); for (final Parm evParm : event.getParmCollection()) { final String parmName = evParm.getParmName(); if (parmName == null) continue; final Value parmValue = evParm.getValue(); if (parmValue == null) continue; final String parmValueStr = EventConstants.getValueAsString(parmValue); if (ret.length() != 0) { ret.append(SPACE_DELIM); } ret.append(parmName.trim()).append(NAME_VAL_DELIM).append("\"").append(parmValueStr).append("\""); } return ret.toString().intern(); } } /** * Helper method. * * @param parm * @param event * @return The name of a parameter based on its ordinal position in the event's list of parameters */ protected static String getNumParmName(String parm, Event event) { String retParmVal = null; final List<Parm> parms = event.getParmCollection(); int end = parm.lastIndexOf(PARM_END_SUFFIX); if (end != -1 && parms != null && parms.size() > 0) { // Get the string between the '#' and ']' String parmSpec = parm.substring(PARM_NAME_NUMBERED_PREFIX_LENGTH, end); String eparmnum = null; String eparmsep = null; String eparmoffset = null; String eparmrangesep = null; String eparmrangelen = null; if (parmSpec.matches("^\\d+$")) { eparmnum = parmSpec; } else { Matcher m = Pattern.compile("^(\\d+)([^0-9+-]+)([+-]?\\d+)((:)([+-]?\\d+)?)?$").matcher(parmSpec); if (m.matches()) { eparmnum = m.group(1); eparmsep = m.group(2); eparmoffset = m.group(3); eparmrangesep = m.group(5); eparmrangelen = m.group(6); } } int parmNum = -1; try { parmNum = Integer.parseInt(eparmnum); } catch (NumberFormatException nfe) { parmNum = -1; retParmVal = null; } if (parmNum > 0 && parmNum <= parms.size()) { final Parm evParm = parms.get(parmNum - 1); // get parm name String eparmname = evParm.getParmName(); // If separator and offset specified, split and extract accordingly if ((eparmsep != null) && (eparmoffset != null)) { int parmOffset = Integer.parseInt(eparmoffset); boolean doRange = ":".equals(eparmrangesep); int parmRangeLen = (eparmrangelen == null) ? 0 : Integer.parseInt(eparmrangelen); retParmVal = splitAndExtract(eparmname, eparmsep, parmOffset, doRange, parmRangeLen); } else { retParmVal = eparmname; } } else { retParmVal = null; } } return retParmVal; } public static String splitAndExtract(String src, String sep, int offset, boolean doRange, int rangeLen) { String sepLiteral = Pattern.quote(sep); // If the src string starts with the separator, lose the first separator if (src.startsWith(sep)) { src = src.replaceFirst(sepLiteral, ""); } String[] components = src.split(sepLiteral); int startIndex, endIndex; if ((Math.abs(offset) > components.length) || (offset == 0)) { return null; } else if (offset < 0) { startIndex = components.length + offset; } else { // offset is, by definition, > 0 startIndex = offset - 1; } endIndex = startIndex; if (!doRange) { return components[startIndex]; } else if (rangeLen == 0) { endIndex = components.length - 1; } else if (rangeLen < 0) { endIndex = startIndex + 1 + rangeLen; } else { // rangeLen is, by definition, > 0 endIndex = startIndex - 1 + rangeLen; } StringBuffer retVal = new StringBuffer(); for (int i = startIndex; i <= endIndex; i++) { retVal.append(components[i]); if (i < endIndex) { retVal.append(sep); } } return retVal.toString(); } /** * Helper method. * * @param parm * @param event * @return The value of a parameter based on its ordinal position in the event's list of parameters */ protected static String getNumParmValue(String parm, Event event) { String retParmVal = null; final List<Parm> parms = event.getParmCollection(); int end = parm.lastIndexOf(PARM_END_SUFFIX); if (end != -1 && parms != null && parms.size() > 0) { // Get the value between the '#' and ']' String eparmname = parm.substring(PARM_NUM_PREFIX_LENGTH, end); int parmNum = -1; try { parmNum = Integer.parseInt(eparmname); } catch (NumberFormatException nfe) { parmNum = -1; retParmVal = null; } if (parmNum > 0 && parmNum <= parms.size()) { final Parm evParm = parms.get(parmNum - 1); // get parm value Value eparmval = evParm.getValue(); if (eparmval != null) { retParmVal = EventConstants.getValueAsString(eparmval); } } else { retParmVal = null; } } return retParmVal; } /** * Helper method. * * @param parm a {@link java.lang.String} object. * @param event a {@link org.opennms.netmgt.xml.event.Event} object. * @return A parameter's value as a String using the parameter's name.. */ public String getNamedParmValue(String parm, Event event) { final Matcher matcher = PARM_REGEX.matcher(parm); if (!matcher.matches()) { return null; } final String eparmname = matcher.group(1); final Parm evParm = event.getParmTrim(eparmname); if (evParm != null) { final Value eparmval = evParm.getValue(); if (eparmval != null) { return EventConstants.getValueAsString(eparmval); } } return null; } /** * <p>expandMapValues</p> * * @param map a {@link java.util.Map} object. * @param event a {@link org.opennms.netmgt.xml.event.Event} object. */ public void expandMapValues(final Map<String, String> map, final Event event) { for (final Entry<String, String> entry : map.entrySet()) { final String key = entry.getKey(); final String mapValue = entry.getValue(); if (mapValue == null) { continue; } final String expandedValue = expandParms(map.get(key), event); if (expandedValue == null) { // Don't use this value to replace the existing value if it's null } else { map.put(key, expandedValue); } } } /** * Expand the value if it has parms in one of the following formats - * %element% values are expanded to have the value of the element where * 'element' is an element in the event DTD - %parm[values-all]% is expanded * to a delimited list of all parmblock values - %parm[names-all]% is * expanded to a list of all parm names - %parm[all]% is expanded to a full * dump of all parmblocks - %parm[name]% is expanded to the value of the * parameter named 'name' - %parm[ <name>]% is replaced by the value of the * parameter named 'name', if present - %parm[# <num>]% is replaced by the * value of the parameter number 'num', if present - %parm[##]% is replaced * by the number of parameters * * @param inp * the input string in which parm values are to be expanded * @return expanded value if the value had any parameter to expand, null * otherwise * @param event a {@link org.opennms.netmgt.xml.event.Event} object. */ public String expandParms(String inp, Event event) { return expandParms(inp, event, null); } /** * Expand the value if it has parms in one of the following formats - * %element% values are expanded to have the value of the element where * 'element' is an element in the event DTD - %parm[values-all]% is expanded * to a delimited list of all parmblock values - %parm[names-all]% is * expanded to a list of all parm names - %parm[all]% is expanded to a full * dump of all parmblocks - %parm[name]% is expanded to the value of the * parameter named 'name' - %parm[ <name>]% is replaced by the value of the * parameter named 'name', if present - %parm[# <num>]% is replaced by the * value of the parameter number 'num', if present - %parm[##]% is replaced * by the number of parameters * * @param input * the input string in which parm values are to be expanded * @param decode * the varbind decode for this * @return expanded value if the value had any parameter to expand, null * otherwise * @param event a {@link org.opennms.netmgt.xml.event.Event} object. */ public String expandParms(String input, Event event, Map<String, Map<String, String>> decode) { if (input == null) { return null; } try { final EventTemplate eventTemplate = eventTemplateCache.get(input); Supplier<String> expander = () -> eventTemplate.expand(event, decode); if (eventTemplate.requiresTransaction()) { Objects.requireNonNull(transactionOperations); return transactionOperations.execute(session -> expander.get()); } else { return expander.get(); } } catch (ExecutionException ex) { throw new RuntimeException(ex); } } /** * <p>getEventHost</p> * * @param event a {@link org.opennms.netmgt.xml.event.Event} object. * @return a {@link java.lang.String} object. */ @Override public String getEventHost(final Event event) { if (event.getHost() == null) { return null; } // If the event doesn't have a node ID, we can't lookup the IP address and be sure we have the right one since we don't know what node it is on if (!event.hasNodeid()) { return event.getHost(); } try { return getHostName(event.getNodeid().intValue(), event.getHost()); } catch (final Throwable t) { LOG.warn("Error converting host IP \"{}\" to a hostname, storing the IP.", event.getHost(), t); return event.getHost(); } } @Override public ExpandableParameterResolver getResolver(String token) { return resolverRegistry.getResolver(token); } }