/*
* 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.plugins.jbosscache3.test;
import java.io.File;
import java.lang.reflect.Method;
import java.util.Properties;
import java.util.Set;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import org.jboss.deployers.spi.management.deploy.DeploymentManager;
import org.jboss.deployers.spi.management.deploy.DeploymentProgress;
import org.jboss.deployers.spi.management.deploy.DeploymentStatus;
import org.rhq.core.clientapi.agent.metadata.PluginMetadataManager;
import org.rhq.core.domain.configuration.Configuration;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.resource.ResourceType;
import org.rhq.core.pc.PluginContainer;
import org.rhq.core.pc.inventory.InventoryManager;
import org.rhq.core.pc.inventory.ResourceContainer;
import org.rhq.core.pc.util.ComponentUtil;
import org.rhq.core.pc.util.FacetLockType;
import org.rhq.plugins.jbossas5.ProfileServiceComponent;
/**
* Various application server related utility methods used by the tests.
*
* @author Lukas Krejci
*/
public class AppServerUtils {
public static final String PLUGIN_NAME = "JBossAS5";
public static final String APPLICATION_SERVER_RESOURCE_NAME = "JBossAS Server";
public static final int DEPLOY_CONTENT_TIMEOUT = 30000; // 30s
private AppServerUtils() {
}
/**
* Deploys an archive to the AS and starts it.
*
* @param name
* the name of the archive
* @param archiveFile
* the archive file
* @param exploded
* whether to deploy exploded or not
* @throws Exception
*/
public static void deployFileToAS(String name, File archiveFile,
boolean exploded) throws Exception {
DeploymentManager deploymentManager = getDeploymentManager();
DeploymentProgress progress = deploymentManager.distribute(name,
archiveFile.toURI().toURL(), exploded);
progress.run();
DeploymentStatus status = progress.getDeploymentStatus();
if (status.isFailed()) {
throw new IllegalStateException("Failed to distribute "
+ archiveFile.getAbsolutePath() + " with message: "
+ status.getMessage());
}
String[] deploymentNames = progress.getDeploymentID()
.getRepositoryNames();
progress = deploymentManager.start(deploymentNames);
progress.run();
status = progress.getDeploymentStatus();
if (status.isFailed()) {
throw new IllegalStateException("Failed to start "
+ archiveFile.getAbsolutePath() + " with message: "
+ status.getMessage());
}
}
/**
* Undeploys an archive of given name from the AS
*
* @param archiveName
* @throws Exception
*/
public static void undeployFromAS(String archiveName) throws Exception {
DeploymentManager deploymentManager = getDeploymentManager();
DeploymentProgress progress = deploymentManager.remove(archiveName);
progress.run();
DeploymentStatus status = progress.getDeploymentStatus();
if (status.isFailed()) {
throw new IllegalStateException("Failed to undeploy " + archiveName
+ " with message: " + status.getMessage());
}
}
/**
* @return The application server resource from the plugin container's
* inventory.
*
* @throws IllegalStateException
* if there is none or more than 1 app servers in the plugin
* container's inventory.
*/
public static Resource getASResource() {
PluginMetadataManager pluginMetadataManager = PluginContainer
.getInstance().getPluginManager().getMetadataManager();
ResourceType appServerResourceType = pluginMetadataManager.getType(
APPLICATION_SERVER_RESOURCE_NAME, PLUGIN_NAME);
InventoryManager inventoryManager = PluginContainer.getInstance()
.getInventoryManager();
Set<Resource> appServers = inventoryManager
.getResourcesWithType(appServerResourceType);
if (appServers.size() != 1) {
throw new IllegalStateException(
"Expected to find exactly 1 AS5 server, but found "
+ appServers.size() + " instead.");
}
return appServers.iterator().next();
}
/**
* Returns the application server component proxy with given interface.
* <p>
* The proxy is created using the AS component classloader and therefore
* cannot be directly cast to the facetInterface, which is most probably
* loaded in a different classloader.
* <p>
* The return type is therefore an object and you have to use reflection to
* work with it.
*
* @param <T>
* @param facetInterface
* the proxy interface class to hide the application server
* component behind
* @return the proxy
* @throws Exception
*/
public static <T> Object getASComponentProxy(Class<T> facetInterface)
throws Exception {
ClassLoader currenContextClassLoader = Thread.currentThread()
.getContextClassLoader();
try {
Resource asResource = getASResource();
ClassLoader cl = PluginContainer.getInstance()
.getPluginComponentFactory().getResourceClassloader(
asResource);
Class<?> resourceSpecificFacetInterface = Class.forName(
facetInterface.getName(), true, cl);
// use the resource specific classloader for the proxy creation
Thread.currentThread().setContextClassLoader(cl);
return ComponentUtil.getComponent(asResource.getId(),
resourceSpecificFacetInterface, FacetLockType.WRITE,
DEPLOY_CONTENT_TIMEOUT, true, true, true);
} finally {
Thread.currentThread().setContextClassLoader(
currenContextClassLoader);
}
}
public static <T> T getRemoteObject(String jndiName, Class<T> clazz)
throws Exception {
InitialContext initialContext = getAppServerInitialContext();
return clazz.cast(initialContext.lookup(jndiName));
}
public static InitialContext getAppServerInitialContext()
throws NamingException {
ResourceContainer resourceContainer = PluginContainer.getInstance()
.getInventoryManager().getResourceContainer(getASResource());
Configuration asConfiguration = resourceContainer.getResourceContext()
.getPluginConfiguration();
Properties env = new Properties();
env.setProperty(Context.PROVIDER_URL, asConfiguration.getSimpleValue(
"namingURL", null));
env.setProperty(Context.INITIAL_CONTEXT_FACTORY,
"org.jnp.interfaces.NamingContextFactory");
env.setProperty("jnp.timeout", "60000");
env.setProperty("jnp.sotimeout", "60000");
env.setProperty("jnp.disableDiscovery", "true");
return new InitialContext(env);
}
/**
* A helper method to invoke a method on an object using reflection.
*
* @param methodName
* the name of the method to invoke
* @param instance
* the instance to invoke the method upon
* @param methodArgTypesAndValues
* the method argument types and values
* @return the result of the method call
* @throws Exception
* on error
*/
public static Object invokeMethod(String methodName, Object instance,
MethodArgDef... methodArgTypesAndValues) throws Exception {
Class<?>[] argTypes = null;
Object[] argValues = null;
if (methodArgTypesAndValues != null) {
argTypes = new Class<?>[methodArgTypesAndValues.length];
argValues = new Object[methodArgTypesAndValues.length];
for (int i = 0; i < methodArgTypesAndValues.length; ++i) {
argTypes[i] = methodArgTypesAndValues[i].getType();
argValues[i] = methodArgTypesAndValues[i].getValue();
}
}
Method method = instance.getClass().getMethod(methodName, argTypes);
return method.invoke(instance, argValues);
}
private static DeploymentManager getDeploymentManager() throws Exception {
Object asComponent = getASComponentProxy(ProfileServiceComponent.class);
Object connection = invokeMethod("getConnection", asComponent,
(MethodArgDef[]) null);
// I wonder why this cast works... where does the DeploymentManager get
// loaded from in plugin and in here?
return (DeploymentManager) invokeMethod("getDeploymentManager",
connection, (MethodArgDef[]) null);
}
}