/*
* RHQ Management Platform
* Copyright (C) 2005-2013 Red Hat, Inc.
* All rights reserved.
*
* This program 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 version 2 of the License.
*
* This program 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 this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
package org.rhq.core.pc.content;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rhq.core.clientapi.server.content.ContentDiscoveryReport;
import java.util.concurrent.Callable;
/**
* Thread run by the {@link ContentManager} to perform content discoveries. Much of the logic in these discoveries takes
* place in that manager; this is largely just a <code>Runnable</code> implementation in order to thread the
* discoveries.
*
* @author Jason Dobies
*/
public class ContentDiscoveryRunner implements Runnable, Callable<ContentDiscoveryReport> {
private static final Log LOG = LogFactory.getLog(ContentDiscoveryRunner.class);
// Attributes --------------------------------------------
/**
* If specified, this constrains this instance to running the described discovery. If this is not present, this
* class will ask the manager for the next discovery to run.
*/
private ScheduledContentDiscoveryInfo discoveryInfo;
/**
* Indicates the execution of this runner is intended for a one time execution. In other words, any scheduling logic
* should not be performed.
*/
private boolean oneTimeDiscovery;
/**
* Hook into the content manager to perform the content handling logic.
*/
private ContentManager contentManager;
// Constructors --------------------------------------------
/**
* Creates a new runner that will contact the manager to determine the next piece of scheduled content work that
* needs to take place.
*
* @param contentManager hook to the manager
*/
public ContentDiscoveryRunner(ContentManager contentManager) {
this.contentManager = contentManager;
this.discoveryInfo = null;
this.oneTimeDiscovery = false;
}
/**
* Creates a new runner that will be scoped to performing the specified discovery.
*
* @param contentManager hook to the manager
* @param discoveryInfo specific discovery to perform
*/
public ContentDiscoveryRunner(ContentManager contentManager, ScheduledContentDiscoveryInfo discoveryInfo) {
this.contentManager = contentManager;
this.discoveryInfo = discoveryInfo;
this.oneTimeDiscovery = true;
}
// Runnable Implementation --------------------------------------------
public void run() {
try {
call();
} catch (Exception e) {
LOG.error("Content discovery runner failed", e);
}
}
// Callable Implementation --------------------------------------------
public ContentDiscoveryReport call() throws Exception {
ScheduledContentDiscoveryInfo info = this.discoveryInfo;
// If this instance is not scoped to a particular discovery, get the next discovery chunk of work from the manager
if (info == null) {
info = this.contentManager.getNextScheduledDiscovery();
// If there is still no discovery waiting to happen, do nothing
if (info == null) {
return null;
}
// Check to see if the discovery is executing too far past its next scheduled discovery
// If it is, skip this discovery and increment its next discovery.
if ((System.currentTimeMillis() - 120000L) > info.getNextDiscovery()) {
LOG.debug("Content discovery is falling behind. Missed discovery for " + info + " by: "
+ (System.currentTimeMillis() - info.getNextDiscovery()) + "ms");
}
}
if (LOG.isDebugEnabled()) {
LOG.debug("Performing discovery: " + info);
}
// Catch any error that may occur on the plugin
ContentDiscoveryReport result = null;
try {
result = contentManager.performContentDiscovery(info.getResourceId(), info.getPackageType());
} catch (Throwable throwable) {
LOG.warn("Exception received from component while attempting content retrieval", throwable);
} finally {
// Reschedule after this report has been sent (or failed). Putting this here will delay further discoveries
// if the limited concurrency puts off sending this message for a while.
if (!oneTimeDiscovery) {
contentManager.rescheduleDiscovery(info);
}
}
return result;
}
}