package org.radargun.jmx;
import java.net.InetSocketAddress;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import org.radargun.logging.Log;
import org.radargun.logging.LogFactory;
import org.radargun.utils.TimeService;
/**
*
* JMXClusterValidator for Oracle Coherence
*
* @author Michal Linhard <mlinhard@redhat.com>
*
*/
public class CoherenceJMXClusterValidator implements JMXClusterValidator {
private static final Log log = LogFactory.getLog(CoherenceJMXClusterValidator.class);
private static final String OBJ_CLUSTER = "Coherence:type=Cluster";
private static final String ATTR_CLUSTER_SIZE = "ClusterSize";
private static final String ATTR_MEMBERS = "Members";
public static class ClusterStatus {
public int numAvailableNodes;
public int numMembers;
public Set<String> partitions;
public ClusterStatus(int numAvailableNodes, int numMembers, Set<String> partitions) {
super();
this.numAvailableNodes = numAvailableNodes;
this.numMembers = numMembers;
this.partitions = partitions;
}
}
private class CoherenceJMXPoller extends JMXPoller {
public CoherenceJMXPoller(List<InetSocketAddress> jmxEndpoints, long queryTimeout, String serviceUrlTemplate) {
super(jmxEndpoints, queryTimeout, serviceUrlTemplate);
}
public CoherenceJMXPoller(List<InetSocketAddress> jmxEndpoints, long queryTimeout) {
super(jmxEndpoints, queryTimeout);
}
public ClusterStatus checkStatus() {
List<Result> pollResults = poll();
Set<String> partitions = new HashSet<String>();
int numAvailableNodes = 0;
int numMembers = -1;
boolean numMembersEqual = true;
log.trace("Number of results of polling: " + pollResults.size());
for (int j = 0; j < pollResults.size(); j++) {
Result r = pollResults.get(j);
Object[] tuple = (Object[]) r.value;
if (tuple != null) {
partitions.add((String) tuple[0]);
numAvailableNodes++;
if (numMembers == -1) {
numMembers = (Integer) tuple[1];
} else {
if (numMembers != (Integer) tuple[1]) {
numMembersEqual = false;
}
}
} else {
if (log.isTraceEnabled()) {
if (r.connectError != null) {
log.trace("Connection error", r.connectError);
}
if (r.pollError != null) {
log.trace("Polling error", r.pollError);
}
}
}
}
return new ClusterStatus(numAvailableNodes, (numMembersEqual ? numMembers : -1), partitions);
}
protected Object[] pollNode(MBeanServerConnection connection, String node, int nodeIdx) throws Exception {
ObjectName clusterObj = new ObjectName(OBJ_CLUSTER);
Integer clusterSize = (Integer) connection.getAttribute(clusterObj, ATTR_CLUSTER_SIZE);
String members = Arrays.asList((String[]) connection.getAttribute(clusterObj, ATTR_MEMBERS)).toString();
return new Object[] {members, clusterSize};
}
}
private List<InetSocketAddress> endpoints;
private long jmxConnectionTimeout;
@Override
public void init(List<InetSocketAddress> slaveAddresses, long jmxConnectionTimeout, String prop1, String prop2,
String prop3) {
this.endpoints = slaveAddresses;
this.jmxConnectionTimeout = jmxConnectionTimeout;
}
@Override
public boolean waitUntilClusterFormed(long timeout) {
if (timeout < 0) {
log.info("Skipping waiting for cluster");
return true;
}
CoherenceJMXPoller poller = null;
try {
poller = new CoherenceJMXPoller(endpoints, jmxConnectionTimeout);
long giveUpTime = TimeService.currentTimeMillis() + timeout;
ClusterStatus status = poller.checkStatus();
boolean formed = false;
while (!(formed = isClusterFormed(status, endpoints.size())) && TimeService.currentTimeMillis() < giveUpTime) {
if (log.isDebugEnabled()) {
log.debug("Cluster incomplete: " + getDebugStatus(status));
}
Thread.sleep(1000);
status = poller.checkStatus();
}
if (formed) {
log.info("Cluster formed: " + status.partitions.iterator().next());
} else {
log.error("Cluster failed to form, last status: " + getDebugStatus(status));
}
return formed;
} catch (Exception e) {
log.error("Error while waiting for cluster formation", e);
return false;
} finally {
if (poller != null) {
poller.closeConnections();
}
}
}
private boolean isClusterFormed(ClusterStatus status, int expectedClusterSize) {
return status.numAvailableNodes == expectedClusterSize && status.numMembers == expectedClusterSize && status.partitions.size() == 1;
}
private String getDebugStatus(ClusterStatus status) {
StringBuffer s = new StringBuffer("Available nodes: ");
s.append(status.numAvailableNodes);
s.append("\nCurrent views:\n\n");
for (String view : status.partitions) {
s.append(view);
s.append("\n");
}
s.append("\n");
return s.toString();
}
}