package hudson.plugins.jboss;
import hudson.model.BuildListener;
import java.util.Properties;
import java.util.Set;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.jboss.system.ServiceMBean;
/**
* This utility class contains static methods to help dealing with JBoss Managed Beans.
*
* @author Juliusz Brzostek
*
*/
public class JMXUtils {
/**
* Default constructor.
*/
private JMXUtils() {
// utility class cannot be instantiated
}
/**
* Gets {@link InitialContext} from given server and port.
*
* @param hostName Name of the server connect to
* @param jndiPort Port number of naming service
*
* @return Obtained InitialContext, or RuntimeException will thrown.
*/
public static InitialContext getInitialContext(final String hostName, final int jndiPort) {
Properties env = new Properties();
try {
env.put("java.naming.factory.initial",
"org.jnp.interfaces.NamingContextFactory");
env.put("java.naming.factory.url.pkgs",
"org.jboss.naming:org.jnp.interfaces");
env.put("java.naming.provider.url", hostName + ":" + jndiPort);
return new InitialContext(env);
} catch (NamingException e) {
throw new RuntimeException(
"Unable to instantiate naming context: " + e.getMessage(),
e);
}
}
/**
* Gets Managed Beans server for given naming context.
*
* @param ctx {@link InitialContext} used to lookup.
* @param listener used only for logging purpose
* @param timeout timeout of connection in seconds
*
* @return server connection or exception will thrown if failed
*/
public static MBeanServerConnection getMBeanServer(
final InitialContext ctx, final BuildListener listener, final int timeout) {
MBeanServerConnection server = null;
NamingException ne = null;
int retryWait = 1000;
for (int i = 0; i < timeout; ++i) {
try {
Thread.sleep(retryWait);
server = (MBeanServerConnection) ctx
.lookup("jmx/invoker/RMIAdaptor");
break;
} catch (NamingException e) {
ne = e;
} catch (InterruptedException e) {
listener.getLogger().println(
"Thread interrupted while waiting for MBean connection: "
+ e.getMessage());
return server;
}
}
if (server == null) {
throw new RuntimeException(new StringBuilder().append(
"Unable to get JBoss JMX MBean connection ").append("in ")
.append(timeout).append(" seconds.").toString(), ne);
}
return server;
}
/**
* Checks if Server is up using given MBean server connection.
*
* @param server given {@link MBeanServerConnection}
*
* @return true if server is up, false otherwise
*
* @throws Exception A few types of exception can be thrown.
*/
public static boolean isServerStarted(MBeanServerConnection server) throws Exception {
ObjectName serverMBeanName = new ObjectName("jboss.system:type=Server");
return ((Boolean) server.getAttribute(serverMBeanName, "Started"))
.booleanValue();
}
/**
* Waits for server status.
*
* If server is not started checks status every second for 'timeout'.
*
* @param hostName name of the server connect to
* @param jndiPort port number of naming service
* @param listener {@link BuildListener} for logging purpose
* @param timeout how long will we wait for server start
* @param ignoreErrors if true any connection problems will be ignored
*
* @return true if server is up, false otherwise
*/
public static boolean checkServerStatus(
final String hostName, final int jndiPort,
final BuildListener listener,
final int timeout, boolean ignoreErrors) {
boolean started = false;
try {
InitialContext ctx = getInitialContext(hostName, jndiPort);
MBeanServerConnection server = getMBeanServer(ctx, listener, timeout);
// Wait until server startup is complete
long startTime = System.currentTimeMillis();
while (!started
&& (System.currentTimeMillis() - startTime < timeout * 1000)) {
try {
Thread.sleep(1000);
started = isServerStarted(server);
} catch (Exception e) {
throw new RuntimeException("Unable to wait: " + e.getMessage(),
e);
}
}
} catch (RuntimeException e) {
if (!ignoreErrors) {
throw e;
}
}
return started;
}
/**
* Checks if given modules have been correctly deployed.
*
* @param hostName name of the server connect to
* @param jndiPort port number of naming service
* @param listener {@link BuildListener} for logging purpose
* @param timeout how long will we wait for server start
*
* @return true if gone fine, false if any module have deployment problem
*/
public static boolean checkDeploy(final String hostName,
final int jndiPort, final BuildListener listener,
final int timeout, final String[] modules) {
listener.getLogger().println("Verification of deplyed modules started");
InitialContext ctx = getInitialContext(hostName, jndiPort);
MBeanServerConnection server = getMBeanServer(ctx, listener, timeout);
boolean deployed = true;
for (String moduleName : modules) {
if (moduleName.endsWith(".ear")) {
boolean ok = checkEARDeploymentState(listener, server, moduleName);
listener.getLogger().println(
String.format("Verifying deployment of the EAR '%s' ... %s",
moduleName, ok?"SUCCESS":"FAILED"));
deployed &= ok;
} else if (moduleName.endsWith("-ejb.jar")) {
boolean ok = checkEJBDeploymentState(listener, server, moduleName);
listener.getLogger().println(
String.format("Verifying deployment of the EJB '%s' ... %s",
moduleName, ok?"SUCCESS":"FAILED"));
deployed &= ok;
} else if (moduleName.endsWith(".war")) {
boolean ok = checkWARDeploymentState(listener, server, moduleName);
listener.getLogger().println(
String.format("Verifying deployment of the WAR '%s' ... %s",
moduleName, ok?"SUCCESS":"FAILED"));
deployed &= ok;
} else {
listener.error(
String.format("Unknown type of the module '%s'. Cannot verify deployment.", moduleName));
deployed = false;
}
}
listener.getLogger().println("Verification finished.");
return deployed;
}
/**
* Checks if single WAR is deployed with no problems.
* To check other states take a look on {@link ServiceMBean}.
*
* @param listener for logging purpose
* @param server given {@link MBeanServerConnection}
* @param warName the name of the WAR to be checked
*
* @return true if started, false otherwise
*/
public static boolean checkWARDeploymentState(
final BuildListener listener,
MBeanServerConnection server, String warName) {
try {
String objectPattern = String.format("jboss.web.deployment:*,war=%s", warName);
@SuppressWarnings("unchecked")
Set<ObjectName> set = server.queryNames(new ObjectName(objectPattern), null);
if (set == null || set.size() == 0) {
return false; // no instance
}
ObjectName serverMBeanName = set.iterator().next(); // only first
return ServiceMBean.STARTED == (Integer) server.getAttribute(serverMBeanName, "State");
} catch (Exception e) {
return false;
}
}
/**
* Checks if single EAR is deployed with no problems.
* To check other states take a look on {@link ServiceMBean}.
*
* @param listener for logging purpose
* @param server given {@link MBeanServerConnection}
* @param earName the name of the EAR to be checked
*
* @return true if started, false otherwise
*/
public static boolean checkEARDeploymentState(
final BuildListener listener,
MBeanServerConnection server, String earName) {
try {
ObjectName serverMBeanName = new ObjectName(
String.format("jboss.j2ee:service=EARDeployment,url='%s'", earName));
return ServiceMBean.STARTED == (Integer) server.getAttribute(serverMBeanName, "State");
} catch (Exception e) {
return false;
}
}
/**
* Checks if single EJB module is deployed with no problems.
* To check other states take a look on {@link ServiceMBean}.
*
* @param listener for logging purpose
* @param server given {@link MBeanServerConnection}
* @param ejbName the name of the EJB module to be checked
*
* @return true if started, false otherwise
*/
public static boolean checkEJBDeploymentState(
final BuildListener listener,
MBeanServerConnection server, String ejbName) {
try {
ObjectName serverMBeanName = new ObjectName(
String.format("jboss.j2ee:service=EjbModule,module=%s", ejbName));
return ServiceMBean.STARTED == (Integer) server.getAttribute(serverMBeanName, "State");
} catch (Exception e) {
return false;
}
}
}