package org.mobicents.slee.container.deployment.jboss;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import javax.management.MBeanServer;
import javax.management.ObjectName;
import javax.slee.ComponentID;
import javax.slee.InvalidStateException;
import javax.slee.management.DeployableUnitID;
import javax.slee.management.DeploymentMBean;
import javax.slee.management.ResourceAdaptorEntityAlreadyExistsException;
import javax.slee.management.ResourceManagementMBean;
import javax.slee.management.ServiceManagementMBean;
import javax.slee.management.SleeState;
import javax.slee.management.UnrecognizedLinkNameException;
import org.jboss.deployment.DeploymentException;
import org.jboss.logging.Logger;
import org.jboss.mx.loading.RepositoryClassLoader;
import org.mobicents.slee.container.SleeContainer;
/**
* This class represents the Manager responsible for executing deployment actions
* and for controlling dependencies and monitoring new deployments using the deployer.
*
* @author Alexandre Mendon�a
* @version 1.0
*/
@SuppressWarnings("deprecation")
public class DeploymentManager {
// Let's make sure it's a singleton
public final static DeploymentManager INSTANCE = new DeploymentManager();
// The Logger.
private static Logger logger = Logger.getLogger(DeploymentManager.class);
// The DUs waiting to be installed.
private Collection<DeployableUnit> waitingForInstallDUs = new ConcurrentLinkedQueue<DeployableUnit>();
// The DUs waiting for being uninstalled.
private Collection<DeployableUnit> waitingForUninstallDUs = new ConcurrentLinkedQueue<DeployableUnit>();
private ConcurrentHashMap<DeployableUnit, RepositoryClassLoader> replacedUCLs = new ConcurrentHashMap<DeployableUnit, RepositoryClassLoader>();
// The components already deployed to SLEE
private Collection<String> deployedComponents = new ConcurrentLinkedQueue<String>();
// Actions using DeploymentMBean
private Collection<String> deploymentActions = Arrays.asList(new String[] {
"install", "uninstall" });
// Actions using ResourceManagementMBean
private Collection<String> resourceAdaptorActions = Arrays
.asList(new String[] { "bindLinkName", "unbindLinkName",
"createResourceAdaptorEntity",
"removeResourceAdaptorEntity",
"activateResourceAdaptorEntity",
"deactivateResourceAdaptorEntity" });
// Actions using ServiceManagementMBean
private Collection<String> serviceActions = Arrays.asList(new String[] {
"activate", "deactivate" });
private Collection<String> deployActions = Arrays.asList(new String[] {
"install", "activate", "bindLinkName",
"createResourceAdaptorEntity", "activateResourceAdaptorEntity" });
private ConcurrentHashMap<DeployableUnit, Collection<String>> actionsToAvoidByDU = new ConcurrentHashMap<DeployableUnit, Collection<String>>();
public long waitTimeBetweenOperations = 250;
private final SleeStateJMXMonitor sleeStateJMXMonitor;
/**
* Constructor.
*/
private DeploymentManager() {
sleeStateJMXMonitor = new SleeStateJMXMonitor(this);
}
/**
* Method for adding a new deployable unit to the manager.
* @param du the DeployableUnit object to add.
* @throws Exception
*/
public void addDeployableUnit(DeployableUnit du) throws Exception {
// Get a fresh copy of the deployed components.
updateDeployedComponents();
// Check if there aren't already deployed components in this DU...
if (!deployedComponents.containsAll(du.getComponents())) {
// Add it to the deploy list.
waitingForInstallDUs.add(du);
} else {
logger.warn("Trying to deploy a duplicate DU ("
+ du.getDeploymentInfoShortName() + ").");
}
}
/**
* Updates the list of components already deployed to SLEE.
*/
public void updateDeployedComponents() {
try {
// Get the SLEE Container from JNDI
SleeContainer sleeContainer = SleeContainer.lookupFromJndi();
// First we'll put the components in a temp Collection
ConcurrentLinkedQueue<String> newDeployedComponents = new ConcurrentLinkedQueue<String>();
// Get the deployed Profile Specifications
for (ComponentID componentID: sleeContainer.getComponentRepositoryImpl().getProfileSpecificationIDs()) {
newDeployedComponents.add(componentID.toString());
}
// Get the deployed Event Types
for (ComponentID componentID: sleeContainer.getComponentRepositoryImpl().getEventComponentIDs()) {
newDeployedComponents.add(componentID.toString());
}
// Get the deployed Resource Adaptor Types
for (ComponentID componentID: sleeContainer.getComponentRepositoryImpl().getResourceAdaptorTypeIDs()) {
newDeployedComponents.add(componentID.toString());
}
// Get the deployed Resource Adaptors
for (ComponentID componentID: sleeContainer.getComponentRepositoryImpl().getResourceAdaptorIDs()) {
newDeployedComponents.add(componentID.toString());
}
// Get the deployed Service Building Blocks (SBBs)
for (ComponentID componentID: sleeContainer.getComponentRepositoryImpl().getSbbIDs()) {
newDeployedComponents.add(componentID.toString());
}
// Get the deployed Services
for (ComponentID componentID: sleeContainer.getComponentRepositoryImpl().getServiceIDs()) {
newDeployedComponents.add(componentID.toString());
}
// Get the deployed Libraries
for (ComponentID componentID: sleeContainer.getComponentRepositoryImpl().getLibraryIDs()) {
newDeployedComponents.add(componentID.toString());
}
// Get the existing Resource Adaptor Entity links
String[] entityNames = sleeContainer.getResourceManagement()
.getResourceAdaptorEntities();
for (String entityName : entityNames) {
newDeployedComponents.addAll(Arrays.asList(sleeContainer.getResourceManagement().getLinkNames(entityName)));
}
// All good.. Make the temp the good one.
deployedComponents = newDeployedComponents;
} catch (Exception e) {
logger.warn("Failure while updating deployed components.", e);
}
}
/**
* Method for installing a Deployable Unit into SLEE.
* @param du the Deployable Unit to install.
* @throws Exception
*/
public void installDeployableUnit(DeployableUnit du) throws Exception {
SleeState state = sleeStateJMXMonitor.getSleeState();
if (state != SleeState.RUNNING) {
logger.warn("Unable to INSTALL " + du.getDeploymentInfoShortName()
+ " right now. Waiting for SLEE to be in RUNNING state (" + state + ").");
waitingForInstallDUs.add(du);
return;
}
// Update the deployed components from SLEE
updateDeployedComponents();
// Check if the DU is ready to be installed
if (du.isReadyToInstall(true)) {
// Get and Run the actions needed for installing this DU
sciAction(du.getInstallActions(), du);
// Set the DU as installed
du.setInstalled(true);
// Update the deployed components from SLEE
updateDeployedComponents();
// Go through the remaining DUs waiting for installation
Iterator<DeployableUnit> duIt = waitingForInstallDUs.iterator();
while (duIt.hasNext()) {
DeployableUnit waitingDU = duIt.next();
// If it is ready for installation, follow the same procedure
if (waitingDU.isReadyToInstall(false)) {
// Get and Run the actions needed for installing this DU
sciAction(waitingDU.getInstallActions(), du);
// Set the DU as installed
waitingDU.setInstalled(true);
// Update the deployed components from SLEE
updateDeployedComponents();
// Remove the DU from the waiting list.
waitingForInstallDUs.remove(waitingDU);
// Let's start all over.. :)
duIt = waitingForInstallDUs.iterator();
}
}
} else {
logger.warn("Unable to INSTALL " + du.getDeploymentInfoShortName()
+ " right now. Waiting for dependencies to be resolved.");
// The DU can't be installed now, let's wait...
waitingForInstallDUs.add(du);
}
}
/**
* Method for uninstalling a Deployable Unit into SLEE.
* @param du the Deployable Unit to install.
* @throws Exception
*/
public void uninstallDeployableUnit(DeployableUnit du) throws Exception {
SleeState state = sleeStateJMXMonitor.getSleeState();
if (state != SleeState.RUNNING && state != SleeState.STOPPING) {
logger.warn("Unable to UNINSTALL " + du.getDeploymentInfoShortName()
+ " right now. Waiting for SLEE to be in RUNNING/STOPPING state (" + state + ").");
waitingForUninstallDUs.add(du);
return;
}
// Update the deployed components from SLEE
updateDeployedComponents();
// It isn't installed?
if (!du.isInstalled()) {
// Then it should be in the waiting list... remove and we're done.
if (waitingForInstallDUs.remove(du)) {
logger.info(du.getDeploymentInfoShortName()
+ " wasn't deployed. Removing from waiting list.");
}
}
// Check if the DU is ready to be uninstalled
else if (du.isReadyToUninstall()) {
// Get and Run the actions needed for uninstalling this DU
sciAction(du.getUninstallActions(), du);
// Set the DU as not installed
du.setInstalled(false);
// Remove if it was present in waiting list
waitingForUninstallDUs.remove(du);
// Update the deployed components from SLEE
updateDeployedComponents();
// Unregister the replaced UCL, if any
RepositoryClassLoader repositoryClassLoader = replacedUCLs
.remove(du);
if (repositoryClassLoader != null) {
repositoryClassLoader.unregister();
if (logger.isDebugEnabled()) {
logger.debug("replacedUCLs size is " + replacedUCLs.size()
+ " after removing DU "
+ du.getDeploymentInfoShortName());
}
}
// Go through the remaining DUs waiting for uninstallation
Iterator<DeployableUnit> duIt = waitingForUninstallDUs.iterator();
while (duIt.hasNext()) {
DeployableUnit waitingDU = duIt.next();
// If it is ready for being uninstalled, follow the same procedure
if (waitingDU.isReadyToUninstall()) {
// Get and Run the actions needed for uninstalling this DU
//sciAction(waitingDU.getUninstallActions(), du);
// Schedule removal
SLEESubDeployer.INSTANCE.stop(new DeployableUnitWrapper(waitingDU.getURL()));
// Set the DU as not installed
// waitingDU.setInstalled(false);
// Update the deployed components from SLEE
// updateDeployedComponents();
// Remove the DU from the waiting list.
waitingForUninstallDUs.remove(waitingDU);
// Unregister the replaced UCL, if any
repositoryClassLoader = replacedUCLs.remove(waitingDU);
if (repositoryClassLoader != null) {
repositoryClassLoader.unregister();
if (logger.isDebugEnabled()) {
logger.debug("replacedUCLs size is "
+ replacedUCLs.size()
+ " after removing DU "
+ du.getDeploymentInfoShortName());
}
}
// Let's start all over.. :)
duIt = waitingForUninstallDUs.iterator();
}
}
} else {
// Have we been her already? If so, don't flood user with log messages...
if (!waitingForUninstallDUs.contains(du)) {
// Add it to the waiting list.
waitingForUninstallDUs.add(du);
logger.warn("Unable to UNINSTALL "
+ du.getDeploymentInfoShortName()
+ " right now. Waiting for dependents to be removed.");
}
// But we have to throw this so task knows that it needs to retry
throw new DeploymentException("Unable to UNINSTALL "
+ du.getDeploymentInfoShortName()
+ " right now. Waiting for dependents to be removed.");
}
}
public void addReplacedUCL(DeployableUnit du, RepositoryClassLoader ucl) {
if (ucl != null)
this.replacedUCLs.put(du, ucl);
}
/**
* Method for performing the actions needed for (un)deployment.
* @param actions the array of strings containing the actions to perform.
* @param du the DeployableUnit from where the actions are being performed.
* @throws Exception
*/
private void sciAction(Collection<Object[]> actions, DeployableUnit du)
throws Exception {
// Get the MBeanServer
MBeanServer ms = SleeContainer.lookupFromJndi().getMBeanServer();
// For each action, get the params..
for (Object[] params : actions) {
// The ObjectName for the MBean invocations
ObjectName objectName = null;
// The arguments and their signature
Object[] arguments = new Object[params.length - 1];
;
String[] signature = new String[params.length - 1];
// Get the action to perform
String action = (String) params[0];
// Shall we skip this action?
if (actionsToAvoidByDU.get(du) != null
&& actionsToAvoidByDU.get(du).remove(action)) {
// Clean if it was the last one.
if (actionsToAvoidByDU.get(du).size() == 0)
actionsToAvoidByDU.remove(du);
continue;
}
// Get the parameters and the signature
for (int i = 1; i < params.length; i++) {
arguments[i - 1] = params[i];
signature[i - 1] = params[i].getClass().getName();
}
// Get the correct object name for the action
if (deploymentActions.contains(action)) {
// Set the corresponding ObjectName
objectName = new ObjectName(DeploymentMBean.OBJECT_NAME);
if (action.equals("uninstall")) {
// Need to convert from file to DeployableUnitID
DeployableUnitID duID = (DeployableUnitID) ms.invoke(
objectName, "getDeployableUnit",
new Object[] { params[1] },
new String[] { params[1].getClass().getName() });
// Update arguments and signature
arguments[0] = duID;
signature[0] = "javax.slee.management.DeployableUnitID";
}
} else if (resourceAdaptorActions.contains(action)) {
// Set the corresponding ObjectName
objectName = new ObjectName(ResourceManagementMBean.OBJECT_NAME);
// Special case as arg is ResourceAdaptorIDImpl..
if (action.equals("createResourceAdaptorEntity"))
signature[0] = "javax.slee.resource.ResourceAdaptorID";
} else if (serviceActions.contains(action)) {
// Set the corresponding ObjectName
objectName = new ObjectName(ServiceManagementMBean.OBJECT_NAME);
// Special case as arg is ServiceIDImpl..
signature[0] = "javax.slee.ServiceID";
}
if (logger.isDebugEnabled())
logger.debug("Invoking " + action + "("
+ Arrays.toString(signature) + ") on " + objectName);
// We are isolating each action, so it won't affect the whole proccess
try {
// Invoke it.
ms.invoke(objectName, action, arguments, signature);
// We need to wait for service to deactivate...
// if(action.equals( "deactivate" ))
// {
// long waited = 0;
//
// ServiceState ss = null;
//
// double maxWaitTime = 60 * 1000 * MobicentsManagement.entitiesRemovalDelay;
//
// while(true)
// {
// ss = (ServiceState) ms.invoke( objectName, "getState", arguments, signature );
//
// if(logger.isDebugEnabled())
// logger.debug( arguments[0] + " State [" + ss.toString() + "]." );
//
// if(!ss.isInactive() && waited <= maxWaitTime)
// {
// if(logger.isDebugEnabled())
// logger.debug( "Waiting more " + waitTimeBetweenOperations + "ms. Waited a total of " + waited + "ms." );
//
// Thread.sleep( waitTimeBetweenOperations );
// waited += waitTimeBetweenOperations;
// }
// else
// {
// if(logger.isDebugEnabled())
// logger.debug( "Service already deactivated or maximum wait time reached. Moving on!" );
//
// break;
// }
// }
// }
} catch (Exception e) {
// We might expect some exceptions...
if (e.getCause() instanceof ResourceAdaptorEntityAlreadyExistsException
|| (e.getCause() instanceof InvalidStateException && action
.equals("activateResourceAdaptorEntity"))) {
String actionToAvoid = "";
// If the activate/create failed then we don't want to deactivate/remove
if (action.equals("activateResourceAdaptorEntity"))
actionToAvoid = "deactivateResourceAdaptorEntity";
else if (action.equals("createResourceAdaptorEntity"))
actionToAvoid = "removeResourceAdaptorEntity";
Collection actionsToAvoid;
if ((actionsToAvoid = actionsToAvoidByDU.get(du)) == null) {
actionsToAvoid = new ArrayList();
// Add it to the list of actions to skip on undeploy
actionsToAvoid.add(actionToAvoid);
// And put it to the map
actionsToAvoidByDU.put(du, actionsToAvoid);
} else {
// Add it to the list of actions to skip on undeploy
actionsToAvoid.add(actionToAvoid);
}
logger.warn(e.getCause().getMessage());
} else if (e.getCause() instanceof InvalidStateException
&& action.equals("deactivate")) {
logger
.info("Delaying uninstall due to service deactivation not complete.");
} else if (e.getCause() instanceof InvalidStateException
&& action.equals("deactivateResourceAdaptorEntity")) {
// ignore this... someone has already deactivated the link.
} else if (e.getCause() instanceof UnrecognizedLinkNameException
&& action.equals("unbindLinkName")) {
// ignore this... someone has already removed the link.
} else if (deployActions.contains(action)) {
logger.error(
"Failure invoking '" + action + "("
+ Arrays.toString(arguments) + ") on "
+ objectName, e);
} else {
throw (e);
}
}
// Wait a little while just to make sure it finishes
Thread.sleep(waitTimeBetweenOperations);
}
}
/**
* Getter for the Deployed Components collection.
* @return a Collection of Strings with the deployed components IDs.
*/
public Collection<String> getDeployedComponents() {
return deployedComponents;
}
/**
* Method for showing current status of the Deployment Manager.
* @return a HTML string with the status.
*/
public String showStatus() {
// Update the currently deployed components.
updateDeployedComponents();
String output = "";
output += "<p>Deployable Units Waiting For Install:</p>";
for (DeployableUnit waitingDU : waitingForInstallDUs) {
output += "+-- " + waitingDU.getDeploymentInfoShortName() + "<br>";
for (String dependency : waitingDU.getExternalDependencies()) {
if (!deployedComponents.contains(dependency))
dependency += " <strong>MISSING!</strong>";
output += " +-- depends on " + dependency + "<br>";
}
}
output += "<p>Deployable Units Waiting For Uninstall:</p>";
for (DeployableUnit waitingDU : waitingForUninstallDUs) {
output += "+-- " + waitingDU.getDeploymentInfoShortName() + "<br>";
}
return output;
}
/**
* Callback for {@link SleeStateJMXMonitor}, to learn when SLEE is running.
*/
public void sleeIsRunning() {
if (logger.isDebugEnabled()) {
logger.debug("Got notified that SLEE is now in running state");
}
// process all DUs that are on hold
Set<DeployableUnit> duSet = new HashSet<DeployableUnit>(waitingForUninstallDUs);
waitingForUninstallDUs.clear();
for (DeployableUnit du : duSet) {
try {
uninstallDeployableUnit(du);
} catch (Exception e) {
logger.error("Failed to uninstall DU on hold, after SLEE is running",e);
}
}
duSet = new HashSet<DeployableUnit>(waitingForInstallDUs);
waitingForInstallDUs.clear();
for (DeployableUnit du : duSet) {
try {
installDeployableUnit(du);
} catch (Exception e) {
logger.error("Failed to install DU on hold, after SLEE is running",e);
}
}
}
}