Java tutorial
/******************************************************************************* * This file is part of OpenNMS(R). * * Copyright (C) 2006-2012 The OpenNMS Group, Inc. * OpenNMS(R) is Copyright (C) 1999-2012 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.ng.services.collectd; import java.io.File; import java.util.Map; import org.opennms.core.logging.Logging; import org.opennms.core.utils.InetAddressUtils; import org.opennms.netmgt.EventConstants; import org.opennms.netmgt.collectd.BasePersister; import org.opennms.netmgt.collectd.CollectionAgent; import org.opennms.netmgt.collectd.CollectionException; import org.opennms.netmgt.collectd.CollectionFailed; import org.opennms.netmgt.collectd.CollectionInitializationException; import org.opennms.netmgt.collectd.CollectionTimedOut; import org.opennms.netmgt.collectd.CollectionWarning; import org.opennms.netmgt.collectd.GroupPersister; import org.opennms.netmgt.collectd.OneToOnePersister; import org.opennms.netmgt.collectd.ServiceCollector; import org.opennms.netmgt.config.DataCollectionConfigFactory; import org.opennms.netmgt.config.collector.CollectionSet; import org.opennms.netmgt.config.collector.ServiceParameters; import org.opennms.netmgt.eventd.EventIpcManagerFactory; import org.opennms.netmgt.model.OnmsIpInterface; import org.opennms.netmgt.model.RrdRepository; import org.opennms.netmgt.model.events.EventBuilder; import org.opennms.netmgt.threshd.ThresholdingVisitor; import org.opennms.ng.persistence.dao.OnmsIpInterfaceDao; import org.opennms.ng.services.collectd.Collectd.SchedulingCompletedFlag; import org.opennms.ng.services.scheduler.ReadyRunnable; import org.opennms.ng.services.scheduler.Scheduler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.transaction.PlatformTransactionManager; /** * <P> * The CollectableService class ... * </P> * * @author <A HREF="mailto:mike@opennms.org">Mike Davidson </A> * @author <A HREF="http://www.opennms.org/">OpenNMS </A> * */ final class CollectableService implements ReadyRunnable { private static final Logger LOG = LoggerFactory.getLogger(CollectableService.class); /** * Interface's parent node identifier */ private volatile int m_nodeId; /** * Last known/current status */ private volatile int m_status; /** * The last time the collector was scheduled for collection. */ private volatile long m_lastScheduledCollectionTime; /** * The scheduler for collectd */ private final Scheduler m_scheduler; /** * Service updates */ private final CollectorUpdates m_updates; /** * The thresholdvisitor for this collectable service; called */ private final ThresholdingVisitor m_thresholdVisitor; /** * */ private static final boolean ABORT_COLLECTION = true; private final CollectionSpecification m_spec; private final SchedulingCompletedFlag m_schedulingCompletedFlag; private volatile CollectionAgent m_agent; private final PlatformTransactionManager m_transMgr; private final OnmsIpInterfaceDao m_ifaceDao; private final ServiceParameters m_params; private final RrdRepository m_repository; /** * Constructs a new instance of a CollectableService object. * * @param iface The interface on which to collect data * @param spec * The package containing parms for this collectable service. * @param ifaceDao a {@link org.opennms.netmgt.dao.api.IpInterfaceDao} object. * @param scheduler a {@link org.opennms.netmgt.scheduler.Scheduler} object. * @param schedulingCompletedFlag a {@link org.opennms.netmgt.collectd.Collectd.SchedulingCompletedFlag} object. * @param transMgr a {@link org.springframework.transaction.PlatformTransactionManager} object. */ protected CollectableService(OnmsIpInterface iface, OnmsIpInterfaceDao ifaceDao, CollectionSpecification spec, Scheduler scheduler, SchedulingCompletedFlag schedulingCompletedFlag, PlatformTransactionManager transMgr) throws CollectionInitializationException { m_agent = DefaultCollectionAgent.create(iface.getId(), ifaceDao, transMgr); m_spec = spec; m_scheduler = scheduler; m_schedulingCompletedFlag = schedulingCompletedFlag; m_ifaceDao = ifaceDao; m_transMgr = transMgr; m_nodeId = iface.getNode().getId().intValue(); m_status = ServiceCollector.COLLECTION_SUCCEEDED; m_updates = new CollectorUpdates(); m_lastScheduledCollectionTime = 0L; m_spec.initialize(m_agent); Map<String, Object> roProps = m_spec.getReadOnlyPropertyMap(); m_params = new ServiceParameters(roProps); m_repository = m_spec.getRrdRepository(m_params.getCollectionName()); m_thresholdVisitor = ThresholdingVisitor.create(m_nodeId, getHostAddress(), m_spec.getServiceName(), m_repository, roProps); } /** * <p>getAddress</p> * * @return a {@link java.lang.Object} object. */ public Object getAddress() { return m_agent.getAddress(); } /** * <p>getSpecification</p> * * @return a {@link org.opennms.netmgt.collectd.CollectionSpecification} object. */ public CollectionSpecification getSpecification() { return m_spec; } /** * Returns node identifier * * @return a int. */ public int getNodeId() { return m_nodeId; } /** * Returns the service name * * @return a {@link java.lang.String} object. */ public String getServiceName() { return m_spec.getServiceName(); } /** * Returns the package name * * @return a {@link java.lang.String} object. */ public String getPackageName() { return m_spec.getPackageName(); } /** * Returns updates object * * @return a {@link CollectorUpdates} object. */ public CollectorUpdates getCollectorUpdates() { return m_updates; } /** * Uses the existing package name to try and re-obtain the package from the collectd config factory. * Should be called when the collect config has been reloaded. * * @param collectorConfigDao a {@link org.opennms.netmgt.dao.api.CollectorConfigDao} object. */ public void refreshPackage(CollectorConfigDao collectorConfigDao) { m_spec.refresh(collectorConfigDao); if (m_thresholdVisitor != null) m_thresholdVisitor.reloadScheduledOutages(); } /** {@inheritDoc} */ @Override public String toString() { return "CollectableService for service " + m_nodeId + ':' + getAddress() + ':' + getServiceName(); } /** * This method is used to evaluate the status of this interface and service * pair. If it is time to run the collection again then a value of true is * returned. If the interface is not ready then a value of false is * returned. * * @return a boolean. */ @Override public boolean isReady() { boolean ready = false; if (!isSchedulingComplete()) return false; if (m_spec.getInterval() < 1) { ready = true; } else { ready = ((m_spec.getInterval() - (System.currentTimeMillis() - m_lastScheduledCollectionTime)) < 1); } return ready; } private boolean isSchedulingComplete() { return m_schedulingCompletedFlag.isSchedulingCompleted(); } /** * Generate event and send it to eventd via the event proxy. * * uei Universal event identifier of event to generate. */ private void sendEvent(String uei, String reason) { EventBuilder builder = new EventBuilder(uei, "OpenNMS.Collectd"); builder.setNodeid(m_nodeId); builder.setInterface(m_agent.getInetAddress()); builder.setService(m_spec.getServiceName()); builder.setHost(InetAddressUtils.getLocalHostName()); if (reason != null) { builder.addParam("reason", reason); } // Send the event try { EventIpcManagerFactory.getIpcManager().sendNow(builder.getEvent()); LOG.debug("sendEvent: Sent event {} for {}/{}/{}", uei, m_nodeId, getHostAddress(), getServiceName()); } catch (Throwable e) { LOG.error("Failed to send the event {} for interface {}", uei, getHostAddress(), e); } } private String getHostAddress() { return m_agent.getHostAddress(); } /** * This is the main method of the class. An instance is normally enqueued on * the scheduler which checks its <code>isReady</code> method to determine * execution. If the instance is ready for execution then it is started with * it's own thread context to execute the query. The last step in the method * before it exits is to reschedule the interface. */ @Override public void run() { Logging.withPrefix(org.opennms.ng.services.collectd.Collectd.LOG4J_CATEGORY, new Runnable() { @Override public void run() { doRun(); } }); } private void doRun() { // Process any outstanding updates. if (processUpdates() == ABORT_COLLECTION) { LOG.debug( "run: Aborting because processUpdates returned ABORT_COLLECTION (probably marked for deletion) for {}", this); return; } // Update last scheduled poll time m_lastScheduledCollectionTime = System.currentTimeMillis(); /* * Check scheduled outages to see if any apply indicating * that the collection should be skipped. */ if (!m_spec.scheduledOutage(m_agent)) { try { doCollection(); updateStatus(ServiceCollector.COLLECTION_SUCCEEDED, null); } catch (CollectionTimedOut e) { LOG.info(e.getMessage()); updateStatus(ServiceCollector.COLLECTION_FAILED, e); } catch (CollectionWarning e) { LOG.warn(e.getMessage(), e); updateStatus(ServiceCollector.COLLECTION_FAILED, e); } catch (CollectionException e) { LOG.error(e.getMessage(), e); updateStatus(ServiceCollector.COLLECTION_FAILED, e); } catch (Throwable e) { LOG.error(e.getMessage(), e); updateStatus(ServiceCollector.COLLECTION_FAILED, new CollectionException( "Collection failed unexpectedly: " + e.getClass().getSimpleName() + ": " + e.getMessage(), e)); } } // Reschedule the service m_scheduler.schedule(m_spec.getInterval(), getReadyRunnable()); } private void updateStatus(int status, CollectionException e) { // Any change in status? if (status != m_status) { // Generate data collection transition events LOG.debug("run: change in collection status, generating event."); String reason = null; if (e != null) { reason = e.getMessage(); } // Send the appropriate event switch (status) { case ServiceCollector.COLLECTION_SUCCEEDED: sendEvent(EventConstants.DATA_COLLECTION_SUCCEEDED_EVENT_UEI, null); break; case ServiceCollector.COLLECTION_FAILED: sendEvent(EventConstants.DATA_COLLECTION_FAILED_EVENT_UEI, reason); break; default: break; } } // Set the new status m_status = status; } private BasePersister createPersister(ServiceParameters params, RrdRepository repository) { if (Boolean.getBoolean("org.opennms.rrd.storeByGroup")) { return new GroupPersister(params, repository); } else { return new OneToOnePersister(params, repository); } } /** * Perform data collection. */ private void doCollection() throws CollectionException { LOG.info("run: starting new collection for {}/{}/{}", getHostAddress(), m_spec.getServiceName(), m_spec.getPackageName()); CollectionSet result = null; try { result = m_spec.collect(m_agent); if (result != null) { org.opennms.netmgt.collectd.Collectd.instrumentation().beginPersistingServiceData(m_nodeId, getHostAddress(), m_spec.getServiceName()); try { BasePersister persister = createPersister(m_params, m_repository); persister.setIgnorePersist(result.ignorePersist()); result.visit(persister); } finally { Collectd.instrumentation().endPersistingServiceData(m_nodeId, getHostAddress(), m_spec.getServiceName()); } /* * Do the thresholding; this could be made more generic (listeners being passed the collectionset), but frankly, why bother? * The first person who actually needs to configure that sort of thing on the fly can code it up. */ if (m_thresholdVisitor != null) { if (m_thresholdVisitor.isNodeInOutage()) { LOG.info( "run: the threshold processing will be skipped because the node {} is on a scheduled outage.", m_nodeId); } else if (m_thresholdVisitor.hasThresholds()) { result.visit(m_thresholdVisitor); } } if (result.getStatus() != ServiceCollector.COLLECTION_SUCCEEDED) { throw new CollectionFailed(result.getStatus()); } } } catch (CollectionException e) { LOG.warn("run: failed collection for {}/{}/{}", getHostAddress(), m_spec.getServiceName(), m_spec.getPackageName()); throw e; } catch (Throwable t) { LOG.warn("run: failed collection for {}/{}/{}", getHostAddress(), m_spec.getServiceName(), m_spec.getPackageName()); throw new CollectionException("An undeclared throwable was caught during data collection for interface " + getHostAddress() + "/" + m_spec.getServiceName(), t); } LOG.info("run: finished collection for {}/{}/{}", getHostAddress(), m_spec.getServiceName(), m_spec.getPackageName()); } /** * Process any outstanding updates. * * @return true if update indicates that collection should be aborted (for * example due to deletion flag being set), false otherwise. */ private boolean processUpdates() { // All update processing takes place within synchronized block // to ensure that no updates are missed. // synchronized (this) { if (!m_updates.hasUpdates()) return !ABORT_COLLECTION; // Update: deletion flag // if (m_updates.isDeletionFlagSet()) { // Deletion flag is set, simply return without polling // or rescheduling this collector. // LOG.debug("Collector for {} is marked for deletion...skipping collection, will not reschedule.", getHostAddress()); return ABORT_COLLECTION; } OnmsIpInterface newIface = m_updates.isReinitializationNeeded(); // Update: reinitialization flag // if (newIface != null) { // Reinitialization flag is set, call initialize() to // reinit the collector for this interface // LOG.debug("ReinitializationFlag set for {}", getHostAddress()); try { reinitialize(newIface); LOG.debug("Completed reinitializing {} collector for {}/{}", this.getServiceName(), getHostAddress(), m_spec.getServiceName()); } catch (CollectionInitializationException rE) { LOG.warn("Unable to initialize {} for {} collection, reason: {}", getHostAddress(), m_spec.getServiceName(), rE.getMessage()); } catch (Throwable t) { LOG.error("Uncaught exception, failed to intialize interface {} for {} data collection", getHostAddress(), m_spec.getServiceName(), t); } } // Update: reparenting flag // if (m_updates.isReparentingFlagSet()) { LOG.debug("ReparentingFlag set for {}", getHostAddress()); // The interface has been reparented under a different node // (with // a different nodeId). // // If the new directory doesn't already exist simply need to // rename the old // directory: // /opt/OpenNMS/share/rrd/snmp/<oldNodeId> // to the new directory: // /opt/OpenNMS/share/rrd/snmp/<newNodeId> // // Otherwise must iterate over each of the files/dirs in the // <oldNodeId> // directory and move/rename them under the <newNodeId> // directory. // Get path to RRD repository // String rrdPath = DataCollectionConfigFactory.getInstance().getRrdPath(); // Does the <newNodeId> directory already exist? File newNodeDir = new File(rrdPath + File.separator + m_updates.getReparentNewNodeId()); if (!newNodeDir.isDirectory()) { // New directory does not exist yet so simply rename the old // directory to // the new directory. // // <oldNodeId> directory File oldNodeDir = new File(rrdPath + File.separator + m_updates.getReparentOldNodeId()); try { // Rename <oldNodeId> dir to <newNodeId> dir. LOG.debug("Attempting to rename {} to {}", oldNodeDir, newNodeDir); oldNodeDir.renameTo(newNodeDir); LOG.debug("Rename successful!!"); } catch (SecurityException se) { LOG.error("Insufficient authority to rename RRD directory.", se); } catch (Throwable t) { LOG.error("Unexpected exception while attempting to rename RRD directory.", t); } } else { // New node directory already exists so we must move/rename // each of the // old node directory contents under the new node directory. // // Get list of files to be renamed/moved File oldNodeDir = new File(rrdPath + File.separator + m_updates.getReparentOldNodeId()); String[] filesToMove = oldNodeDir.list(); if (filesToMove != null) { // Iterate over the file list and rename/move each one for (int i = 0; i < filesToMove.length; i++) { File srcFile = new File(oldNodeDir.toString() + File.separator + filesToMove[i]); File destFile = new File(newNodeDir.toString() + File.separator + filesToMove[i]); try { LOG.debug("Attempting to move {} to {}", srcFile, destFile); srcFile.renameTo(destFile); } catch (SecurityException se) { LOG.error("Insufficient authority to move RRD files.", se); break; } catch (Throwable t) { LOG.warn("Unexpected exception while attempting to move {} to {}", srcFile, destFile, t); } } } } // Convert new nodeId to integer value int newNodeId = -1; try { newNodeId = Integer.parseInt(m_updates.getReparentNewNodeId()); } catch (NumberFormatException nfE) { LOG.warn("Unable to convert new nodeId value to an int while processing reparenting update: {}", m_updates.getReparentNewNodeId()); } // Set this collector's nodeId to the value of the interface's // new parent nodeid. m_nodeId = newNodeId; // We must now reinitialize the collector for this interface, // in order to update the NodeInfo object to reflect changes // to the interface's parent node among other things. // try { LOG.debug("Reinitializing collector for {}/{}", getHostAddress(), m_spec.getServiceName()); reinitialize(m_updates.getUpdatedInterface()); LOG.debug("Completed reinitializing collector for {}/{}", getHostAddress(), m_spec.getServiceName()); } catch (CollectionInitializationException rE) { LOG.warn("Unable to initialize {} for {} collection, reason: {}", getHostAddress(), m_spec.getServiceName(), rE.getMessage()); } catch (Throwable t) { LOG.error("Uncaught exception, failed to initialize interface {} for {} data collection", getHostAddress(), m_spec.getServiceName(), t); } } // Updates have been applied. Reset CollectorUpdates object. // . m_updates.reset(); } // end synchronized return !ABORT_COLLECTION; } private void reinitialize(OnmsIpInterface newIface) throws CollectionInitializationException { m_spec.release(m_agent); m_agent = DefaultCollectionAgent.create(newIface.getId(), m_ifaceDao, m_transMgr); m_spec.initialize(m_agent); } /** * <p>reinitializeThresholding</p> */ public void reinitializeThresholding() { if (m_thresholdVisitor != null) { LOG.debug("reinitializeThresholding on {}", this); m_thresholdVisitor.reload(); } } /** * <p>getReadyRunnable</p> * * @return a {@link org.opennms.netmgt.scheduler.ReadyRunnable} object. */ public ReadyRunnable getReadyRunnable() { return this; } }