package net.sourceforge.cruisecontrol.jmx;
import net.sourceforge.cruisecontrol.CruiseControlException;
import net.sourceforge.cruisecontrol.builders.DistributedMasterBuilder;
import net.sourceforge.cruisecontrol.distributed.util.BuildAgentUtility;
import net.sourceforge.cruisecontrol.distributed.BuildAgentService;
import net.jini.core.lookup.ServiceRegistrar;
import net.jini.core.lookup.ServiceItem;
import java.util.List;
import java.util.ArrayList;
import java.util.Arrays;
import java.rmi.RemoteException;
import org.apache.log4j.Logger;
/**
* @author Dan Rollo
* Date: Sep 25, 2008
* Time: 12:06:08 AM
*/
public class JMXBuildAgentUtility implements JMXBuildAgentUtilityMBean {
private static final Logger LOG = Logger.getLogger(JMXBuildAgentUtility.class);
private static final BuildAgentUtility AGENT_UTIL_SINGLETON = BuildAgentUtility.createForJMX();
private boolean isAfterBuildFinished = true;
private final List<ServiceRegistrar> lstRegistrars = new ArrayList<ServiceRegistrar>();
private final List<String> lusIds = new ArrayList<String>();
private List<ServiceItem> lstServiceItems = new ArrayList<ServiceItem>();
private List<String> agentServiceIds = new ArrayList<String>();
private String agentInfoAll;
private long lastRefreshTime;
// @todo make refresh timeout configurable
private final long refreshTimeout = (BuildAgentUtility.LUS_WAIT_SECONDS + 1) * 1000;
private void tryRefreshAgentList() throws RemoteException {
// don't refresh until 5 seconds have elapsed since last refresh
if ((System.currentTimeMillis() - lastRefreshTime) > refreshTimeout) {
doRefresh();
} else {
LOG.debug("Skipping JMX Agent Util refresh, using cached agent info. timeout(millis): " + refreshTimeout);
}
}
private void doRefresh() throws RemoteException {
LOG.debug("JMX Agent Util refreshing...");
lstServiceItems = new ArrayList<ServiceItem>();
agentInfoAll = AGENT_UTIL_SINGLETON.getAgentInfoAll(lstServiceItems);
agentServiceIds = new ArrayList<String>();
for (ServiceItem serviceItem : lstServiceItems) {
agentServiceIds.add(
((BuildAgentService) serviceItem.service).getMachineName()
+ ": " + serviceItem.serviceID);
}
// build list of LUS's after the above call to AGENT_UTIL_SINGLETON.getAgentInfoAll() to have recent data
final ServiceRegistrar[] registrars = AGENT_UTIL_SINGLETON.getValidRegistrars();
lstRegistrars.clear();
lstRegistrars.addAll(Arrays.asList(registrars));
lusIds.clear();
for (final ServiceRegistrar lus : registrars) {
lusIds.add(lus.getLocator().getHost() + ": "
+ lus.getServiceID().toString());
}
lastRefreshTime = System.currentTimeMillis();
LOG.debug("JMX Agent Util refresh complete.");
}
public void refresh() throws RemoteException {
doRefresh();
}
public int getLookupServiceCount() throws RemoteException {
tryRefreshAgentList();
return AGENT_UTIL_SINGLETON.getLastLUSCount();
}
public String[] getLUSServiceIds() throws RemoteException {
tryRefreshAgentList();
return lusIds.toArray(new String[lusIds.size()]);
}
public void destroyLUS(final String lusServiceId) throws RemoteException, CruiseControlException {
final ServiceRegistrar lus = findLUSViaServiceId(lusServiceId);
if (lus != null) {
LOG.debug("JMXBuildAgentUtility : LUS to destroy: " + lus.toString());
// @todo Find a better way to get jini.httpPort sys prop set in main CC vm from cruise.properties
DistributedMasterBuilder.loadJiniHttpPortIfNeeded();
try {
AGENT_UTIL_SINGLETON.destroyLookupService(lus);
} catch (RemoteException e) {
LOG.error("Error killing LookupService via JMX", e);
throw e;
} catch (Exception e) {
LOG.error("Error killing LookupService via JMX", e);
throw new CruiseControlException(e);
}
}
}
public String getBuildAgents() throws RemoteException {
tryRefreshAgentList();
return agentInfoAll;
}
public String[] getBuildAgentServiceIds() throws RemoteException {
tryRefreshAgentList();
return agentServiceIds.toArray(new String[agentServiceIds.size()]);
}
public boolean isKillOrRestartAfterBuildFinished() { return isAfterBuildFinished; }
public void setKillOrRestartAfterBuildFinished(final boolean afterBuildFinished) {
isAfterBuildFinished = afterBuildFinished;
}
public void kill(final String agentServiceId) throws RemoteException, CruiseControlException {
final BuildAgentService buildAgentService = findAgentViaServiceId(agentServiceId);
if (buildAgentService != null) {
try {
buildAgentService.kill(isAfterBuildFinished);
} catch (RemoteException e) {
LOG.error("Error killing Agent via JMX", e);
throw e;
} catch (Exception e) {
LOG.error("Error killing Agent via JMX", e);
throw new CruiseControlException(e);
}
}
}
public void killAll() throws CruiseControlException {
for (ServiceItem serviceItem : lstServiceItems) {
try {
kill(serviceItem.serviceID.toString());
} catch (RemoteException e) {
LOG.error("Error killing Agent via JMX", e);
}
}
}
public void restart(final String agentServiceId) throws RemoteException, CruiseControlException {
final BuildAgentService buildAgentService = findAgentViaServiceId(agentServiceId);
if (buildAgentService != null) {
try {
buildAgentService.restart(isAfterBuildFinished);
} catch (RemoteException e) {
final String msg = BuildAgentUtility.checkRestartRequiresWebStart(e);
if (msg != null) {
LOG.error(msg, e);
} else {
LOG.error("Error restarting Agent via JMX", e);
}
throw e;
} catch (Exception e) {
LOG.error("Error killing Agent via JMX", e);
throw new CruiseControlException(e);
}
}
}
public void restartAll() throws CruiseControlException {
for (ServiceItem serviceItem : lstServiceItems) {
try {
restart(serviceItem.serviceID.toString());
} catch (RemoteException e) {
final String msg = BuildAgentUtility.checkRestartRequiresWebStart(e);
if (msg != null) {
LOG.error(msg, e);
} else {
LOG.error("Error restarting Agent via JMX", e);
}
}
}
}
static final String MSG_NULL_SERVICEID = "ServiceId must not be null";
private static String validateServiceId(final String agentServiceId) {
if (agentServiceId == null) {
throw new IllegalArgumentException(MSG_NULL_SERVICEID);
}
return agentServiceId.trim(); // JMX page can add spaces to values sent
}
private BuildAgentService findAgentViaServiceId(final String serviceIdUnTrimmed) {
final String serviceId = validateServiceId(serviceIdUnTrimmed);
for (ServiceItem serviceItem : lstServiceItems) {
if (serviceItem.serviceID.toString().equals(serviceId)) {
return (BuildAgentService) serviceItem.service;
}
}
LOG.error("JMXBuildAgentUtility : Could not find Agent via serviceID: " + serviceId);
return null;
}
private ServiceRegistrar findLUSViaServiceId(final String serviceIdUnTrimmed) {
final String serviceId = validateServiceId(serviceIdUnTrimmed);
for (ServiceRegistrar lus : lstRegistrars) {
if (lus.getServiceID().toString().equals(serviceId)) {
return lus;
}
}
LOG.error("JMXBuildAgentUtility : Could not find LookupService via serviceID: " + serviceId);
return null;
}
}