/*******************************************************************************
* This file is part of OpenNMS(R).
*
* Copyright (C) 2006-2011 The OpenNMS Group, Inc.
* OpenNMS(R) is Copyright (C) 1999-2011 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 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 General Public License for more details.
*
* You should have received a copy of the GNU 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.config;
import static org.opennms.core.utils.InetAddressUtils.addr;
import static org.opennms.core.utils.InetAddressUtils.str;
import static org.opennms.core.utils.InetAddressUtils.toIpAddrBytes;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.Marshaller;
import org.exolab.castor.xml.ValidationException;
import org.opennms.core.utils.ByteArrayComparator;
import org.opennms.core.utils.IpListFromUrl;
import org.opennms.core.utils.LogUtils;
import org.opennms.core.xml.CastorUtils;
import org.opennms.core.xml.MarshallingResourceFailureException;
import org.opennms.netmgt.config.poller.CriticalService;
import org.opennms.netmgt.config.poller.ExcludeRange;
import org.opennms.netmgt.config.poller.IncludeRange;
import org.opennms.netmgt.config.poller.Monitor;
import org.opennms.netmgt.config.poller.Package;
import org.opennms.netmgt.config.poller.Parameter;
import org.opennms.netmgt.config.poller.PollerConfiguration;
import org.opennms.netmgt.config.poller.Service;
import org.opennms.netmgt.dao.CastorObjectRetrievalFailureException;
import org.opennms.netmgt.filter.FilterDaoFactory;
import org.opennms.netmgt.model.OnmsMonitoredService;
import org.opennms.netmgt.model.ServiceSelector;
import org.opennms.netmgt.poller.Distributable;
import org.opennms.netmgt.poller.DistributionContext;
import org.opennms.netmgt.poller.ServiceMonitor;
import org.opennms.netmgt.poller.ServiceMonitorLocator;
import org.opennms.netmgt.rrd.RrdException;
import org.opennms.netmgt.rrd.RrdUtils;
import org.springframework.dao.PermissionDeniedDataAccessException;
/**
* <p>Abstract PollerConfigManager class.</p>
*
* @author <a href="mailto:brozow@openms.org">Mathew Brozowski</a>
* @author <a href="mailto:david@opennms.org">David Hustace</a>
*/
abstract public class PollerConfigManager implements PollerConfig {
private final ReadWriteLock m_globalLock = new ReentrantReadWriteLock();
private final Lock m_readLock = m_globalLock.readLock();
private final Lock m_writeLock = m_globalLock.writeLock();
/**
* <p>Constructor for PollerConfigManager.</p>
*
* @param stream a {@link java.io.InputStream} object.
* @param localServer a {@link java.lang.String} object.
* @param verifyServer a boolean.
* @throws org.exolab.castor.xml.MarshalException if any.
* @throws org.exolab.castor.xml.ValidationException if any.
*/
public PollerConfigManager(final InputStream stream, final String localServer, final boolean verifyServer) throws MarshalException, ValidationException {
m_localServer = localServer;
m_verifyServer = verifyServer;
m_config = CastorUtils.unmarshal(PollerConfiguration.class, stream);
setUpInternalData();
}
public Lock getReadLock() {
return m_readLock;
}
public Lock getWriteLock() {
return m_writeLock;
}
/**
* <p>setUpInternalData</p>
*/
protected void setUpInternalData() {
createUrlIpMap();
createPackageIpListMap();
initializeServiceMonitors();
}
/**
* <p>update</p>
*
* @throws java.io.IOException if any.
* @throws org.exolab.castor.xml.MarshalException if any.
* @throws org.exolab.castor.xml.ValidationException if any.
*/
public abstract void update() throws IOException, MarshalException, ValidationException;
/**
* <p>saveXml</p>
*
* @param xml a {@link java.lang.String} object.
* @throws java.io.IOException if any.
*/
protected abstract void saveXml(String xml) throws IOException;
/**
* The config class loaded from the config file
*/
protected PollerConfiguration m_config;
/**
* A mapping of the configured URLs to a list of the specific IPs configured
* in each - so as to avoid file reads
*/
private Map<String, List<String>> m_urlIPMap;
/**
* A mapping of the configured package to a list of IPs selected via filter
* rules, so as to avoid repetitive database access.
*/
private AtomicReference<Map<Package, List<InetAddress>>> m_pkgIpMap = new AtomicReference<Map<Package, List<InetAddress>>>();;
/**
* A mapp of service names to service monitors. Constructed based on data in
* the configuration file.
*/
private Map<String, ServiceMonitor> m_svcMonitors = new ConcurrentSkipListMap<String, ServiceMonitor>();
/**
* A boolean flag to indicate If a filter rule against the local OpenNMS
* server has to be used.
*/
private static boolean m_verifyServer;
/**
* The name of the local OpenNMS server
*/
private static String m_localServer;
/**
* Go through the poller configuration and build a mapping of each
* configured URL to a list of IPs configured in that URL - done at init()
* time so that repeated file reads can be avoided
*/
private void createUrlIpMap() {
m_urlIPMap = new HashMap<String, List<String>>();
for(final Package pkg : packages()) {
for(final String url : includeURLs(pkg)) {
final List<String> iplist = IpListFromUrl.parse(url);
if (iplist.size() > 0) {
m_urlIPMap.put(url, iplist);
}
}
}
}
/**
* Saves the current in-memory configuration to disk and reloads
*
* @throws org.exolab.castor.xml.MarshalException if any.
* @throws java.io.IOException if any.
* @throws org.exolab.castor.xml.ValidationException if any.
*/
public void save() throws MarshalException, IOException, ValidationException {
getWriteLock().lock();
try {
// marshal to a string first, then write the string to the file. This
// way the original config
// isn't lost if the XML from the marshal is hosed.
final StringWriter stringWriter = new StringWriter();
Marshaller.marshal(m_config, stringWriter);
saveXml(stringWriter.toString());
update();
} finally {
getWriteLock().unlock();
}
}
/**
* Return the poller configuration object.
*
* @return a {@link org.opennms.netmgt.config.poller.PollerConfiguration} object.
*/
public PollerConfiguration getConfiguration() {
getReadLock().lock();
try {
return m_config;
} finally {
getReadLock().unlock();
}
}
/** {@inheritDoc} */
public Package getPackage(final String name) {
getReadLock().lock();
try {
for(final Package pkg : packages()) {
if (pkg.getName().equals(name)) {
return pkg;
}
}
} finally {
getReadLock().unlock();
}
return null;
}
/** {@inheritDoc} */
public ServiceSelector getServiceSelectorForPackage(final Package pkg) {
getReadLock().lock();
try {
final List<String> svcNames = new LinkedList<String>();
for(Service svc : services(pkg)) {
svcNames.add(svc.getName());
}
final String filter = pkg.getFilter().getContent();
return new ServiceSelector(filter, svcNames);
} finally {
getReadLock().unlock();
}
}
/** {@inheritDoc} */
public void addPackage(final Package pkg) {
getWriteLock().lock();
try {
m_config.addPackage(pkg);
} finally {
getWriteLock().unlock();
}
}
/** {@inheritDoc} */
public void addMonitor(final String svcName, final String className) {
getWriteLock().lock();
try {
final Monitor monitor = new Monitor();
monitor.setService(svcName);
monitor.setClassName(className);
m_config.addMonitor(monitor);
} finally {
getWriteLock().unlock();
}
}
/**
* This method is used to determine if the named interface is included in
* the passed package's url includes. If the interface is found in any of
* the URL files, then a value of true is returned, else a false value is
* returned.
*
* <pre>
*
* The file URL is read and each entry in this file checked. Each line
* in the URL file can be one of -
* <IP><space>#<comments>
* or
* <IP>
* or
* #<comments>
*
* Lines starting with a '#' are ignored and so are characters after
* a '<space>#' in a line.
*
* </pre>
*
* @param addr
* The interface to test against the package's URL
* @param url
* The url file to read
*
* @return True if the interface is included in the url, false otherwise.
*/
private boolean interfaceInUrl(final String addr, final String url) {
boolean bRet = false;
// get list of IPs in this URL
final List<String> iplist = m_urlIPMap.get(url);
if (iplist != null && iplist.size() > 0) {
bRet = iplist.contains(addr);
}
return bRet;
}
/**
* This method returns the boolean flag xmlrpc to indicate if notification
* to external xmlrpc server is needed.
*
* @return true if need to notify an external xmlrpc server
*/
public boolean shouldNotifyXmlrpc() {
getReadLock().lock();
try {
return Boolean.valueOf(m_config.getXmlrpc());
} finally {
getReadLock().unlock();
}
}
/**
* This method returns the boolean flag pathOutageEnabled to indicate if
* path outage processing on nodeDown events is enabled
*
* @return true if pathOutageEnabled
*/
public boolean isPathOutageEnabled() {
getReadLock().lock();
try {
return Boolean.valueOf(m_config.getPathOutageEnabled());
} finally {
getReadLock().unlock();
}
}
/**
* This method returns the configured critical service name.
*
* @return the name of the configured critical service, or null if none is
* present
*/
public String getCriticalService() {
getReadLock().lock();
try {
CriticalService service = m_config.getNodeOutage().getCriticalService();
return service == null ? null : service.getName();
} finally {
getReadLock().unlock();
}
}
/**
* This method returns the configured value of the
* 'pollAllIfNoCriticalServiceDefined' flag.
*
* A value of true causes the poller's node outage code to poll all the
* services on an interface if a status change has occurred and there is no
* critical service defined on the interface.
*
* A value of false causes the poller's node outage code to not poll all the
* services on an interface in this situation.
* </p>
*
* @return true or false based on configured value
*/
public boolean shouldPollAllIfNoCriticalServiceDefined() {
getReadLock().lock();
try {
return Boolean.valueOf(m_config.getNodeOutage().getPollAllIfNoCriticalServiceDefined());
} finally {
getReadLock().unlock();
}
}
/**
* Returns true if node outage processing is enabled.
*
* @return a boolean.
*/
public boolean isNodeOutageProcessingEnabled() {
getReadLock().lock();
try {
return m_config.getNodeOutage().getStatus().equals("on");
} finally {
getReadLock().unlock();
}
}
/**
* Returns true if serviceUnresponsive behavior is enabled. If enabled a
* serviceUnresponsive event is generated for TCP-based services if the
* service monitor is able to connect to the designated port but times out
* before receiving the expected response. If disabled, an outage will be
* generated in this scenario.
*
* @return a boolean.
*/
public boolean isServiceUnresponsiveEnabled() {
getReadLock().lock();
try {
return Boolean.valueOf(m_config.getServiceUnresponsiveEnabled());
} finally {
getReadLock().unlock();
}
}
/**
* This method is used to establish package agaist iplist mapping, with
* which, the iplist is selected per package via the configured filter rules
* from the database.
*/
private void createPackageIpListMap() {
getReadLock().lock();
try {
Map<Package, List<InetAddress>> pkgIpMap = new HashMap<Package, List<InetAddress>>();
for(final Package pkg : packages()) {
// Get a list of ipaddress per package against the filter rules from
// database and populate the package, IP list map.
//
try {
List<InetAddress> ipList = getIpList(pkg);
LogUtils.debugf(this, "createPackageIpMap: package %s: ipList size = %d", pkg.getName(), ipList.size());
if (ipList.size() > 0) {
pkgIpMap.put(pkg, ipList);
}
} catch (final Throwable t) {
LogUtils.errorf(this, t, "createPackageIpMap: failed to map package: %s to an IP List with filter \"%s\"", pkg.getName(), pkg.getFilter().getContent());
}
}
m_pkgIpMap.set(pkgIpMap);
} finally {
getReadLock().unlock();
}
}
/** {@inheritDoc} */
public List<InetAddress> getIpList(final Package pkg) {
getReadLock().lock();
try {
final StringBuffer filterRules = new StringBuffer(pkg.getFilter().getContent());
if (m_verifyServer) {
filterRules.append(" & (serverName == ");
filterRules.append('\"');
filterRules.append(m_localServer);
filterRules.append('\"');
filterRules.append(")");
}
LogUtils.debugf(this, "createPackageIpMap: package is %s. filter rules are %s", pkg.getName(), filterRules.toString());
return FilterDaoFactory.getInstance().getActiveIPAddressList(filterRules.toString());
} finally {
getReadLock().unlock();
}
}
/**
* This method is used to rebuild the package agaist iplist mapping when
* needed. When a node gained service event occurs, poller has to determine
* which package the ip/service combination is in, but if the interface is a
* newly added one, the package iplist should be rebuilt so that poller
* could know which package this ip/service pair is in.
*/
public void rebuildPackageIpListMap() {
createPackageIpListMap();
}
/**
* {@inheritDoc}
*
* This method is used to determine if the named interface is included in
* the passed package definition. If the interface belongs to the package
* then a value of true is returned. If the interface does not belong to the
* package a false value is returned.
*
* <strong>Note: </strong>Evaluation of the interface against a package
* filter will only work if the IP is already in the database.
*/
public boolean isInterfaceInPackage(final String iface, final Package pkg) {
boolean filterPassed = false;
final InetAddress ifaceAddr = addr(iface);
// get list of IPs in this package
final List<InetAddress> ipList = m_pkgIpMap.get().get(pkg);
if (ipList != null && ipList.size() > 0) {
filterPassed = ipList.contains(ifaceAddr);
}
LogUtils.debugf(this, "interfaceInPackage: Interface %s passed filter for package %s?: %s", iface, pkg.getName(), Boolean.valueOf(filterPassed));
if (!filterPassed) return false;
//
// Ensure that the interface is in the specific list or
// that it is in the include range and is not excluded
//
boolean has_specific = false;
boolean has_range_include = false;
boolean has_range_exclude = false;
// if there are NO include ranges then treat act as if the user include
// the range of all valid addresses (0.0.0.0 - 255.255.255.255, ::1 - ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff)
has_range_include = pkg.getIncludeRangeCount() == 0 && pkg.getSpecificCount() == 0;
final byte[] addr = toIpAddrBytes(iface);
for (final IncludeRange rng : pkg.getIncludeRangeCollection()) {
int comparison = new ByteArrayComparator().compare(addr, toIpAddrBytes(rng.getBegin()));
if (comparison > 0) {
int endComparison = new ByteArrayComparator().compare(addr, toIpAddrBytes(rng.getEnd()));
if (endComparison <= 0) {
has_range_include = true;
break;
}
} else if (comparison == 0) {
has_range_include = true;
break;
}
}
for (final String spec : pkg.getSpecificCollection()) {
if (new ByteArrayComparator().compare(addr, toIpAddrBytes(spec)) == 0) {
has_specific = true;
break;
}
}
for (final String includeUrl : pkg.getIncludeUrlCollection()) {
if (interfaceInUrl(iface, includeUrl)) {
has_specific = true;
break;
}
}
if (!has_specific) {
for (final ExcludeRange rng : pkg.getExcludeRangeCollection()) {
int comparison = new ByteArrayComparator().compare(addr, toIpAddrBytes(rng.getBegin()));
if (comparison > 0) {
int endComparison = new ByteArrayComparator().compare(addr, toIpAddrBytes(rng.getEnd()));
if (endComparison <= 0) {
has_range_exclude = true;
break;
}
} else if (comparison == 0) {
has_range_exclude = true;
break;
}
}
}
return has_specific || (has_range_include && !has_range_exclude);
}
/**
* {@inheritDoc}
*
* Returns true if the service is part of the package and the status of the
* service is set to "on". Returns false if the service is not in the
* package or it is but the status of the service is set to "off".
*/
public boolean isServiceInPackageAndEnabled(final String svcName, final Package pkg) {
getReadLock().lock();
try {
if (pkg == null) {
LogUtils.warnf(this, "serviceInPackageAndEnabled: pkg argument is NULL!!");
return false;
} else {
LogUtils.debugf(this, "serviceInPackageAndEnabled: svcName=%s pkg=%s", svcName, pkg.getName());
}
for(final Service svc : services(pkg)) {
if (svc.getName().equalsIgnoreCase(svcName)) {
// Ok its in the package. Now check the
// status of the service
final String status = svc.getStatus();
if (status == null || status.equals("on")) {
return true;
}
}
}
} finally {
getReadLock().unlock();
}
return false;
}
/**
* {@inheritDoc}
*
* Return the Service object with the given name from the give Package.
*/
public Service getServiceInPackage(final String svcName, final Package pkg) {
getReadLock().lock();
try {
for(final Service svc : services(pkg)) {
if (svcName.equals(svc.getName())) return svc;
}
} finally {
getReadLock().unlock();
}
return null;
}
/**
* {@inheritDoc}
*
* Returns true if the service has a monitor configured, false otherwise.
*/
public boolean isServiceMonitored(final String svcName) {
getReadLock().lock();
try {
for (final Monitor monitor : monitors()) {
if (monitor.getService().equals(svcName)) {
return true;
}
}
} finally {
getReadLock().unlock();
}
return false;
}
/**
* {@inheritDoc}
*
* Returns the first package that the ip belongs to, null if none.
*
* <strong>Note: </strong>Evaluation of the interface against a package
* filter will only work if the IP is alrady in the database.
*/
public Package getFirstPackageMatch(final String ipaddr) {
getReadLock().lock();
try {
for(final Package pkg : packages()) {
if (isInterfaceInPackage(ipaddr, pkg)) {
return pkg;
}
}
} finally {
getReadLock().unlock();
}
return null;
}
/** {@inheritDoc} */
public Package getFirstLocalPackageMatch(final String ipaddr) {
getReadLock().lock();
try {
for(final Package pkg : packages()) {
if (!pkg.getRemote() && isInterfaceInPackage(ipaddr, pkg)) {
return pkg;
}
}
} finally {
getReadLock().unlock();
}
return null;
}
/**
* {@inheritDoc}
*
* Returns a list of package names that the ip belongs to, null if none.
*
* <strong>Note: </strong>Evaluation of the interface against a package
* filter will only work if the IP is alrady in the database.
*/
public List<String> getAllPackageMatches(final String ipaddr) {
List<String> matchingPkgs = new ArrayList<String>();
getReadLock().lock();
try {
for (final Package pkg : packages()) {
if (isInterfaceInPackage(ipaddr, pkg)) {
matchingPkgs.add(pkg.getName());
}
}
} finally {
getReadLock().unlock();
}
return matchingPkgs;
}
/**
* {@inheritDoc}
*
* Returns true if the ip is part of atleast one package.
*
* <strong>Note: </strong>Evaluation of the interface against a package
* filter will only work if the IP is alrady in the database.
*/
public boolean isPolled(final String ipaddr) {
getReadLock().lock();
try {
for(final Package pkg : packages()) {
if (isInterfaceInPackage(ipaddr, pkg)) return true;
}
} finally {
getReadLock().unlock();
}
return false;
}
/** {@inheritDoc} */
public boolean isPolledLocally(final String ipaddr) {
getReadLock().lock();
try {
for(final Package pkg : packages()) {
if (!pkg.getRemote() && isInterfaceInPackage(ipaddr, pkg)) {
return true;
}
}
} finally {
getReadLock().unlock();
}
return false;
}
/**
* {@inheritDoc}
*
* Returns true if this package has the service enabled and if there is a
* monitor for this service.
*
* <strong>Note: </strong>Evaluation of the interface against a package
* filter will only work if the IP is alrady in the database.
*/
public boolean isPolled(final String svcName, final Package pkg) {
if (isServiceInPackageAndEnabled(svcName, pkg)) {
return isServiceMonitored(svcName);
}
return false;
}
/**
* Returns true if the ip is part of atleast one package and if this package
* has the service enabled and if there is a monitor for this service.
*
* <strong>Note: </strong>Evaluation of the interface against a package
* filter will only work if the IP is alrady in the database.
*
* @param ipaddr
* the interface to check
* @param svcName
* the service to check
* @return true if the ip is part of atleast one package and the service is
* enabled in this package and monitored, false otherwise
*/
public boolean isPolled(final String ipaddr, final String svcName) {
getReadLock().lock();
try {
// First make sure there is a service monitor for this service!
if (!isServiceMonitored(svcName)) {
return false;
}
for(final Package pkg : packages()) {
if (isServiceInPackageAndEnabled(svcName, pkg) && isInterfaceInPackage(ipaddr, pkg)) {
return true;
}
}
} finally {
getReadLock().unlock();
}
return false;
}
/** {@inheritDoc} */
public boolean isPolledLocally(final String ipaddr, final String svcName) {
getReadLock().lock();
try {
if (!isServiceMonitored(svcName)) {
return false;
}
for(final Package pkg : packages()) {
if (isServiceInPackageAndEnabled(svcName, pkg) && isInterfaceInPackage(ipaddr, pkg)) {
return true;
}
}
} finally {
getReadLock().unlock();
}
return false;
}
/**
* {@inheritDoc}
*
* Retrieves configured RRD step size.
*/
public int getStep(final Package pkg) {
getReadLock().lock();
try {
return pkg.getRrd().getStep();
} finally {
getReadLock().unlock();
}
}
/**
* {@inheritDoc}
*
* Retrieves configured list of RoundRobin Archive statements.
*/
public List<String> getRRAList(final Package pkg) {
getReadLock().lock();
try {
return pkg.getRrd().getRraCollection();
} finally {
getReadLock().unlock();
}
}
/**
* <p>enumeratePackage</p>
*
* @return a {@link java.util.Enumeration} object.
*/
public Enumeration<Package> enumeratePackage() {
getReadLock().lock();
try {
return getConfiguration().enumeratePackage();
} finally {
getReadLock().unlock();
}
}
/**
* <p>enumerateMonitor</p>
*
* @return a {@link java.util.Enumeration} object.
*/
public Enumeration<Monitor> enumerateMonitor() {
getReadLock().lock();
try {
return getConfiguration().enumerateMonitor();
} finally {
getReadLock().unlock();
}
}
/**
* <p>services</p>
*
* @param pkg a {@link org.opennms.netmgt.config.poller.Package} object.
* @return a {@link java.lang.Iterable} object.
*/
public Iterable<Service> services(final Package pkg) {
getReadLock().lock();
try {
return pkg.getServiceCollection();
} finally {
getReadLock().unlock();
}
}
/**
* <p>includeURLs</p>
*
* @param pkg a {@link org.opennms.netmgt.config.poller.Package} object.
* @return a {@link java.lang.Iterable} object.
*/
public Iterable<String> includeURLs(final Package pkg) {
getReadLock().lock();
try {
return pkg.getIncludeUrlCollection();
} finally {
getReadLock().unlock();
}
}
/**
* <p>parameters</p>
*
* @param svc a {@link org.opennms.netmgt.config.poller.Service} object.
* @return a {@link java.lang.Iterable} object.
*/
public Iterable<Parameter> parameters(final Service svc) {
getReadLock().lock();
try {
return svc.getParameterCollection();
} finally {
getReadLock().unlock();
}
}
/**
* <p>packages</p>
*
* @return a {@link java.lang.Iterable} object.
*/
public Iterable<Package> packages() {
getReadLock().lock();
try {
return getConfiguration().getPackageCollection();
} finally {
getReadLock().unlock();
}
}
/**
* <p>monitors</p>
*
* @return a {@link java.lang.Iterable} object.
*/
public Iterable<Monitor> monitors() {
getReadLock().lock();
try {
return getConfiguration().getMonitorCollection();
} finally {
getReadLock().unlock();
}
}
/**
* <p>getThreads</p>
*
* @return a int.
*/
public int getThreads() {
getReadLock().lock();
try {
return getConfiguration().getThreads();
} finally {
getReadLock().unlock();
}
}
/**
* @param poller
* @return
*/
private void initializeServiceMonitors() {
// Load up an instance of each monitor from the config
// so that the event processor will have them for
// new incoming events to create pollable service objects.
//
LogUtils.debugf(this, "start: Loading monitors");
final Collection<ServiceMonitorLocator> locators = getServiceMonitorLocators(DistributionContext.DAEMON);
for (final ServiceMonitorLocator locator : locators) {
try {
m_svcMonitors.put(locator.getServiceName(), locator.getServiceMonitor());
} catch (Throwable t) {
LogUtils.warnf(this, t, "start: Failed to create monitor %s for service %s", locator.getServiceLocatorKey(), locator.getServiceName());
}
}
}
/**
* <p>getServiceMonitors</p>
*
* @return a {@link java.util.Map} object.
*/
public Map<String, ServiceMonitor> getServiceMonitors() {
getReadLock().lock();
try {
return Collections.unmodifiableMap(m_svcMonitors);
} finally {
getReadLock().unlock();
}
}
/** {@inheritDoc} */
public ServiceMonitor getServiceMonitor(final String svcName) {
getReadLock().lock();
try {
return getServiceMonitors().get(svcName);
} finally {
getReadLock().unlock();
}
}
/** {@inheritDoc} */
public Collection<ServiceMonitorLocator> getServiceMonitorLocators(final DistributionContext context) {
List<ServiceMonitorLocator> locators = new ArrayList<ServiceMonitorLocator>();
getReadLock().lock();
try {
for(final Monitor monitor : monitors()) {
try {
final Class<? extends ServiceMonitor> mc = findServiceMonitorClass(monitor);
if (isDistributableToContext(mc, context)) {
final ServiceMonitorLocator locator = new DefaultServiceMonitorLocator(monitor.getService(), mc);
locators.add(locator);
}
} catch (final ClassNotFoundException e) {
LogUtils.warnf(this, e, "Unable to location monitor for service: %s class-name: %s", monitor.getService(), monitor.getClassName());
} catch (CastorObjectRetrievalFailureException e) {
LogUtils.warnf(this, e, e.getMessage(), e.getRootCause());
}
}
} finally {
getReadLock().unlock();
}
return locators;
}
private boolean isDistributableToContext(final Class<? extends ServiceMonitor> mc, final DistributionContext context) {
final List<DistributionContext> supportedContexts = getSupportedDistributionContexts(mc);
if (supportedContexts.contains(context) || supportedContexts.contains(DistributionContext.ALL)) {
return true;
}
return false;
}
private List<DistributionContext> getSupportedDistributionContexts(final Class<? extends ServiceMonitor> mc) {
final Distributable distributable = mc.getAnnotation(Distributable.class);
final List<DistributionContext> declaredContexts =
distributable == null
? Collections.singletonList(DistributionContext.DAEMON)
: Arrays.asList(distributable.value());
return declaredContexts;
}
private Class<? extends ServiceMonitor> findServiceMonitorClass(final Monitor monitor) throws ClassNotFoundException {
final Class<? extends ServiceMonitor> mc = Class.forName(monitor.getClassName()).asSubclass(ServiceMonitor.class);
if (!ServiceMonitor.class.isAssignableFrom(mc)) {
throw new MarshallingResourceFailureException("The monitor for service: "+monitor.getService()+" class-name: "+monitor.getClassName()+" must implement ServiceMonitor");
}
return mc;
}
/**
* <p>getNextOutageIdSql</p>
*
* @return a {@link java.lang.String} object.
*/
public String getNextOutageIdSql() {
getReadLock().lock();
try {
return m_config.getNextOutageId();
} finally {
getReadLock().unlock();
}
}
/**
* <p>releaseAllServiceMonitors</p>
*/
public void releaseAllServiceMonitors() {
getWriteLock().lock();
try {
Iterator<ServiceMonitor> iter = getServiceMonitors().values().iterator();
while (iter.hasNext()) {
ServiceMonitor sm = iter.next();
sm.release();
}
} finally {
getWriteLock().unlock();
}
}
/** {@inheritDoc} */
public void saveResponseTimeData(final String locationMonitor, final OnmsMonitoredService monSvc, final double responseTime, final Package pkg) {
getReadLock().lock();
try {
final String svcName = monSvc.getServiceName();
final Service svc = getServiceInPackage(svcName, pkg);
final String dsName = getServiceParameter(svc, "ds-name");
if (dsName == null) {
return;
}
final String rrdRepository = getServiceParameter(svc, "rrd-repository");
if (rrdRepository == null) {
return;
}
final String rrdDir = rrdRepository+File.separatorChar+"distributed"+File.separatorChar+locationMonitor+File.separator+str(monSvc.getIpAddress());
try {
final File rrdFile = new File(rrdDir, dsName);
if (!rrdFile.exists()) {
RrdUtils.createRRD(locationMonitor, rrdDir, dsName, getStep(pkg), "GAUGE", 600, "U", "U", getRRAList(pkg));
}
RrdUtils.updateRRD(locationMonitor, rrdDir, dsName, System.currentTimeMillis(), String.valueOf(responseTime));
} catch (final RrdException e) {
throw new PermissionDeniedDataAccessException("Unable to store rrdData from "+locationMonitor+" for service "+monSvc, e);
}
} finally {
getReadLock().unlock();
}
}
private String getServiceParameter(final Service svc, final String key) {
for(final Parameter parm : parameters(svc)) {
if (key.equals(parm.getKey())) {
if (parm.getValue() != null) {
return parm.getValue();
} else if (parm.getAnyObject() != null) {
return parm.getAnyObject().toString();
}
}
}
return null;
}
}