for (final AppInfo info : deployedApplications.values()) {
globalResolver.addAll(info.ejbJars);
}
SystemInstance.get().setComponent(EjbResolver.class, globalResolver);
final UndeployException undeployException = new UndeployException(messages.format("destroyApplication.failed", appInfo.path));
final WebAppBuilder webAppBuilder = SystemInstance.get().getComponent(WebAppBuilder.class);
if (webAppBuilder != null && !appInfo.webAppAlone) {
try {
webAppBuilder.undeployWebApps(appInfo);
} catch (final Exception e) {
undeployException.getCauses().add(new Exception("App: " + appInfo.path + ": " + e.getMessage(), e));
}
}
// get all of the ejb deployments
List<BeanContext> deployments = new ArrayList<BeanContext>();
for (final EjbJarInfo ejbJarInfo : appInfo.ejbJars) {
for (final EnterpriseBeanInfo beanInfo : ejbJarInfo.enterpriseBeans) {
final String deploymentId = beanInfo.ejbDeploymentId;
final BeanContext beanContext = containerSystem.getBeanContext(deploymentId);
if (beanContext == null) {
undeployException.getCauses().add(new Exception("deployment not found: " + deploymentId));
} else {
deployments.add(beanContext);
}
}
}
// Just as with startup we need to get things in an
// order that respects the singleton @DependsOn information
// Theoreticlly if a Singleton depends on something in its
// @PostConstruct, it can depend on it in its @PreDestroy.
// Therefore we want to make sure that if A dependsOn B,
// that we destroy A first then B so that B will still be
// usable in the @PreDestroy method of A.
// Sort them into the original starting order
deployments = sort(deployments);
// reverse that to get the stopping order
Collections.reverse(deployments);
// stop
for (final BeanContext deployment : deployments) {
final String deploymentID = String.valueOf(deployment.getDeploymentID());
try {
final Container container = deployment.getContainer();
container.stop(deployment);
} catch (final Throwable t) {
undeployException.getCauses().add(new Exception("bean: " + deploymentID + ": " + t.getMessage(), t));
}
}
// undeploy
for (final BeanContext bean : deployments) {
final String deploymentID = String.valueOf(bean.getDeploymentID());
try {
final Container container = bean.getContainer();
container.undeploy(bean);
bean.setContainer(null);
} catch (final Throwable t) {
undeployException.getCauses().add(new Exception("bean: " + deploymentID + ": " + t.getMessage(), t));
} finally {
bean.setDestroyed(true);
}
}
if (webAppBuilder != null && appInfo.webAppAlone) { // now that EJB are stopped we can undeploy webapps
try {
webAppBuilder.undeployWebApps(appInfo);
} catch (final Exception e) {
undeployException.getCauses().add(new Exception("App: " + appInfo.path + ": " + e.getMessage(), e));
}
}
// get the client ids
final List<String> clientIds = new ArrayList<String>();
for (final ClientInfo clientInfo : appInfo.clients) {
clientIds.add(clientInfo.moduleId);
for (final String className : clientInfo.localClients) {
clientIds.add(className);
}
for (final String className : clientInfo.remoteClients) {
clientIds.add(className);
}
}
for (final WebContext webContext : appContext.getWebContexts()) {
containerSystem.removeWebContext(webContext);
}
TldScanner.forceCompleteClean(classLoader);
// Clear out naming for all components first
for (final BeanContext deployment : deployments) {
final String deploymentID = String.valueOf(deployment.getDeploymentID());
try {
containerSystem.removeBeanContext(deployment);
} catch (final Throwable t) {
undeployException.getCauses().add(new Exception(deploymentID, t));
}
final JndiBuilder.Bindings bindings = deployment.get(JndiBuilder.Bindings.class);
if (bindings != null) {
for (final String name : bindings.getBindings()) {
try {
globalContext.unbind(name);
} catch (final Throwable t) {
undeployException.getCauses().add(new Exception("bean: " + deploymentID + ": " + t.getMessage(), t));
}
}
}
}
// stop this executor only now since @PreDestroy can trigger some stop events
final AsynchronousPool pool = appContext.get(AsynchronousPool.class);
if (pool != null) {
pool.stop();
}
for (final CommonInfoObject jar : listCommonInfoObjectsForAppInfo(appInfo)) {
try {
globalContext.unbind(VALIDATOR_FACTORY_NAMING_CONTEXT + jar.uniqueId);
globalContext.unbind(VALIDATOR_NAMING_CONTEXT + jar.uniqueId);
} catch (final NamingException e) {
if (EjbJarInfo.class.isInstance(jar)) {
undeployException.getCauses().add(new Exception("validator: " + jar.uniqueId + ": " + e.getMessage(), e));
} // else an error but not that important
}
}
try {
if (globalContext instanceof IvmContext) {
final IvmContext ivmContext = (IvmContext) globalContext;
ivmContext.prune("openejb/Deployment");
ivmContext.prune("openejb/local");
ivmContext.prune("openejb/remote");
ivmContext.prune("openejb/global");
}
} catch (final NamingException e) {
undeployException.getCauses().add(new Exception("Unable to prune openejb/Deployments and openejb/local namespaces, this could cause future deployments to fail.",
e));
}
deployments.clear();
for (final String clientId : clientIds) {
try {
globalContext.unbind("/openejb/client/" + clientId);
} catch (final Throwable t) {
undeployException.getCauses().add(new Exception("client: " + clientId + ": " + t.getMessage(), t));
}
}
// mbeans
final MBeanServer server = LocalMBeanServer.get();
for (final Object objectName : appInfo.jmx.values()) {
try {
final ObjectName on = new ObjectName((String) objectName);
if (server.isRegistered(on)) {
server.unregisterMBean(on);
}
final CreationalContext cc = creationalContextForAppMbeans.remove(on);
if (cc != null) {
cc.release();
}
} catch (final InstanceNotFoundException e) {
logger.warning("can't unregister " + objectName + " because the mbean was not found", e);
} catch (final MBeanRegistrationException e) {
logger.warning("can't unregister " + objectName, e);
} catch (final MalformedObjectNameException mone) {
logger.warning("can't unregister because the ObjectName is malformed: " + objectName, mone);
}
}
// destroy PUs before resources since the JPA provider can use datasources
for (final PersistenceUnitInfo unitInfo : appInfo.persistenceUnits) {
try {
final Object object = globalContext.lookup(PERSISTENCE_UNIT_NAMING_CONTEXT + unitInfo.id);
globalContext.unbind(PERSISTENCE_UNIT_NAMING_CONTEXT + unitInfo.id);
// close EMF so all resources are released
final ReloadableEntityManagerFactory remf = (ReloadableEntityManagerFactory) object;
remf.close();
persistenceClassLoaderHandler.destroy(unitInfo.id);
remf.unregister();
} catch (final Throwable t) {
undeployException.getCauses().add(new Exception("persistence-unit: " + unitInfo.id + ": " + t.getMessage(), t));
}
}
for (final String id : appInfo.resourceAliases) {
final String name = OPENEJB_RESOURCE_JNDI_PREFIX + id;
ContextualJndiReference.followReference.set(false);
try {
final Object object;
try {
object = globalContext.lookup(name);
} finally {
ContextualJndiReference.followReference.remove();
}
if (object instanceof ContextualJndiReference) {
final ContextualJndiReference contextualJndiReference = ContextualJndiReference.class.cast(object);
contextualJndiReference.removePrefix(appContext.getId());
if (contextualJndiReference.hasNoMorePrefix()) {
globalContext.unbind(name);
} // else not the last deployed application to use this resource so keep it
} else {
globalContext.unbind(name);
}
} catch (final NamingException e) {
logger.warning("can't unbind resource '{0}'", id);
}
}
for (final String id : appInfo.resourceIds) {
final String name = OPENEJB_RESOURCE_JNDI_PREFIX + id;
try {
destroyLookedUpResource(globalContext, id, name);
} catch (final NamingException e) {
logger.warning("can't unbind resource '{0}'", id);
}
}
for (final ConnectorInfo connector : appInfo.connectors) {
if (connector.resourceAdapter == null || connector.resourceAdapter.id == null) {
continue;
}
final String name = OPENEJB_RESOURCE_JNDI_PREFIX + connector.resourceAdapter.id;
try {
destroyLookedUpResource(globalContext, connector.resourceAdapter.id, name);
} catch (final NamingException e) {
logger.warning("can't unbind resource '{0}'", connector);
}
}
containerSystem.removeAppContext(appInfo.appId);
if (!appInfo.properties.containsKey("tomee.destroying")) { // destroy tomee classloader after resources cleanup
try {
final Method m = classLoader.getClass().getMethod("internalStop");
m.invoke(classLoader);
} catch (final NoSuchMethodException nsme) {
// no-op
} catch (final Exception e) {
logger.error("error stopping classloader of webapp " + appInfo.appId, e);
}
ClassLoaderUtil.cleanOpenJPACache(classLoader);
}
ClassLoaderUtil.destroyClassLoader(appInfo.appId, appInfo.path);
if (undeployException.getCauses().size() > 0) {
throw undeployException;
}
logger.debug("destroyApplication.success", appInfo.path);
} finally {