blob: 524bfc5abdcd0e3eb56e6edfe1ba2b5fda2ee8f3 [file] [log] [blame]
package org.eclipse.virgo.test.tools;
import static java.time.Instant.now;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.time.Duration;
import java.time.Instant;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.management.AttributeNotFoundException;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanException;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;
import org.eclipse.virgo.util.io.NetUtils;
// TODO - rework static usage of virgoHome
public class JmxUtils {
public static File virgoHome;
private static final Duration HALF_SECOND = Duration.ofMillis(500);
private static final Duration THIRTY_SECONDS = Duration.ofSeconds(30);
private static final Duration TWO_MINUTES = Duration.ofMinutes(2);
private static final String ARTIFACT_BUNDLE = "bundle";
private static MBeanServerConnection connection = null;
private final static int JMX_DEFAULT_PORT = 9875;
private static final String JMXURL = "service:jmx:rmi:///jndi/rmi://localhost:" + JMX_DEFAULT_PORT + "/jmxrmi";
private static final String KEYSTORE = "/configuration/keystore";
private static final String KEYPASSWORD = "changeit";
private static final String DEPLOYER_MBEAN_NAME = "org.eclipse.virgo.kernel:category=Control,type=Deployer";
private static final String[] DEPLOYMENT_IDENTITY_FIELDS = new String[] { "type", "symbolicName", "version" };
private final static String STATUS_STARTED = "STARTED";
private final static String STATUS_STARTING = "STARTING";
public static boolean isDefaultJmxPortAvailable() {
return NetUtils.isPortAvailable(JMX_DEFAULT_PORT);
}
public static boolean isKernelStarted() {
return JmxUtils.STATUS_STARTED.equals(getKernelStatus());
}
public static boolean waitForVirgoServerStartFully() throws Exception {
Instant start = Instant.now();
while (start.plus(THIRTY_SECONDS).isAfter(Instant.now())) {
try {
String currentKernelStatus = getKernelStatus();
System.out.println("Current kernel status: '" + currentKernelStatus + "'");
switch (currentKernelStatus) {
case STATUS_STARTED:
// wait for startup to complete
SECONDS.sleep(15);
return true;
case STATUS_STARTING:
default:
break;
}
} catch (IllegalStateException e) {
// ignore JMX related exception and try again?
}
SECONDS.sleep(1);
}
// startup failed
return false;
}
public static boolean waitForVirgoServerShutdownFully() throws Exception {
Instant start = now();
while (start.plus(THIRTY_SECONDS).isAfter(now())) {
if (isDefaultJmxPortAvailable()) {
// allow some more time to finish shutdown
SECONDS.sleep(5);
return true;
}
try {
String currentKernelStatus = getKernelStatus();
System.out.println("Current kernel status: '" + currentKernelStatus + "'");
if (!getKernelStatus().equals(STATUS_STARTED)) {
}
} catch (IllegalStateException e) {
// ignore JMX related exception and try again?
}
SECONDS.sleep(1);
}
// shutdown failed
return false;
}
public static void waitForMBean(String mBeanName) throws Exception {
waitForMBean(mBeanName, HALF_SECOND, TWO_MINUTES);
}
public static void waitForMBean(String mBeanName, Duration sleepDuration, Duration duration) throws Exception {
Instant start = Instant.now();
boolean mbeanStatus = false;
while (start.plus(duration).isAfter(Instant.now())) {
try {
ObjectName objectName = new ObjectName(mBeanName);
System.out.println("Looking for JMX object '" + objectName + "'");
mbeanStatus = getMBeanServerConnection().isRegistered(objectName);
if (mbeanStatus) {
return;
}
} catch (IOException e) {
// swallow and retry - No JMX server available (yet)
}
Thread.sleep(sleepDuration.toMillis());
}
fail(String.format("After %d s and %d ns, artifact %s mbean Status was", duration.getSeconds(), duration.getNano(), mBeanName) + mbeanStatus);
}
public static void waitForArtifactInUserRegion(String type, String name, String version, long interval, long duration) throws Exception {
long startTime = System.currentTimeMillis();
boolean mbeanStatus = false;
while (System.currentTimeMillis() - startTime < duration) {
try {
ObjectName objectName = getObjectName(type, name, version);
System.out.println("Looking for JMX object '" + objectName + "'");
mbeanStatus = getMBeanServerConnection().isRegistered(objectName);
if (mbeanStatus) {
return;
}
} catch (IOException e) {
// swallow and retry
}
Thread.sleep(interval);
}
fail(String.format("After %d ms, artifact %s mbean Status was", duration, name) + mbeanStatus);
}
public static void waitForArtifactInKernelRegion(String type, String name, String version, long interval, long duration) throws Exception {
long startTime = System.currentTimeMillis();
boolean mbeanStatus = false;
while (System.currentTimeMillis() - startTime < duration) {
try {
ObjectName objectName = getObjectNameInKernelRegion(type, name, version);
System.out.println("Looking for JMX object '" + objectName + "'");
mbeanStatus = getMBeanServerConnection().isRegistered(objectName);
if (mbeanStatus) {
return;
}
} catch (IOException e) {
// swallow and retry
}
Thread.sleep(interval);
}
fail(String.format("After %d ms, artifact %s mbean Status was", duration, name) + mbeanStatus);
}
public static MBeanServerConnection getMBeanServerConnection() throws IOException {
String severDir = null;
String[] creds = { "admin", "admin" };
Map<String, String[]> env = new HashMap<String, String[]>();
try {
severDir = virgoHome.getCanonicalPath();
} catch (IOException e) {
throw new IllegalStateException("Failed to get canonical path of server directory '" + virgoHome + "'.");
}
env.put(JMXConnector.CREDENTIALS, creds);
System.setProperty("javax.net.ssl.trustStore", severDir + KEYSTORE);
System.setProperty("javax.net.ssl.trustStorePassword", KEYPASSWORD);
JMXServiceURL url;
try {
url = new JMXServiceURL(JMXURL);
connection = JMXConnectorFactory.connect(url, env).getMBeanServerConnection();
} catch (MalformedURLException e) {
throw new IllegalStateException("Failed to create JMX connection to '" + JMXURL + "'.", e);
}
return connection;
}
public static ObjectName getObjectName(String type, String name, String version) throws MalformedObjectNameException {
return new ObjectName(String.format(
"org.eclipse.virgo.kernel:type=ArtifactModel,artifact-type=%s,name=%s,version=%s,region=org.eclipse.virgo.region.user", type, name,
version));
}
public static ObjectName getObjectNameInKernelRegion(String type, String name, String version) throws MalformedObjectNameException {
return new ObjectName(String.format(
"org.eclipse.virgo.kernel:type=ArtifactModel,artifact-type=%s,name=%s,version=%s,region=org.eclipse.equinox.region.kernel", type, name,
version));
}
public static void deploy(File uploadedFile) throws Exception {
deploy(java.util.Collections.singletonList(uploadedFile));
}
public static void deploy(List<File> uploadedFiles) throws Exception {
waitForMBean(DEPLOYER_MBEAN_NAME, HALF_SECOND, TWO_MINUTES);
ObjectName objectName = new ObjectName(DEPLOYER_MBEAN_NAME);
for (File file : uploadedFiles) {
URI uri = file.toURI();
System.out.println("Deploying file '" + uri + "' on '" + objectName + "'");
Object invoke = getMBeanServerConnection().invoke(objectName, "deploy", new Object[] { uri.toString() },
new String[] { String.class.getName() });
getDeploymentIdentity(invoke);
}
}
// Taken from org.eclipse.virgo.management.console.UploadServlet.getDeploymentIdentity()
private static String getDeploymentIdentity(Object deploymentIdentity) {
StringBuilder builder = new StringBuilder();
if (deploymentIdentity instanceof CompositeDataSupport) {
CompositeDataSupport deploymentIdentityInstance = (CompositeDataSupport) deploymentIdentity;
Object[] all = deploymentIdentityInstance.getAll(DEPLOYMENT_IDENTITY_FIELDS);
builder.append(all[0]);
builder.append(" - ").append(all[1]);
builder.append(": ").append(all[2]);
}
return builder.toString();
}
public static void waitForArtifactState(String type, String name, String version, String state, long interval, long duration) throws Exception {
long startTime = System.currentTimeMillis();
String artifactstate = null;
while (System.currentTimeMillis() - startTime < duration) {
artifactstate = getMBeanServerConnection().getAttribute(getObjectName(type, name, version), "State").toString();
if (artifactstate.equals(state)) {
return;
}
Thread.sleep(interval);
}
fail(String.format("After %d ms, artifact %s state was", duration, name) + artifactstate);
}
public static void assertArtifactExists(String type, String name, String version) throws Exception {
assertTrue(String.format("Artifact %s:%s:%s does not exist", type, name, version),
getMBeanServerConnection().isRegistered(JmxUtils.getObjectName(type, name, version)));
}
public static void assertBundleArtifactExists(String name, String version) throws Exception {
assertTrue(String.format("Artifact %s:%s:%s does not exist", ARTIFACT_BUNDLE, name, version),
getMBeanServerConnection().isRegistered(JmxUtils.getObjectName(ARTIFACT_BUNDLE, name, version)));
}
public static void assertBundleArtifactExistsInKernelRegion(String name, String version) throws Exception {
assertTrue(String.format("Artifact %s:%s:%s does not exist", ARTIFACT_BUNDLE, name, version),
getMBeanServerConnection().isRegistered(JmxUtils.getObjectNameInKernelRegion(ARTIFACT_BUNDLE, name, version)));
}
public static void assertBundleArtifactState(String name, String version, String state) throws Exception {
assertArtifactState(ARTIFACT_BUNDLE, name, version, state);
}
public static void assertBundleArtifactStateInKernelRegion(String name, String version, String state) throws Exception {
assertArtifactStateInKernelRegion(ARTIFACT_BUNDLE, name, version, state);
}
public static void assertArtifactState(String type, String name, String version, String state) throws Exception {
assertEquals(String.format("admin console plan artifact %s:%s:%s is not in state %s", type, name, version, state), state,
getMBeanServerConnection().getAttribute(JmxUtils.getObjectName(type, name, version), "State"));
}
public static void assertArtifactStateInKernelRegion(String type, String name, String version, String state) throws Exception {
assertEquals(String.format("admin console plan artifact %s:%s:%s is not in state %s", type, name, version, state), state,
getMBeanServerConnection().getAttribute(JmxUtils.getObjectNameInKernelRegion(type, name, version), "State"));
}
public static void uninstall(String type, String name, String version) throws Exception {
getMBeanServerConnection().invoke(getObjectName(type, name, version), "uninstall", new Object[] {}, new String[] {});
}
public static String getKernelStatus() {
try {
return (String) getMBeanServerConnection().getAttribute(new ObjectName("org.eclipse.virgo.kernel:type=KernelStatus"), "Status");
} catch (AttributeNotFoundException e) {
throw new IllegalStateException("Failed to get server status.", e);
} catch (InstanceNotFoundException e) {
throw new IllegalStateException("Failed to get server status.", e);
} catch (MalformedObjectNameException e) {
throw new IllegalStateException("Failed to get server status.", e);
} catch (MBeanException e) {
throw new IllegalStateException("Failed to get server status.", e);
} catch (ReflectionException e) {
throw new IllegalStateException("Failed to get server status.", e);
} catch (IOException e) {
throw new IllegalStateException("Failed to get server status.", e);
}
}
}