Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.apache.openejb.assembler.classic.Assembler Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.openejb.assembler.classic;
import org.apache.geronimo.connector.GeronimoBootstrapContext;
import org.apache.geronimo.connector.outbound.AbstractConnectionManager;
import org.apache.geronimo.connector.work.GeronimoWorkManager;
import org.apache.geronimo.connector.work.HintsContextHandler;
import org.apache.geronimo.connector.work.TransactionContextHandler;
import org.apache.geronimo.connector.work.WorkContextHandler;
import org.apache.geronimo.transaction.manager.GeronimoTransactionManager;
import org.apache.openejb.AppContext;
import org.apache.openejb.BeanContext;
import org.apache.openejb.BeanType;
import org.apache.openejb.ClassLoaderUtil;
import org.apache.openejb.Container;
import org.apache.openejb.DeploymentContext;
import org.apache.openejb.DuplicateDeploymentIdException;
import org.apache.openejb.Extensions;
import org.apache.openejb.Injection;
import org.apache.openejb.JndiConstants;
import org.apache.openejb.MethodContext;
import org.apache.openejb.NoSuchApplicationException;
import org.apache.openejb.OpenEJBException;
import org.apache.openejb.OpenEJBRuntimeException;
import org.apache.openejb.UndeployException;
import org.apache.openejb.api.DestroyableResource;
import org.apache.openejb.assembler.classic.event.AssemblerAfterApplicationCreated;
import org.apache.openejb.assembler.classic.event.AssemblerBeforeApplicationDestroyed;
import org.apache.openejb.assembler.classic.event.AssemblerCreated;
import org.apache.openejb.assembler.classic.event.AssemblerDestroyed;
import org.apache.openejb.assembler.classic.event.BeforeStartEjbs;
import org.apache.openejb.assembler.classic.event.ContainerSystemPostCreate;
import org.apache.openejb.assembler.classic.event.ContainerSystemPreDestroy;
import org.apache.openejb.assembler.monitoring.JMXContainer;
import org.apache.openejb.async.AsynchronousPool;
import org.apache.openejb.cdi.CdiAppContextsService;
import org.apache.openejb.cdi.CdiBuilder;
import org.apache.openejb.cdi.CdiResourceInjectionService;
import org.apache.openejb.cdi.CdiScanner;
import org.apache.openejb.cdi.CustomELAdapter;
import org.apache.openejb.cdi.ManagedSecurityService;
import org.apache.openejb.cdi.OpenEJBJndiService;
import org.apache.openejb.cdi.OpenEJBTransactionService;
import org.apache.openejb.cdi.OptimizedLoaderService;
import org.apache.openejb.classloader.ClassLoaderConfigurer;
import org.apache.openejb.classloader.CompositeClassLoaderConfigurer;
import org.apache.openejb.component.ClassLoaderEnricher;
import org.apache.openejb.config.ConfigurationFactory;
import org.apache.openejb.config.NewLoaderLogic;
import org.apache.openejb.config.QuickJarsTxtParser;
import org.apache.openejb.config.TldScanner;
import org.apache.openejb.core.ConnectorReference;
import org.apache.openejb.core.CoreContainerSystem;
import org.apache.openejb.core.CoreUserTransaction;
import org.apache.openejb.core.JndiFactory;
import org.apache.openejb.core.ParentClassLoaderFinder;
import org.apache.openejb.core.ServerFederation;
import org.apache.openejb.core.SimpleTransactionSynchronizationRegistry;
import org.apache.openejb.core.TransactionSynchronizationRegistryWrapper;
import org.apache.openejb.core.WebContext;
import org.apache.openejb.core.ivm.IntraVmProxy;
import org.apache.openejb.core.ivm.naming.ContextualJndiReference;
import org.apache.openejb.core.ivm.naming.IvmContext;
import org.apache.openejb.core.ivm.naming.IvmJndiFactory;
import org.apache.openejb.core.ivm.naming.LazyObjectReference;
import org.apache.openejb.core.ivm.naming.Reference;
import org.apache.openejb.core.security.SecurityContextHandler;
import org.apache.openejb.core.timer.EjbTimerServiceImpl;
import org.apache.openejb.core.timer.MemoryTimerStore;
import org.apache.openejb.core.timer.NullEjbTimerServiceImpl;
import org.apache.openejb.core.timer.ScheduleData;
import org.apache.openejb.core.timer.TimerStore;
import org.apache.openejb.core.transaction.JtaTransactionPolicyFactory;
import org.apache.openejb.core.transaction.SimpleBootstrapContext;
import org.apache.openejb.core.transaction.SimpleWorkManager;
import org.apache.openejb.core.transaction.TransactionPolicyFactory;
import org.apache.openejb.core.transaction.TransactionType;
import org.apache.openejb.javaagent.Agent;
import org.apache.openejb.jpa.integration.MakeTxLookup;
import org.apache.openejb.loader.IO;
import org.apache.openejb.loader.JarLocation;
import org.apache.openejb.loader.Options;
import org.apache.openejb.loader.ProvisioningUtil;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.monitoring.DynamicMBeanWrapper;
import org.apache.openejb.monitoring.LocalMBeanServer;
import org.apache.openejb.monitoring.ObjectNameBuilder;
import org.apache.openejb.monitoring.remote.RemoteResourceMonitor;
import org.apache.openejb.observer.Observes;
import org.apache.openejb.persistence.JtaEntityManagerRegistry;
import org.apache.openejb.persistence.PersistenceClassLoaderHandler;
import org.apache.openejb.quartz.Scheduler;
import org.apache.openejb.resource.GeronimoConnectionManagerFactory;
import org.apache.openejb.resource.PropertiesFactory;
import org.apache.openejb.resource.jdbc.DataSourceFactory;
import org.apache.openejb.spi.ApplicationServer;
import org.apache.openejb.spi.ContainerSystem;
import org.apache.openejb.spi.SecurityService;
import org.apache.openejb.util.Contexts;
import org.apache.openejb.util.DaemonThreadFactory;
import org.apache.openejb.util.ExecutorBuilder;
import org.apache.openejb.util.Join;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;
import org.apache.openejb.util.Messages;
import org.apache.openejb.util.OpenEJBErrorHandler;
import org.apache.openejb.util.PropertiesHelper;
import org.apache.openejb.util.PropertyPlaceHolderHelper;
import org.apache.openejb.util.References;
import org.apache.openejb.util.SafeToolkit;
import org.apache.openejb.util.SetAccessible;
import org.apache.openejb.util.SuperProperties;
import org.apache.openejb.util.URISupport;
import org.apache.openejb.util.URLs;
import org.apache.openejb.util.classloader.ClassLoaderAwareHandler;
import org.apache.openejb.util.classloader.URLClassLoaderFirst;
import org.apache.openejb.util.proxy.ProxyFactory;
import org.apache.openejb.util.proxy.ProxyManager;
import org.apache.webbeans.config.WebBeansContext;
import org.apache.webbeans.container.BeanManagerImpl;
import org.apache.webbeans.inject.OWBInjector;
import org.apache.webbeans.logger.JULLoggerFactory;
import org.apache.webbeans.spi.ContainerLifecycle;
import org.apache.webbeans.spi.ContextsService;
import org.apache.webbeans.spi.JNDIService;
import org.apache.webbeans.spi.LoaderService;
import org.apache.webbeans.spi.ResourceInjectionService;
import org.apache.webbeans.spi.ScannerService;
import org.apache.webbeans.spi.TransactionService;
import org.apache.webbeans.spi.adaptor.ELAdaptor;
import org.apache.xbean.finder.AnnotationFinder;
import org.apache.xbean.finder.ClassLoaders;
import org.apache.xbean.finder.ResourceFinder;
import org.apache.xbean.finder.UrlSet;
import org.apache.xbean.finder.archive.ClassesArchive;
import org.apache.xbean.recipe.ConstructionException;
import org.apache.xbean.recipe.ObjectRecipe;
import org.apache.xbean.recipe.Option;
import org.apache.xbean.recipe.UnsetPropertiesRecipe;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.enterprise.context.Dependent;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.management.InstanceNotFoundException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.naming.Binding;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NameAlreadyBoundException;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.ConnectionManager;
import javax.resource.spi.ManagedConnectionFactory;
import javax.resource.spi.ResourceAdapter;
import javax.resource.spi.ResourceAdapterInternalException;
import javax.resource.spi.XATerminator;
import javax.resource.spi.work.WorkManager;
import javax.sql.DataSource;
import javax.transaction.TransactionManager;
import javax.transaction.TransactionSynchronizationRegistry;
import javax.validation.ValidationException;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.io.ByteArrayInputStream;
import java.io.Externalizable;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidObjectException;
import java.io.ObjectStreamException;
import java.io.Serializable;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;
import java.util.concurrent.locks.ReentrantLock;
import static org.apache.openejb.util.Classes.ancestors;
@SuppressWarnings({"UnusedDeclaration", "UnqualifiedFieldAccess", "UnqualifiedMethodAccess"})
public class Assembler extends AssemblerTool implements org.apache.openejb.spi.Assembler, JndiConstants {
/**
* Private static
*/
private static final AtomicReference SLF4J_RESET = new AtomicReference(null);
private static final ReentrantLock lock = new ReentrantLock(true);
private static final String GLOBAL_UNIQUE_ID = "global";
/**
* Public static
*/
public static final String OPENEJB_URL_PKG_PREFIX = IvmContext.class.getPackage().getName();
public static final String OPENEJB_JPA_DEPLOY_TIME_ENHANCEMENT_PROP = "openejb.jpa.deploy-time-enhancement";
public static final String PROPAGATE_APPLICATION_EXCEPTIONS = "openejb.propagate.application-exceptions";
public static final String TOMEE_DATASOURCE_DESTROY_TIMEOUT = "tomee.datasource.destroy.timeout.ms";
public static final String TIMER_STORE_CLASS = "timerStore.class";
public static final String OPENEJB_TIMERS_ON = "openejb.timers.on";
public static final Class>[] VALIDATOR_FACTORY_INTERFACES = new Class>[]{ValidatorFactory.class};
public static final Class>[] VALIDATOR_INTERFACES = new Class>[]{Validator.class};
static {
// avoid linkage error on mac
// adding just in case others run into in their tests
JULLoggerFactory.class.getName();
//Cache slf4j method if available
if (SystemInstance.get().getOptions().get("tomee.slf4j.deployment.reset", false)) {
try {
final Class> c = Class.forName("org.slf4j.LoggerFactory");
final Method m = c.getDeclaredMethod("reset", null);
m.setAccessible(true);
Assembler.SLF4J_RESET.set(m);
} catch (final ClassNotFoundException e) {
System.out.println("Assembler.resetSlf4j: " + e.getMessage());
} catch (final NoSuchMethodException e) {
System.out.println("Assembler.resetSlf4j: " + e.getMessage());
}
}
}
private final Map deployedApplications = new HashMap();
private final Map creationalContextForAppMbeans = new HashMap();
private final Set containerObjectNames = new HashSet();
private final RemoteResourceMonitor remoteResourceMonitor = new RemoteResourceMonitor();
private final Messages messages = new Messages(Assembler.class.getPackage().getName());
private final CoreContainerSystem containerSystem;
private final PersistenceClassLoaderHandler persistenceClassLoaderHandler;
private final JndiBuilder jndiBuilder;
protected OpenEjbConfigurationFactory configFactory;
private final boolean skipLoaderIfPossible;
private TransactionManager transactionManager;
private SecurityService securityService;
//Used outside of this class
private final Logger logger;
protected SafeToolkit toolkit = SafeToolkit.getToolkit("Assembler");
protected OpenEjbConfiguration config;
public Assembler() {
this(new IvmJndiFactory());
}
public Assembler(final JndiFactory jndiFactory) {
logger = Logger.getInstance(LogCategory.OPENEJB_STARTUP, Assembler.class);
skipLoaderIfPossible = "true".equalsIgnoreCase(SystemInstance.get().getProperty("openejb.classloader.skip-app-loader-if-possible", "true"));
persistenceClassLoaderHandler = new PersistenceClassLoaderHandlerImpl();
installNaming();
final SystemInstance system = SystemInstance.get();
system.setComponent(org.apache.openejb.spi.Assembler.class, this);
system.setComponent(Assembler.class, this);
containerSystem = new CoreContainerSystem(jndiFactory);
system.setComponent(ContainerSystem.class, containerSystem);
jndiBuilder = new JndiBuilder(containerSystem.getJNDIContext());
setConfiguration(new OpenEjbConfiguration());
final ApplicationServer appServer = system.getComponent(ApplicationServer.class);
if (appServer == null) {
system.setComponent(ApplicationServer.class, new ServerFederation());
}
system.setComponent(EjbResolver.class, new EjbResolver(null, EjbResolver.Scope.GLOBAL));
installExtensions();
system.fireEvent(new AssemblerCreated());
}
@Override
public ContainerSystem getContainerSystem() {
return containerSystem;
}
@Override
public TransactionManager getTransactionManager() {
return transactionManager;
}
@Override
public SecurityService getSecurityService() {
return securityService;
}
public void addDeploymentListener(final DeploymentListener deploymentListener) {
final ReentrantLock l = lock;
l.lock();
try {
logger.warning("DeploymentListener API is replaced by @Observes event");
SystemInstance.get().addObserver(new DeploymentListenerObserver(deploymentListener));
} finally {
l.unlock();
}
}
public void removeDeploymentListener(final DeploymentListener deploymentListener) {
final ReentrantLock l = lock;
l.lock();
try {
// the wrapping is done here to get the correct equals/hashcode methods
SystemInstance.get().removeObserver(new DeploymentListenerObserver(deploymentListener));
} finally {
l.unlock();
}
}
private void installExtensions() {
try {
final Collection urls = NewLoaderLogic.applyBuiltinExcludes(new UrlSet(Assembler.class.getClassLoader()).excludeJvm()).getUrls();
Extensions.installExtensions(new Extensions.Finder("META-INF", false, urls.toArray(new URL[urls.size()])));
return;
} catch (final IOException e) {
// no-op
}
// if an error occurred do it brutely
Extensions.installExtensions(new Extensions.Finder("META-INF", true));
}
private void setConfiguration(final OpenEjbConfiguration config) {
this.config = config;
if (config.containerSystem == null) {
config.containerSystem = new ContainerSystemInfo();
}
if (config.facilities == null) {
config.facilities = new FacilitiesInfo();
}
SystemInstance.get().setComponent(OpenEjbConfiguration.class, this.config);
}
@Override
public void init(final Properties props) throws OpenEJBException {
this.props = new Properties(props);
final Options options = new Options(props, SystemInstance.get().getOptions());
final String className = options.get("openejb.configurator", "org.apache.openejb.config.ConfigurationFactory");
if ("org.apache.openejb.config.ConfigurationFactory".equals(className)) {
configFactory = new ConfigurationFactory(); // no need to use reflection
} else {
configFactory = (OpenEjbConfigurationFactory) toolkit.newInstance(className);
}
configFactory.init(props);
SystemInstance.get().setComponent(OpenEjbConfigurationFactory.class, configFactory);
}
public static void installNaming() {
if (SystemInstance.get().hasProperty("openejb.geronimo")) {
return;
}
/* Add IntraVM JNDI service /////////////////////*/
installNaming(OPENEJB_URL_PKG_PREFIX);
/*\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
}
public static void installNaming(final String prefix) {
installNaming(prefix, false);
}
public static void installNaming(final String prefix, final boolean clean) {
final ReentrantLock l = lock;
l.lock();
try {
final Properties systemProperties = System.getProperties();
String str = systemProperties.getProperty(Context.URL_PKG_PREFIXES);
if (str == null || clean) {
str = prefix;
} else if (!str.contains(prefix)) {
str = str + ":" + prefix;
}
systemProperties.setProperty(Context.URL_PKG_PREFIXES, str);
} finally {
l.unlock();
}
}
private static final ThreadLocal> context = new ThreadLocal>();
public static void setContext(final Map map) {
context.set(map);
}
public static Map getContext() {
Map map = context.get();
if (map == null) {
map = new HashMap();
context.set(map);
}
return map;
}
@Override
public void build() throws OpenEJBException {
setContext(new HashMap());
try {
final OpenEjbConfiguration config = getOpenEjbConfiguration();
buildContainerSystem(config);
} catch (final OpenEJBException ae) {
/* OpenEJBExceptions contain useful information and are debbugable.
* Let the exception pass through to the top and be logged.
*/
throw ae;
} catch (final Exception e) {
/* General Exceptions at this level are too generic and difficult to debug.
* These exceptions are considered unknown bugs and are fatal.
* If you get an error at this level, please trap and handle the error
* where it is most relevant.
*/
OpenEJBErrorHandler.handleUnknownError(e, "Assembler");
throw new OpenEJBException(e);
} finally {
context.set(null);
}
}
protected OpenEjbConfiguration getOpenEjbConfiguration() throws OpenEJBException {
return configFactory.getOpenEjbConfiguration();
}
/////////////////////////////////////////////////////////////////////
////
//// Public Methods Used for Assembly
////
/////////////////////////////////////////////////////////////////////
/**
* When given a complete OpenEjbConfiguration graph this method
* will construct an entire container system and return a reference to that
* container system, as ContainerSystem instance.
*
* This method leverage the other assemble and apply methods which
* can be used independently.
*
* Assembles and returns the {@link CoreContainerSystem} using the
* information from the {@link OpenEjbConfiguration} object passed in.
*
* This method performs the following actions(in order):
*
* 1 Assembles ProxyFactory
* 2 Assembles External JNDI Contexts
* 3 Assembles TransactionService
* 4 Assembles SecurityService
* 5 Assembles ConnectionManagers
* 6 Assembles Connectors
* 7 Assembles Containers
* 8 Assembles Applications
*
*
* @param configInfo OpenEjbConfiguration
* @throws Exception if there was a problem constructing the ContainerSystem.
* @see OpenEjbConfiguration
*/
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
public void buildContainerSystem(final OpenEjbConfiguration configInfo) throws Exception {
final SystemInstance systemInstance = SystemInstance.get();
if (systemInstance.getOptions().get(OPENEJB_JPA_DEPLOY_TIME_ENHANCEMENT_PROP, false)) {
systemInstance.addObserver(new DeployTimeEnhancer());
}
for (final ServiceInfo serviceInfo : configInfo.facilities.services) {
createService(serviceInfo);
}
final ContainerSystemInfo containerSystemInfo = configInfo.containerSystem;
if (configInfo.facilities.intraVmServer != null) {
createProxyFactory(configInfo.facilities.intraVmServer);
}
for (final JndiContextInfo contextInfo : configInfo.facilities.remoteJndiContexts) {
createExternalContext(contextInfo);
}
createTransactionManager(configInfo.facilities.transactionService);
createSecurityService(configInfo.facilities.securityService);
final Set reservedResourceIds = new HashSet(configInfo.facilities.resources.size());
for (final AppInfo appInfo : containerSystemInfo.applications) {
reservedResourceIds.addAll(appInfo.resourceIds);
}
final Set rIds = new HashSet(configInfo.facilities.resources.size());
for (final ResourceInfo resourceInfo : configInfo.facilities.resources) {
createResource(resourceInfo);
rIds.add(resourceInfo.id);
}
rIds.removeAll(reservedResourceIds);
final ContainerSystem containerSystem = systemInstance.getComponent(ContainerSystem.class);
if (containerSystem != null) {
postConstructResources(rIds, ParentClassLoaderFinder.Helper.get(), containerSystem.getJNDIContext(), null);
}else {
logger.error("ContainerSystem not initialized");
}
// Containers
for (final ContainerInfo serviceInfo : containerSystemInfo.containers) {
createContainer(serviceInfo);
}
createJavaGlobal(); // before any deployment bind global to be able to share the same context
for (final AppInfo appInfo : containerSystemInfo.applications) {
try {
createApplication(appInfo, createAppClassLoader(appInfo));
} catch (final DuplicateDeploymentIdException e) {
// already logged.
} catch (final Throwable e) {
logger.error("appNotDeployed", e, appInfo.path);
final DeploymentExceptionManager exceptionManager = systemInstance.getComponent(DeploymentExceptionManager.class);
if (Exception.class.isInstance(exceptionManager)) {
exceptionManager.saveDeploymentException(appInfo, Exception.class.cast(exceptionManager));
}
}
}
systemInstance.fireEvent(new ContainerSystemPostCreate());
}
private void createJavaGlobal() {
try {
containerSystem.getJNDIContext().createSubcontext("global");
} catch (final NamingException e) {
// no-op
}
}
public boolean isDeployed(final String path) {
return deployedApplications.containsKey(ProvisioningUtil.realLocation(path));
}
public Collection getDeployedApplications() {
return new ArrayList(deployedApplications.values());
}
public AppContext createApplication(final EjbJarInfo ejbJar) throws NamingException, IOException, OpenEJBException {
return createEjbJar(ejbJar);
}
public AppContext createEjbJar(final EjbJarInfo ejbJar) throws NamingException, IOException, OpenEJBException {
final AppInfo appInfo = new AppInfo();
appInfo.path = ejbJar.path;
appInfo.appId = ejbJar.moduleName;
appInfo.ejbJars.add(ejbJar);
return createApplication(appInfo);
}
public AppContext createApplication(final EjbJarInfo ejbJar, final ClassLoader classLoader) throws NamingException, IOException, OpenEJBException {
return createEjbJar(ejbJar, classLoader);
}
public AppContext createEjbJar(final EjbJarInfo ejbJar, final ClassLoader classLoader) throws NamingException, IOException, OpenEJBException {
final AppInfo appInfo = new AppInfo();
appInfo.path = ejbJar.path;
appInfo.appId = ejbJar.moduleName;
appInfo.ejbJars.add(ejbJar);
return createApplication(appInfo, classLoader);
}
public AppContext createClient(final ClientInfo clientInfo) throws NamingException, IOException, OpenEJBException {
final AppInfo appInfo = new AppInfo();
appInfo.path = clientInfo.path;
appInfo.appId = clientInfo.moduleId;
appInfo.clients.add(clientInfo);
return createApplication(appInfo);
}
public AppContext createClient(final ClientInfo clientInfo, final ClassLoader classLoader) throws NamingException, IOException, OpenEJBException {
final AppInfo appInfo = new AppInfo();
appInfo.path = clientInfo.path;
appInfo.appId = clientInfo.moduleId;
appInfo.clients.add(clientInfo);
return createApplication(appInfo, classLoader);
}
public AppContext createConnector(final ConnectorInfo connectorInfo) throws NamingException, IOException, OpenEJBException {
final AppInfo appInfo = new AppInfo();
appInfo.path = connectorInfo.path;
appInfo.appId = connectorInfo.moduleId;
appInfo.connectors.add(connectorInfo);
return createApplication(appInfo);
}
public AppContext createConnector(final ConnectorInfo connectorInfo, final ClassLoader classLoader) throws NamingException, IOException, OpenEJBException {
final AppInfo appInfo = new AppInfo();
appInfo.path = connectorInfo.path;
appInfo.appId = connectorInfo.moduleId;
appInfo.connectors.add(connectorInfo);
return createApplication(appInfo, classLoader);
}
public AppContext createWebApp(final WebAppInfo webAppInfo) throws NamingException, IOException, OpenEJBException {
final AppInfo appInfo = new AppInfo();
appInfo.path = webAppInfo.path;
appInfo.appId = webAppInfo.moduleId;
appInfo.webApps.add(webAppInfo);
return createApplication(appInfo);
}
public AppContext createWebApp(final WebAppInfo webAppInfo, final ClassLoader classLoader) throws NamingException, IOException, OpenEJBException {
final AppInfo appInfo = new AppInfo();
appInfo.path = webAppInfo.path;
appInfo.appId = webAppInfo.moduleId;
appInfo.webApps.add(webAppInfo);
return createApplication(appInfo, classLoader);
}
public AppContext createApplication(final AppInfo appInfo) throws OpenEJBException, IOException, NamingException {
return createApplication(appInfo, createAppClassLoader(appInfo));
}
public AppContext createApplication(final AppInfo appInfo, final ClassLoader classLoader) throws OpenEJBException, IOException, NamingException {
return createApplication(appInfo, classLoader, true);
}
private AppContext createApplication(final AppInfo appInfo, ClassLoader classLoader, final boolean start) throws OpenEJBException, IOException, NamingException {
try {
mergeServices(appInfo);
} catch (final URISyntaxException e) {
logger.info("Failed to merge resources.xml services and appInfo.properties");
}
// The path is used in the UrlCache, command line deployer, JNDI name templates, tomcat integration and a few other places
if (appInfo.appId == null) {
throw new IllegalArgumentException("AppInfo.appId cannot be null");
}
if (appInfo.path == null) {
appInfo.path = appInfo.appId;
}
Extensions.addExtensions(classLoader, appInfo.eventClassesNeedingAppClassloader);
logger.info("createApplication.start", appInfo.path);
final Context containerSystemContext = containerSystem.getJNDIContext();
// To start out, ensure we don't already have any beans deployed with duplicate IDs.
// This is a conflict we fail to handle.
this.checkForDuplicates(appInfo);
//Construct the global and app jndi contexts for this app
final InjectionBuilder injectionBuilder = new InjectionBuilder(classLoader);
final Set injections = new HashSet();
injections.addAll(injectionBuilder.buildInjections(appInfo.globalJndiEnc));
injections.addAll(injectionBuilder.buildInjections(appInfo.appJndiEnc));
final JndiEncBuilder globalBuilder = new JndiEncBuilder(appInfo.globalJndiEnc, injections, appInfo.appId, null, GLOBAL_UNIQUE_ID, classLoader, appInfo.properties);
final Map globalBindings = globalBuilder.buildBindings(JndiEncBuilder.JndiScope.global);
final Context globalJndiContext = globalBuilder.build(globalBindings);
final JndiEncBuilder appBuilder = new JndiEncBuilder(appInfo.appJndiEnc, injections, appInfo.appId, null, appInfo.appId, classLoader, appInfo.properties);
final Map appBindings = appBuilder.buildBindings(JndiEncBuilder.JndiScope.app);
final Context appJndiContext = appBuilder.build(appBindings);
try {
// Generate the cmp2/cmp1 concrete subclasses
final CmpJarBuilder cmpJarBuilder = new CmpJarBuilder(appInfo, classLoader);
final File generatedJar = cmpJarBuilder.getJarFile();
if (generatedJar != null) {
classLoader = ClassLoaderUtil.createClassLoader(appInfo.path, new URL[]{generatedJar.toURI().toURL()}, classLoader);
}
final AppContext appContext = new AppContext(appInfo.appId, SystemInstance.get(), classLoader, globalJndiContext, appJndiContext, appInfo.standaloneModule);
appContext.getProperties().putAll(appInfo.properties);
appContext.getInjections().addAll(injections);
appContext.getBindings().putAll(globalBindings);
appContext.getBindings().putAll(appBindings);
containerSystem.addAppContext(appContext);
appContext.set(AsynchronousPool.class, AsynchronousPool.create(appContext));
final Map lazyValidatorFactories = new HashMap();
final Map lazyValidators = new HashMap();
final boolean isGeronimo = SystemInstance.get().hasProperty("openejb.geronimo");
// Load units and fill validator maps
this.loadPersistenceUnits(appInfo, classLoader, containerSystemContext, appContext, lazyValidatorFactories, lazyValidators, isGeronimo);
// Connectors
for (final ConnectorInfo connector : appInfo.connectors) {
final ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
try {
// todo add undeployment code for these
if (connector.resourceAdapter != null) {
createResource(connector.resourceAdapter);
}
for (final ResourceInfo outbound : connector.outbound) {
createResource(outbound);
outbound.properties.setProperty("openejb.connector", "true"); // set it after as a marker but not as an attribute (no getOpenejb().setConnector(...))
}
for (final MdbContainerInfo inbound : connector.inbound) {
createContainer(inbound);
}
for (final ResourceInfo adminObject : connector.adminObject) {
createResource(adminObject);
}
} finally {
Thread.currentThread().setContextClassLoader(oldClassLoader);
}
}
final List allDeployments = initEjbs(classLoader, appInfo, appContext, injections, new ArrayList(), null);
if ("true".equalsIgnoreCase(SystemInstance.get()
.getProperty(PROPAGATE_APPLICATION_EXCEPTIONS,
appInfo.properties.getProperty(PROPAGATE_APPLICATION_EXCEPTIONS, "false")))) {
propagateApplicationExceptions(appInfo, classLoader, allDeployments);
}
if ("true".equalsIgnoreCase(appInfo.properties.getProperty("openejb.cdi.activated", "true"))) {
new CdiBuilder().build(appInfo, appContext, allDeployments);
ensureWebBeansContext(appContext);
appJndiContext.bind("app/BeanManager", appContext.getBeanManager());
appContext.getBindings().put("app/BeanManager", appContext.getBeanManager());
}
// now cdi is started we can try to bind real validator factory and validator
if (!isGeronimo) {
bindValidators(containerSystemContext, lazyValidatorFactories, lazyValidators);
}
startEjbs(start, allDeployments);
// App Client
for (final ClientInfo clientInfo : appInfo.clients) {
bindInjections(classLoader, containerSystemContext, injectionBuilder, clientInfo);
}
// WebApp
final SystemInstance systemInstance = SystemInstance.get();
final WebAppBuilder webAppBuilder = systemInstance.getComponent(WebAppBuilder.class);
if (webAppBuilder != null) {
webAppBuilder.deployWebApps(appInfo, classLoader);
}
if (start) {
final EjbResolver globalEjbResolver = systemInstance.getComponent(EjbResolver.class);
if (globalEjbResolver != null) {
globalEjbResolver.addAll(appInfo.ejbJars);
}
}
// bind all global values on global context
bindGlobals(appContext.getBindings());
// deploy MBeans
for (final String mbean : appInfo.mbeans) {
deployMBean(appContext.getWebBeansContext(), classLoader, mbean, appInfo.jmx, appInfo.appId);
}
for (final EjbJarInfo ejbJarInfo : appInfo.ejbJars) {
for (final String mbean : ejbJarInfo.mbeans) {
deployMBean(appContext.getWebBeansContext(), classLoader, mbean, appInfo.jmx, ejbJarInfo.moduleName);
}
}
for (final ConnectorInfo connectorInfo : appInfo.connectors) {
for (final String mbean : connectorInfo.mbeans) {
deployMBean(appContext.getWebBeansContext(), classLoader, mbean, appInfo.jmx, appInfo.appId + ".add-lib");
}
}
postConstructResources(appInfo.resourceIds, classLoader, containerSystemContext, appContext);
deployedApplications.put(appInfo.path, appInfo);
resumePersistentSchedulers(appContext);
systemInstance.fireEvent(new AssemblerAfterApplicationCreated(appInfo, appContext, allDeployments));
logger.info("createApplication.success", appInfo.path);
return appContext;
} catch (final ValidationException ve) {
throw ve;
} catch (final Throwable t) {
try {
destroyApplication(appInfo);
} catch (final Exception e1) {
logger.debug("createApplication.undeployFailed", e1, appInfo.path);
}
throw new OpenEJBException(messages.format("createApplication.failed", appInfo.path), t);
}
}
private void bindInjections(final ClassLoader classLoader, final Context containerSystemContext, final InjectionBuilder injectionBuilder, final ClientInfo clientInfo) throws OpenEJBException, NamingException {
// determine the injections
final List clientInjections = injectionBuilder.buildInjections(clientInfo.jndiEnc);
// build the enc
final JndiEncBuilder jndiEncBuilder = new JndiEncBuilder(clientInfo.jndiEnc, clientInjections, "Bean", clientInfo.moduleId, null, clientInfo.uniqueId, classLoader, new Properties());
// if there is at least a remote client classes
// or if there is no local client classes
// then, we can set the client flag
if (clientInfo.remoteClients.size() > 0 || clientInfo.localClients.size() == 0) {
jndiEncBuilder.setClient(true);
}
jndiEncBuilder.setUseCrossClassLoaderRef(false);
final Context context = jndiEncBuilder.build(JndiEncBuilder.JndiScope.comp);
// Debug.printContext(context);
containerSystemContext.bind("openejb/client/" + clientInfo.moduleId, context);
if (clientInfo.path != null) {
context.bind("info/path", clientInfo.path);
}
if (clientInfo.mainClass != null) {
context.bind("info/mainClass", clientInfo.mainClass);
}
if (clientInfo.callbackHandler != null) {
context.bind("info/callbackHandler", clientInfo.callbackHandler);
}
context.bind("info/injections", clientInjections);
for (final String clientClassName : clientInfo.remoteClients) {
containerSystemContext.bind("openejb/client/" + clientClassName, clientInfo.moduleId);
}
for (final String clientClassName : clientInfo.localClients) {
containerSystemContext.bind("openejb/client/" + clientClassName, clientInfo.moduleId);
logger.getChildLogger("client").info("createApplication.createLocalClient", clientClassName, clientInfo.moduleId);
}
}
private void bindValidators(final Context containerSystemContext, final Map lazyValidatorFactories, final Map lazyValidators) throws OpenEJBException {
for (final Entry lazyValidator : lazyValidators.entrySet()) {
final String id = lazyValidator.getKey();
final ValidatorFactory factory = lazyValidatorFactories.get(lazyValidator.getKey()).getFactory();
try {
final String factoryName = VALIDATOR_FACTORY_NAMING_CONTEXT + id;
containerSystemContext.unbind(factoryName);
containerSystemContext.bind(factoryName, factory);
final String validatoryName = VALIDATOR_NAMING_CONTEXT + id;
try { // do it after factory cause of TCKs which expects validator to be created later
final Validator val = lazyValidator.getValue().getValidator();
containerSystemContext.unbind(validatoryName);
containerSystemContext.bind(validatoryName, val);
} catch (final Exception e) {
logger.error(e.getMessage(), e);
}
} catch (final NameAlreadyBoundException e) {
throw new OpenEJBException("ValidatorFactory already exists for module " + id, e);
} catch (final Exception e) {
throw new OpenEJBException(e);
}
}
}
private void loadPersistenceUnits(final AppInfo appInfo, final ClassLoader classLoader, final Context containerSystemContext, final AppContext appContext, final Map lazyValidatorFactories, final Map lazyValidators, final boolean isGeronimo) throws OpenEJBException {
// try to not create N times the same validator for a single app
final Map validatorFactoriesByConfig = new HashMap();
if (!isGeronimo) {
// Bean Validation
// ValidatorFactory needs to be put in the map sent to the entity manager factory
// so it has to be constructed before
final List vfs = listCommonInfoObjectsForAppInfo(appInfo);
final Map validatorFactories = new HashMap();
for (final CommonInfoObject info : vfs) {
final ComparableValidationConfig conf = new ComparableValidationConfig(
info.validationInfo.providerClassName, info.validationInfo.messageInterpolatorClass,
info.validationInfo.traversableResolverClass, info.validationInfo.constraintFactoryClass,
info.validationInfo.propertyTypes, info.validationInfo.constraintMappings
);
ValidatorFactory factory = validatorFactoriesByConfig.get(conf);
if (factory == null) {
try { // lazy cause of CDI :(
final LazyValidatorFactory handler = new LazyValidatorFactory(classLoader, info.validationInfo);
factory = (ValidatorFactory) Proxy.newProxyInstance(
appContext.getClassLoader(), VALIDATOR_FACTORY_INTERFACES, handler);
lazyValidatorFactories.put(info.uniqueId, handler);
} catch (final ValidationException ve) {
logger.warning("Failed to build the validation factory for module " + info.uniqueId, ve);
continue;
}
validatorFactoriesByConfig.put(conf, factory);
} else {
lazyValidatorFactories.put(info.uniqueId, LazyValidatorFactory.class.cast(Proxy.getInvocationHandler(factory)));
}
validatorFactories.put(info.uniqueId, factory);
}
// validators bindings
for (final Entry validatorFactory : validatorFactories.entrySet()) {
final String id = validatorFactory.getKey();
final ValidatorFactory factory = validatorFactory.getValue();
try {
containerSystemContext.bind(VALIDATOR_FACTORY_NAMING_CONTEXT + id, factory);
final Validator validator;
try {
final LazyValidator lazyValidator = new LazyValidator(factory);
validator = (Validator) Proxy.newProxyInstance(appContext.getClassLoader(), VALIDATOR_INTERFACES, lazyValidator);
lazyValidators.put(id, lazyValidator);
} catch (final Exception e) {
logger.error(e.getMessage(), e);
continue;
}
containerSystemContext.bind(VALIDATOR_NAMING_CONTEXT + id, validator);
} catch (final NameAlreadyBoundException e) {
throw new OpenEJBException("ValidatorFactory already exists for module " + id, e);
} catch (final Exception e) {
throw new OpenEJBException(e);
}
}
validatorFactories.clear();
}
// JPA - Persistence Units MUST be processed first since they will add ClassFileTransformers
// to the class loader which must be added before any classes are loaded
final Map units = new HashMap();
final PersistenceBuilder persistenceBuilder = new PersistenceBuilder(persistenceClassLoaderHandler);
for (final PersistenceUnitInfo info : appInfo.persistenceUnits) {
final ReloadableEntityManagerFactory factory;
try {
factory = persistenceBuilder.createEntityManagerFactory(info, classLoader, validatorFactoriesByConfig);
containerSystem.getJNDIContext().bind(PERSISTENCE_UNIT_NAMING_CONTEXT + info.id, factory);
units.put(info.name, PERSISTENCE_UNIT_NAMING_CONTEXT + info.id);
} catch (final NameAlreadyBoundException e) {
throw new OpenEJBException("PersistenceUnit already deployed: " + info.persistenceUnitRootUrl);
} catch (final Exception e) {
throw new OpenEJBException(e);
}
factory.register();
}
logger.debug("Loaded peristence units: " + units);
}
private void checkForDuplicates(final AppInfo appInfo) throws DuplicateDeploymentIdException {
final List used = new ArrayList();
for (final EjbJarInfo ejbJarInfo : appInfo.ejbJars) {
for (final EnterpriseBeanInfo beanInfo : ejbJarInfo.enterpriseBeans) {
if (containerSystem.getBeanContext(beanInfo.ejbDeploymentId) != null) {
used.add(beanInfo.ejbDeploymentId);
}
}
}
if (used.size() > 0) {
String message = logger.error("createApplication.appFailedDuplicateIds", appInfo.path);
for (final String id : used) {
logger.error("createApplication.deploymentIdInUse", id);
message += "\n " + id;
}
throw new DuplicateDeploymentIdException(message);
}
}
private void postConstructResources(
final Set resourceIds, final ClassLoader classLoader,
final Context containerSystemContext, final AppContext appContext) throws NamingException, OpenEJBException {
final Thread thread = Thread.currentThread();
final ClassLoader oldCl = thread.getContextClassLoader();
try {
thread.setContextClassLoader(classLoader);
final List resourceList = config.facilities.resources;
for (final ResourceInfo resourceInfo : resourceList) {
if (!resourceIds.contains(resourceInfo.id)) {
continue;
}
if (isTemplatizedResource(resourceInfo)) {
continue;
}
try {
Class> clazz;
try {
clazz = classLoader.loadClass(resourceInfo.className);
} catch (final ClassNotFoundException cnfe) { // custom classpath
clazz = containerSystemContext.lookup(OPENEJB_RESOURCE_JNDI_PREFIX + resourceInfo.id).getClass();
}
final boolean initialize = "true".equalsIgnoreCase(String.valueOf(resourceInfo.properties.remove("InitializeAfterDeployment")));
final AnnotationFinder finder = Proxy.isProxyClass(clazz) ?
null : new AnnotationFinder(new ClassesArchive(ancestors(clazz)));
final List postConstructs = finder == null ?
Collections.emptyList() : finder.findAnnotatedMethods(PostConstruct.class);
final List preDestroys = finder == null ?
Collections.emptyList() : finder.findAnnotatedMethods(PreDestroy.class);
resourceInfo.postConstructMethods = new ArrayList();
resourceInfo.preDestroyMethods = new ArrayList();
addMethodsToResourceInfo(resourceInfo.postConstructMethods, PostConstruct.class, postConstructs);
addMethodsToResourceInfo(resourceInfo.preDestroyMethods, PreDestroy.class, preDestroys);
CreationalContext> creationalContext = null;
Object originalResource = null;
if (!postConstructs.isEmpty() || initialize) {
originalResource = containerSystemContext.lookup(OPENEJB_RESOURCE_JNDI_PREFIX + resourceInfo.id);
Object resource = originalResource;
if (Reference.class.isInstance(resource)) {
resource = unwrapReference(resource);
this.bindResource(resourceInfo.id, resource, true);
}
try {
// wire up CDI
if (appContext != null) {
final BeanManagerImpl beanManager = appContext.getWebBeansContext().getBeanManagerImpl();
if (beanManager.isInUse()) {
creationalContext = beanManager.createCreationalContext(null);
OWBInjector.inject(beanManager, resource, creationalContext);
}
}
if (!"none".equals(resourceInfo.postConstruct)) {
if (resourceInfo.postConstruct != null) {
final Method p = clazz.getDeclaredMethod(resourceInfo.postConstruct);
if (!p.isAccessible()) {
SetAccessible.on(p);
}
p.invoke(resource);
}
for (final Method m : postConstructs) {
if (!m.isAccessible()) {
SetAccessible.on(m);
}
m.invoke(resource);
}
}
} catch (final Exception e) {
logger.fatal("Error calling @PostConstruct method on " + resource.getClass().getName());
throw new OpenEJBException(e);
}
}
if (!"none".equals(resourceInfo.preDestroy)) {
if (resourceInfo.preDestroy != null) {
final Method p = clazz.getDeclaredMethod(resourceInfo.preDestroy);
if (!p.isAccessible()) {
SetAccessible.on(p);
}
preDestroys.add(p);
}
if (!preDestroys.isEmpty() || creationalContext != null) {
final String name = OPENEJB_RESOURCE_JNDI_PREFIX + resourceInfo.id;
if (originalResource == null) {
originalResource = containerSystemContext.lookup(name);
}
this.bindResource(resourceInfo.id, new ResourceInstance(name, originalResource, preDestroys, creationalContext), true);
}
}
// log unused now for these resources now we built the resource completely and @PostConstruct can have used injected properties
if (resourceInfo.unsetProperties != null) {
final Set unsetKeys = resourceInfo.unsetProperties.stringPropertyNames();
for (final String key : unsetKeys) { // don't use keySet to auto filter txMgr for instance and not real properties!
unusedProperty(resourceInfo.id, logger, key);
}
}
} catch (final Exception e) {
logger.fatal("Error calling PostConstruct method on " + resourceInfo.id);
logger.fatal("Resource " + resourceInfo.id + " could not be initialized. Application will be undeployed.");
throw new OpenEJBException(e);
}
}
} finally {
thread.setContextClassLoader(oldCl);
}
}
private void addMethodsToResourceInfo(final List list, final Class type, final List methodList) throws OpenEJBException {
for (final Method method : methodList) {
if (method.getParameterTypes().length > 0) {
throw new OpenEJBException(type.getSimpleName() + " method " +
method.getDeclaringClass().getName() + "."
+ method.getName() + " should have zero arguments");
}
list.add(method.getName());
}
}
private static boolean isTemplatizedResource(final ResourceInfo resourceInfo) { // ~ container resource even if not 100% right
return resourceInfo.className == null || resourceInfo.className.isEmpty();
}
public static void mergeServices(final AppInfo appInfo) throws URISyntaxException {
for (final ServiceInfo si : appInfo.services) { // used lazily by JaxWsServiceObjectFactory, we could do the same for resources
if (!appInfo.properties.containsKey(si.id)) {
final Map query = new HashMap();
if (si.types != null && !si.types.isEmpty()) {
query.put("type", si.types.iterator().next());
}
if (si.className != null) {
query.put("class-name", si.className);
}
if (si.factoryMethod != null) {
query.put("factory-name", si.factoryMethod);
}
if (si.constructorArgs != null && !si.constructorArgs.isEmpty()) {
query.put("constructor", Join.join(",", si.constructorArgs));
}
appInfo.properties.put(si.id, "new://Service?" + URISupport.createQueryString(query));
if (si.properties != null) {
for (final String k : si.properties.stringPropertyNames()) {
appInfo.properties.setProperty(si.id + "." + k, si.properties.getProperty(k));
}
}
}
}
}
private static List listCommonInfoObjectsForAppInfo(final AppInfo appInfo) {
final List vfs = new ArrayList(
appInfo.clients.size() + appInfo.connectors.size() +
appInfo.ejbJars.size() + appInfo.webApps.size());
for (final ClientInfo clientInfo : appInfo.clients) {
vfs.add(clientInfo);
}
for (final ConnectorInfo connectorInfo : appInfo.connectors) {
vfs.add(connectorInfo);
}
for (final EjbJarInfo ejbJarInfo : appInfo.ejbJars) {
vfs.add(ejbJarInfo);
}
for (final WebAppInfo webAppInfo : appInfo.webApps) {
vfs.add(webAppInfo);
}
return vfs;
}
public void bindGlobals(final Map bindings) throws NamingException {
final Context containerSystemContext = containerSystem.getJNDIContext();
for (final Entry value : bindings.entrySet()) {
final String path = value.getKey();
// keep only global bindings
if (path.startsWith("module/") || path.startsWith("app/") || path.startsWith("comp/") || path.equalsIgnoreCase("global/dummy")) {
continue;
}
// a bit weird but just to be consistent if user doesn't lookup directly the resource
final Context lastContext = Contexts.createSubcontexts(containerSystemContext, path);
try {
lastContext.rebind(path.substring(path.lastIndexOf("/") + 1, path.length()), value.getValue());
} catch (final NameAlreadyBoundException nabe) {
nabe.printStackTrace();
}
containerSystemContext.rebind(path, value.getValue());
}
}
private void propagateApplicationExceptions(final AppInfo appInfo, final ClassLoader classLoader, final List allDeployments) {
for (final BeanContext context : allDeployments) {
if (BeanContext.Comp.class.equals(context.getBeanClass())) {
continue;
}
for (final EjbJarInfo jar : appInfo.ejbJars) {
for (final ApplicationExceptionInfo exception : jar.applicationException) {
try {
final Class> exceptionClass = classLoader.loadClass(exception.exceptionClass);
context.addApplicationException(exceptionClass, exception.rollback, exception.inherited);
} catch (final Exception e) {
// no-op: not a big deal since by jar config is respected, mainly means propagation didn't work because of classloader constraints
}
}
}
}
}
private void resumePersistentSchedulers(final AppContext appContext) {
final Scheduler globalScheduler = SystemInstance.get().getComponent(Scheduler.class);
final Collection schedulers = new ArrayList();
for (final BeanContext ejb : appContext.getBeanContexts()) {
final Scheduler scheduler = ejb.get(Scheduler.class);
if (scheduler == null || scheduler == globalScheduler || schedulers.contains(scheduler)) {
continue;
}
schedulers.add(scheduler);
try {
scheduler.resumeAll();
} catch (final Exception e) {
logger.warning("Failed to resume scheduler for " + ejb.getEjbName(), e);
}
}
}
public List initEjbs(final ClassLoader classLoader, final AppInfo appInfo, final AppContext appContext,
final Set injections, final List allDeployments, final String webappId) throws OpenEJBException {
final String globalTimersOn = SystemInstance.get().getProperty(OPENEJB_TIMERS_ON, "true");
final EjbJarBuilder ejbJarBuilder = new EjbJarBuilder(props, appContext);
for (final EjbJarInfo ejbJar : appInfo.ejbJars) {
boolean skip = false;
if (!appInfo.webAppAlone) {
if (webappId == null) {
skip = ejbJar.webapp; // we look for the lib part of the ear so deploy only if not a webapp
} else if (!ejbJar.webapp
|| (!ejbJar.moduleId.equals(webappId) && !ejbJar.properties.getProperty("openejb.ejbmodule.webappId", "-").equals(webappId))) {
skip = true; // we look for a particular webapp deployment so deploy only if this webapp
}
}
if (skip) {
continue;
}
final HashMap deployments = ejbJarBuilder.build(ejbJar, injections, classLoader);
final JaccPermissionsBuilder jaccPermissionsBuilder = new JaccPermissionsBuilder();
final PolicyContext policyContext = jaccPermissionsBuilder.build(ejbJar, deployments);
jaccPermissionsBuilder.install(policyContext);
final TransactionPolicyFactory transactionPolicyFactory = createTransactionPolicyFactory(ejbJar, classLoader);
for (final BeanContext beanContext : deployments.values()) {
beanContext.setTransactionPolicyFactory(transactionPolicyFactory);
}
final MethodTransactionBuilder methodTransactionBuilder = new MethodTransactionBuilder();
methodTransactionBuilder.build(deployments, ejbJar.methodTransactions);
final MethodConcurrencyBuilder methodConcurrencyBuilder = new MethodConcurrencyBuilder();
methodConcurrencyBuilder.build(deployments, ejbJar.methodConcurrency);
for (final BeanContext beanContext : deployments.values()) {
containerSystem.addDeployment(beanContext);
}
//bind ejbs into global jndi
jndiBuilder.build(ejbJar, deployments);
// setup timers/asynchronous methods - must be after transaction attributes are set
for (final BeanContext beanContext : deployments.values()) {
if (beanContext.getComponentType() != BeanType.STATEFUL) {
final Method ejbTimeout = beanContext.getEjbTimeout();
boolean timerServiceRequired = false;
if (ejbTimeout != null) {
// If user set the tx attribute to RequiresNew change it to Required so a new transaction is not started
if (beanContext.getTransactionType(ejbTimeout) == TransactionType.RequiresNew) {
beanContext.setMethodTransactionAttribute(ejbTimeout, TransactionType.Required);
}
timerServiceRequired = true;
}
for (final Iterator> it = beanContext.iteratorMethodContext(); it.hasNext(); ) {
final Map.Entry entry = it.next();
final MethodContext methodContext = entry.getValue();
if (methodContext.getSchedules().size() > 0) {
timerServiceRequired = true;
final Method method = entry.getKey();
//TODO Need ?
if (beanContext.getTransactionType(method) == TransactionType.RequiresNew) {
beanContext.setMethodTransactionAttribute(method, TransactionType.Required);
}
}
}
if (timerServiceRequired && "true".equalsIgnoreCase(appInfo.properties.getProperty(OPENEJB_TIMERS_ON, globalTimersOn))) {
// Create the timer
final EjbTimerServiceImpl timerService = new EjbTimerServiceImpl(beanContext, newTimerStore(beanContext));
//Load auto-start timers
final TimerStore timerStore = timerService.getTimerStore();
for (final Iterator> it = beanContext.iteratorMethodContext(); it.hasNext(); ) {
final Map.Entry entry = it.next();
final MethodContext methodContext = entry.getValue();
for (final ScheduleData scheduleData : methodContext.getSchedules()) {
timerStore.createCalendarTimer(timerService,
(String) beanContext.getDeploymentID(),
null,
entry.getKey(),
scheduleData.getExpression(),
scheduleData.getConfig(),
true);
}
}
beanContext.setEjbTimerService(timerService);
} else {
beanContext.setEjbTimerService(new NullEjbTimerServiceImpl());
}
}
//set asynchronous methods transaction
//TODO ???
for (final Iterator> it = beanContext.iteratorMethodContext(); it.hasNext(); ) {
final Entry entry = it.next();
if (entry.getValue().isAsynchronous() && beanContext.getTransactionType(entry.getKey()) == TransactionType.RequiresNew) {
beanContext.setMethodTransactionAttribute(entry.getKey(), TransactionType.Required);
}
}
// if local bean or mdb generate proxy class now to avoid bottleneck on classloader later
if (beanContext.isLocalbean() && !beanContext.getComponentType().isMessageDriven() && !beanContext.isDynamicallyImplemented()) {
final List interfaces = new ArrayList(3);
interfaces.add(Serializable.class);
interfaces.add(IntraVmProxy.class);
final BeanType type = beanContext.getComponentType();
if (BeanType.STATEFUL.equals(type) || BeanType.MANAGED.equals(type)) {
interfaces.add(BeanContext.Removable.class);
}
beanContext.set(
BeanContext.ProxyClass.class,
new BeanContext.ProxyClass(
beanContext,
interfaces.toArray(new Class>[interfaces.size()])
));
}
}
// process application exceptions
for (final ApplicationExceptionInfo exceptionInfo : ejbJar.applicationException) {
try {
final Class exceptionClass = classLoader.loadClass(exceptionInfo.exceptionClass);
for (final BeanContext beanContext : deployments.values()) {
beanContext.addApplicationException(exceptionClass, exceptionInfo.rollback, exceptionInfo.inherited);
}
} catch (final ClassNotFoundException e) {
logger.error("createApplication.invalidClass", e, exceptionInfo.exceptionClass, e.getMessage());
}
}
allDeployments.addAll(deployments.values());
}
final List ejbs = sort(allDeployments);
appContext.getBeanContexts().addAll(ejbs);
return ejbs;
}
private TimerStore newTimerStore(final BeanContext beanContext) {
for (final DeploymentContext context : Arrays.asList(beanContext, beanContext.getModuleContext(), beanContext.getModuleContext().getAppContext())) {
final String timerStoreClass = context.getProperties().getProperty(TIMER_STORE_CLASS);
if (timerStoreClass != null) {
logger.info("Found timer class: " + timerStoreClass);
try {
final Class> clazz = beanContext.getClassLoader().loadClass(timerStoreClass);
try {
final Constructor> constructor = clazz.getConstructor(TransactionManager.class);
return TimerStore.class.cast(constructor.newInstance(EjbTimerServiceImpl.getDefaultTransactionManager()));
} catch (final Exception ignored) {
return TimerStore.class.cast(clazz.newInstance());
}
} catch (final Exception e) {
logger.error("Failed to instantiate " + timerStoreClass + ", using default memory timer store");
}
}
}
return new MemoryTimerStore(EjbTimerServiceImpl.getDefaultTransactionManager());
}
public void startEjbs(final boolean start, final List allDeployments) throws OpenEJBException {
// now that everything is configured, deploy to the container
if (start) {
SystemInstance.get().fireEvent(new BeforeStartEjbs(allDeployments));
final Collection toStart = new ArrayList();
// deploy
for (final BeanContext deployment : allDeployments) {
try {
final Container container = deployment.getContainer();
if (container.getBeanContext(deployment.getDeploymentID()) == null) {
container.deploy(deployment);
if (!((String) deployment.getDeploymentID()).endsWith(".Comp")
&& !deployment.isHidden()) {
logger.info("createApplication.createdEjb", deployment.getDeploymentID(), deployment.getEjbName(), container.getContainerID());
}
if (logger.isDebugEnabled()) {
for (final Map.Entry entry : deployment.getProperties().entrySet()) {
logger.info("createApplication.createdEjb.property", deployment.getEjbName(), entry.getKey(), entry.getValue());
}
}
toStart.add(deployment);
}
} catch (final Throwable t) {
throw new OpenEJBException("Error deploying '" + deployment.getEjbName() + "'. Exception: " + t.getClass() + ": " + t.getMessage(), t);
}
}
// start
for (final BeanContext deployment : toStart) {
try {
final Container container = deployment.getContainer();
container.start(deployment);
if (!((String) deployment.getDeploymentID()).endsWith(".Comp")
&& !deployment.isHidden()) {
logger.info("createApplication.startedEjb", deployment.getDeploymentID(), deployment.getEjbName(), container.getContainerID());
}
} catch (final Throwable t) {
throw new OpenEJBException("Error starting '" + deployment.getEjbName() + "'. Exception: " + t.getClass() + ": " + t.getMessage(), t);
}
}
}
}
@SuppressWarnings("unchecked")
private void deployMBean(final WebBeansContext wc, final ClassLoader cl, final String mbeanClass, final Properties appMbeans, final String id) {
if (LocalMBeanServer.isJMXActive()) {
final Class> clazz;
try {
clazz = cl.loadClass(mbeanClass);
} catch (final ClassNotFoundException e) {
throw new OpenEJBRuntimeException(e);
}
// cdi can be off so init with null bean in this case
final Bean> bean;
final BeanManager bm;
if (wc == null) {
bm = null;
bean = null;
} else {
bm = wc.getBeanManagerImpl();
final Set> beans = bm.getBeans(clazz);
bean = bm.resolve(beans);
}
// create the MBean instance with cdi if possible or manually otherwise
final Object instance;
final CreationalContext creationalContext;
if (bean == null) {
try {
instance = clazz.newInstance();
} catch (final InstantiationException e) {
logger.error("the mbean " + mbeanClass + " Failed to be registered because it Failed to be instantiated", e);
return;
} catch (final IllegalAccessException e) {
logger.error("the mbean " + mbeanClass + " Failed to be registered because it Failed to be accessed", e);
return;
}
creationalContext = null;
} else {
creationalContext = bm.createCreationalContext(bean);
instance = bm.getReference(bean, clazz, creationalContext);
}
final MBeanServer server = LocalMBeanServer.get();
try {
final ObjectName leaf = new ObjectNameBuilder("openejb.user.mbeans")
.set("application", id)
.set("group", clazz.getPackage().getName())
.set("name", clazz.getSimpleName())
.build();
server.registerMBean(new DynamicMBeanWrapper(wc, instance), leaf);
appMbeans.put(mbeanClass, leaf.getCanonicalName());
if (creationalContext != null && (bean.getScope() == null || Dependent.class.equals(bean.getScope()))) {
creationalContextForAppMbeans.put(leaf, creationalContext);
}
logger.info("Deployed MBean(" + leaf.getCanonicalName() + ")");
} catch (final Exception e) {
logger.error("the mbean " + mbeanClass + " Failed to be registered", e);
}
}
}
private void ensureWebBeansContext(final AppContext appContext) {
WebBeansContext webBeansContext = appContext.get(WebBeansContext.class);
if (webBeansContext == null) {
webBeansContext = appContext.getWebBeansContext();
} else {
if (null == appContext.getWebBeansContext()) {
appContext.setWebBeansContext(webBeansContext);
}
return;
}
if (webBeansContext == null) {
final Map, Object> services = new HashMap, Object>();
services.put(JNDIService.class, new OpenEJBJndiService());
services.put(AppContext.class, appContext);
services.put(TransactionService.class, new OpenEJBTransactionService());
services.put(ScannerService.class, new CdiScanner());
services.put(ELAdaptor.class, new CustomELAdapter(appContext));
services.put(LoaderService.class, new OptimizedLoaderService());
final Properties properties = new Properties();
properties.setProperty(org.apache.webbeans.spi.SecurityService.class.getName(), ManagedSecurityService.class.getName());
webBeansContext = new WebBeansContext(services, properties);
webBeansContext.registerService(ContextsService.class, new CdiAppContextsService(webBeansContext, true));
webBeansContext.registerService(ResourceInjectionService.class, new CdiResourceInjectionService(webBeansContext));
appContext.setCdiEnabled(false);
final Object obj = services.get(TransactionService.class);
if (null != obj) {
OpenEJBTransactionService.class.cast(obj).setWebBeansContext(webBeansContext);
}
appContext.set(WebBeansContext.class, webBeansContext);
appContext.setWebBeansContext(webBeansContext);
}
}
private TransactionPolicyFactory createTransactionPolicyFactory(final EjbJarInfo ejbJar, final ClassLoader classLoader) {
TransactionPolicyFactory factory = null;
final Object value = ejbJar.properties.get(TransactionPolicyFactory.class.getName());
if (TransactionPolicyFactory.class.isInstance(value)) {
factory = TransactionPolicyFactory.class.cast(value);
} else if (String.class.isInstance(value)) {
try {
final String[] parts = String.class.cast(value).split(":", 2);
final ResourceFinder finder = new ResourceFinder("META-INF", classLoader);
final Map> plugins = finder.mapAvailableImplementations(TransactionPolicyFactory.class);
final Class extends TransactionPolicyFactory> clazz = plugins.get(parts[0]);
if (clazz != null) {
if (parts.length == 1) {
factory = clazz.getConstructor(String.class).newInstance(parts[1]);
} else {
factory = clazz.newInstance();
}
}
} catch (final Exception ignored) {
// couldn't determine the plugins, which isn't fatal
}
}
if (factory == null) {
factory = new JtaTransactionPolicyFactory(transactionManager);
}
return factory;
}
private static List sort(List deployments) {
// Sort all the singletons to the back of the list. We want to make sure
// all non-singletons are created first so that if a singleton refers to them
// they are available.
Collections.sort(deployments, new Comparator() {
@Override
public int compare(final BeanContext a, final BeanContext b) {
final int aa = a.getComponentType() == BeanType.SINGLETON ? 1 : 0;
final int bb = b.getComponentType() == BeanType.SINGLETON ? 1 : 0;
return aa - bb;
}
});
// Sort all the beans with references to the back of the list. Beans
// without references to ther beans will be deployed first.
deployments = References.sort(deployments, new References.Visitor() {
@Override
public String getName(final BeanContext t) {
return (String) t.getDeploymentID();
}
@Override
public Set getReferences(final BeanContext t) {
return t.getDependsOn();
}
});
// Now Sort all the MDBs to the back of the list. The Resource Adapter
// may attempt to use the MDB on endpointActivation and the MDB may have
// references to other ejbs that would need to be available first.
Collections.sort(deployments, new Comparator() {
@Override
public int compare(final BeanContext a, final BeanContext b) {
final int aa = a.getComponentType() == BeanType.MESSAGE_DRIVEN ? 1 : 0;
final int bb = b.getComponentType() == BeanType.MESSAGE_DRIVEN ? 1 : 0;
return aa - bb;
}
});
return deployments;
}
@Override
public void destroy() {
final ReentrantLock l = lock;
l.lock();
try {
SystemInstance.get().fireEvent(new ContainerSystemPreDestroy());
try {
EjbTimerServiceImpl.shutdown();
} catch (final Exception e) {
logger.warning("Unable to shutdown scheduler", e);
}
logger.debug("Undeploying Applications");
final Assembler assembler = this;
final List deployedApps = new ArrayList(assembler.getDeployedApplications());
Collections.reverse(deployedApps); // if an app relies on the previous one it surely relies on it too at undeploy time
for (final AppInfo appInfo : deployedApps) {
try {
assembler.destroyApplication(appInfo.path);
} catch (final UndeployException e) {
logger.error("Undeployment failed: " + appInfo.path, e);
} catch (final NoSuchApplicationException e) {
//Ignore
}
}
final Iterator it = containerObjectNames.iterator();
final MBeanServer server = LocalMBeanServer.get();
while (it.hasNext()) {
try {
server.unregisterMBean(it.next());
} catch (final Exception ignored) {
// no-op
}
it.remove();
}
try {
remoteResourceMonitor.unregister();
} catch (final Exception ignored) {
// no-op
}
NamingEnumeration namingEnumeration = null;
try {
namingEnumeration = containerSystem.getJNDIContext().listBindings("openejb/Resource");
} catch (final NamingException ignored) {
// no resource adapters were created
}
destroyResourceTree("openejb/Resource", namingEnumeration);
try {
containerSystem.getJNDIContext().unbind("java:global");
} catch (final NamingException ignored) {
// no-op
}
SystemInstance.get().removeComponent(OpenEjbConfiguration.class);
SystemInstance.get().removeComponent(JtaEntityManagerRegistry.class);
SystemInstance.get().removeComponent(TransactionSynchronizationRegistry.class);
SystemInstance.get().removeComponent(EjbResolver.class);
SystemInstance.get().fireEvent(new AssemblerDestroyed());
SystemInstance.reset();
} finally {
l.unlock();
}
}
//TODO: add Jndi name to DestroyingResource
private Collection destroyResourceTree(final String name, final NamingEnumeration namingEnumeration) {
final List resources = new LinkedList();
while (namingEnumeration != null && namingEnumeration.hasMoreElements()) {
final Binding binding = namingEnumeration.nextElement();
final String boundName = name + "/" + binding.getName();
String id = boundName;
if (id.startsWith(OPENEJB_RESOURCE_JNDI_PREFIX)) {
id = id.substring(OPENEJB_RESOURCE_JNDI_PREFIX.length());
}
final Object object = binding.getObject();
if (Context.class.isInstance(object)) {
try {
final NamingEnumeration bindings = Context.class.cast(object).listBindings("");
resources.addAll(destroyResourceTree(boundName, bindings));
} catch (final NamingException e) {
logger.error("Error removing bindings from " + boundName, e);
}
} else if (LazyResource.class.isInstance(object)) {
removeResourceInfo(id);
try {
containerSystem.getJNDIContext().unbind(boundName);
} catch (final NamingException e) {
logger.error("Error unbinding " + boundName, e);
}
} else {
resources.add(new DestroyingResource(binding.getName(), binding.getClassName(), object));
}
}
Collections.sort(resources, new Comparator() { // end by destroying RA after having closed CF pool for jms for instance
@Override
public int compare(final DestroyingResource o1, final DestroyingResource o2) {
if (ResourceAdapter.class.isInstance(o2.instance) && !ResourceAdapter.class.isInstance(o1.instance)) {
return -1;
}
return 1;
}
});
for (final DestroyingResource resource : resources) {
try {
destroyResource(resource.name, resource.clazz, resource.instance);
} catch (final Throwable th) {
logger.debug(th.getMessage(), th);
}
}
return resources;
}
private void destroyResource(final String name, final String className, final Object object) {
if (ResourceAdapterReference.class.isInstance(object)) {
final ResourceAdapterReference resourceAdapter = ResourceAdapterReference.class.cast(object);
try {
logger.info("Stopping ResourceAdapter: " + name);
if (logger.isDebugEnabled()) {
logger.debug("Stopping ResourceAdapter: " + className);
}
if (null != resourceAdapter.pool && ExecutorService.class.isInstance(resourceAdapter.pool)) {
final ExecutorService es = ExecutorService.class.cast(resourceAdapter.pool);
es.shutdownNow();
}
resourceAdapter.ra.stop();
} catch (final Throwable t) {
logger.fatal("ResourceAdapter Shutdown Failed: " + name, t);
}
} else if (ResourceAdapter.class.isInstance(object)) {
final ResourceAdapter resourceAdapter = ResourceAdapter.class.cast(object);
try {
logger.info("Stopping ResourceAdapter: " + name);
if (logger.isDebugEnabled()) {
logger.debug("Stopping ResourceAdapter: " + className);
}
resourceAdapter.stop();
} catch (final Throwable t) {
logger.fatal("ResourceAdapter Shutdown Failed: " + name, t);
}
} else if (DataSourceFactory.knows(object)) {
int timeout;
try {
timeout = Integer.parseInt(SystemInstance.get().getProperty(TOMEE_DATASOURCE_DESTROY_TIMEOUT, "1000"));
if (timeout < 50) {
logger.warning(TOMEE_DATASOURCE_DESTROY_TIMEOUT + " must be at least 50");
timeout = 50;
}
if (timeout > 30000) {
timeout = 30000;
logger.warning(TOMEE_DATASOURCE_DESTROY_TIMEOUT + " must not be greater than 30000");
}
} catch (final Exception e) {
timeout = 1000;
}
final CountDownLatch latch = new CountDownLatch(1);
final Thread thread = new Thread("DataSource-Shutdown-" + name) {
@Override
public void run() {
try {
DataSourceFactory.destroy(object);
logger.info("Closed DataSource: " + name);
} catch (final Throwable t) {
//Ignore
} finally {
latch.countDown();
}
}
};
thread.start();
boolean closed;
try {
closed = latch.await(timeout, TimeUnit.MILLISECONDS);
} catch (final InterruptedException e) {
closed = false;
}
if (!closed) {
logger.warning("Failed to close DataSource within " + timeout + "ms: " + name);
}
} else if (ConnectorReference.class.isInstance(object)) {
final ConnectorReference cr = ConnectorReference.class.cast(object);
try {
final ConnectionManager cm = cr.getConnectionManager();
if (AbstractConnectionManager.class.isInstance(cm)) {
AbstractConnectionManager.class.cast(cm).doStop();
}
} catch (final Exception e) {
logger.debug("Not processing resource on destroy: " + className, e);
}
} else if (DestroyableResource.class.isInstance(object)) {
try {
DestroyableResource.class.cast(object).destroyResource();
} catch (final RuntimeException e) {
logger.error(e.getMessage(), e);
}
} else if (logger.isDebugEnabled() && !DataSource.class.isInstance(object)) {
logger.debug("Not processing resource on destroy: " + className);
}
callPreDestroy(name, object);
removeResourceInfo(name);
}
private void callPreDestroy(final String name, final Object object) {
if (object == null) {
return;
}
if (ResourceInstance.class.isInstance(object)) {
ResourceInstance.class.cast(object).destroyResource();
return;
}
final Class> objectClass = object.getClass();
final ResourceInfo ri = findResourceInfo(name);
if (ri == null) {
return;
}
final Set destroyMethods = new HashSet();
if (ri.preDestroy != null) {
destroyMethods.add(ri.preDestroy);
}
if (ri.preDestroyMethods != null && ri.preDestroyMethods.size() > 0) {
destroyMethods.addAll(ri.preDestroyMethods);
}
for (final String destroyMethod : destroyMethods) {
try {
final Method p = objectClass.getDeclaredMethod(destroyMethod);
if (!p.isAccessible()) {
SetAccessible.on(p);
}
p.invoke(object);
} catch (Exception e) {
logger.error("Unable to call pre destroy method " + destroyMethod + " on "
+ objectClass.getName() + ". Continuing with resource destruction.", e);
}
}
}
private ResourceInfo findResourceInfo(final String name) {
final List resourceInfos = config.facilities.resources;
for (final ResourceInfo resourceInfo : resourceInfos) {
if (resourceInfo.id.equals(name)) {
return resourceInfo;
}
}
return null;
}
public void removeResourceInfo(final String name) {
try {
//Ensure ResourceInfo for this resource is removed
final OpenEjbConfiguration configuration = SystemInstance.get().getComponent(OpenEjbConfiguration.class);
if (configuration != null) {
final Iterator iterator = configuration.facilities.resources.iterator();
while (iterator.hasNext()) {
final ResourceInfo info = iterator.next();
if (name.equals(info.id)) {
iterator.remove();
break;
}
}
}
} catch (final Exception e) {
logger.debug("Failed to purge resource on destroy: " + e.getMessage());
}
}
private static Object unwrapReference(final Object object) {
Object o = object;
while (o != null && Reference.class.isInstance(o)) {
try {
o = Reference.class.cast(o).getObject();
} catch (final NamingException e) {
// break
}
}
if (o == null) {
o = object;
}
return o;
}
public void destroyApplication(final String filePath) throws UndeployException, NoSuchApplicationException {
final ReentrantLock l = lock;
l.lock();
try {
final AppInfo appInfo = deployedApplications.remove(filePath);
if (appInfo == null) {
throw new NoSuchApplicationException(filePath);
}
destroyApplication(appInfo);
} finally {
l.unlock();
}
}
public void destroyApplication(final AppContext appContext) throws UndeployException {
final ReentrantLock l = lock;
l.lock();
try {
final AppInfo appInfo = deployedApplications.remove(appContext.getId());
if (appInfo == null) {
throw new IllegalStateException(String.format("Cannot find AppInfo for app: %s", appContext.getId()));
}
destroyApplication(appInfo);
} finally {
l.unlock();
}
}
public void destroyApplication(final AppInfo appInfo) throws UndeployException {
final ReentrantLock l = lock;
l.lock();
try {
deployedApplications.remove(appInfo.path);
logger.info("destroyApplication.start", appInfo.path);
final AppContext appContext = containerSystem.getAppContext(appInfo.appId);
if (null == appContext) {
logger.warning("Application id '" + appInfo.appId + "' not found in: " + Arrays.toString(containerSystem.getAppContextKeys()));
return;
}
final Context globalContext = containerSystem.getJNDIContext();
SystemInstance.get().fireEvent(new AssemblerBeforeApplicationDestroyed(appInfo, appContext));
final Map cb = appContext.getBindings();
for (final Entry value : cb.entrySet()) {
String path = value.getKey();
if (path.startsWith("global")) {
path = "java:" + path;
}
if (!path.startsWith("java:global")) {
continue;
}
unbind(globalContext, path);
unbind(globalContext, "openejb/global/" + path.substring("java:".length()));
unbind(globalContext, path.substring("java:global".length()));
}
if (appInfo.appId != null && !appInfo.appId.isEmpty() && !"openejb".equals(appInfo.appId)) {
unbind(globalContext, "global/" + appInfo.appId);
unbind(globalContext, appInfo.appId);
}
final EjbResolver globalResolver = new EjbResolver(null, EjbResolver.Scope.GLOBAL);
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 deployments = new ArrayList();
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
// Theoretically 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 bc : deployments) {
final String deploymentID = String.valueOf(bc.getDeploymentID());
try {
final Container container = bc.getContainer();
container.stop(bc);
} 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 clientIds = new ArrayList();
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);
}
final ClassLoader classLoader = appContext.getClassLoader();
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 (IvmContext.class.isInstance(globalContext)) {
final IvmContext ivmContext = IvmContext.class.cast(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("Failed to unregister " + objectName + " because the mbean was not found", e);
} catch (final MBeanRegistrationException e) {
logger.warning("Failed to unregister " + objectName, e);
} catch (final MalformedObjectNameException mone) {
logger.warning("Failed to 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 (ContextualJndiReference.class.isInstance(object)) {
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("Failed to 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("Failed to 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("Failed to unbind resource '{0}'", connector);
}
for (final ResourceInfo outbound : connector.outbound) {
try {
destroyLookedUpResource(globalContext, outbound.id, OPENEJB_RESOURCE_JNDI_PREFIX + outbound.id);
} catch (final Exception e) {
// no-op
}
}
for (final ResourceInfo outbound : connector.adminObject) {
try {
destroyLookedUpResource(globalContext, outbound.id, OPENEJB_RESOURCE_JNDI_PREFIX + outbound.id);
} catch (final Exception e) {
// no-op
}
}
for (final MdbContainerInfo container : connector.inbound) {
try {
containerSystem.removeContainer(container.id);
config.containerSystem.containers.remove(container);
this.containerSystem.getJNDIContext().unbind(JAVA_OPENEJB_NAMING_CONTEXT + container.service + "/" + container.id);
} catch (final Exception e) {
// no-op
}
}
}
final WebBeansContext webBeansContext = appContext.getWebBeansContext();
if (webBeansContext != null) {
final ClassLoader old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(classLoader);
try {
webBeansContext.getService(ContainerLifecycle.class).stopApplication(null);
} finally {
Thread.currentThread().setContextClassLoader(old);
}
}
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;
}
Assembler.resetSlf4j(logger);
Logger.configure(true);
logger.info("destroyApplication.success", appInfo.path);
} finally {
l.unlock();
}
}
private static void resetSlf4j(final Logger logger) {
final Method m = Assembler.SLF4J_RESET.get();
if (null != m) {
try {
m.invoke(null);
logger.info("Reset slf4j on application undeployment");
} catch (final InvocationTargetException e) {
logger.warning("Assembler.resetSlf4j: " + e.getMessage());
} catch (final IllegalAccessException e) {
logger.warning("Assembler.resetSlf4j: " + e.getMessage());
}
}
}
private void destroyLookedUpResource(final Context globalContext, final String id, final String name) throws NamingException {
// check to see if the resource is a LazyObjectReference that has not been initialized
// if it is, we'll remove the LazyObjectReference, rather than do a lookup causing it
// to be instantiated
final String ctx = name.substring(0, name.lastIndexOf("/"));
final String objName = name.substring(ctx.length() + 1);
final NamingEnumeration bindings = globalContext.listBindings(ctx);
while (bindings.hasMoreElements()) {
final Binding binding = bindings.nextElement();
if (!binding.getName().equals(objName)) {
continue;
}
if (!LazyObjectReference.class.isInstance(binding.getObject())) {
continue;
}
final LazyObjectReference> ref = LazyObjectReference.class.cast(binding.getObject());
if (!ref.isInitialized()) {
globalContext.unbind(name);
removeResourceInfo(id);
return;
}
}
// otherwise, look the object up and remove it
final Object object = globalContext.lookup(name);
final String clazz;
if (object == null) { // should it be possible?
clazz = "?";
} else {
clazz = object.getClass().getName();
}
destroyResource(id, clazz, object);
globalContext.unbind(name);
}
private void unbind(final Context context, final String name) {
try {
context.unbind(name);
} catch (final NamingException e) {
// no-op
}
}
public ClassLoader createAppClassLoader(final AppInfo appInfo) throws OpenEJBException, IOException {
final Set jars = new HashSet();
for (final EjbJarInfo info : appInfo.ejbJars) {
if (info.path != null) {
jars.add(toUrl(info.path));
}
}
for (final ClientInfo info : appInfo.clients) {
if (info.path != null) {
jars.add(toUrl(info.path));
}
}
for (final ConnectorInfo info : appInfo.connectors) {
for (final String jarPath : info.libs) {
jars.add(toUrl(jarPath));
}
}
for (final String jarPath : appInfo.libs) {
jars.add(toUrl(jarPath));
}
// add openejb-jpa-integration if the jpa provider is in lib/
if (appInfo.libs.size() > 0) { // the test could be enhanced
try {
final File jpaIntegrationFile = JarLocation.jarLocation(MakeTxLookup.class);
final URL url = jpaIntegrationFile.toURI().toURL();
if (!jars.contains(url)) { // could have been done before (webapp enrichment or manually for instance)
jars.add(url);
}
} catch (final RuntimeException re) {
logger.warning("Failed to find open-jpa-integration jar");
}
}
final ClassLoaderEnricher component = SystemInstance.get().getComponent(ClassLoaderEnricher.class);
if (component != null) {
jars.addAll(Arrays.asList(component.applicationEnrichment()));
}
// Create the class loader
final ClassLoader parent = ParentClassLoaderFinder.Helper.get();
final String prefix;
if (appInfo.webAppAlone) {
prefix = "WEB-INF/";
} else {
prefix = "META-INF/";
}
final ClassLoaderConfigurer configurer1 = QuickJarsTxtParser.parse(new File(appInfo.path, prefix + QuickJarsTxtParser.FILE_NAME));
final ClassLoaderConfigurer configurer2 = ClassLoaderUtil.configurer(appInfo.appId);
if (configurer1 != null || configurer2 != null) {
final ClassLoaderConfigurer configurer = new CompositeClassLoaderConfigurer(configurer1, configurer2);
ClassLoaderConfigurer.Helper.configure(jars, configurer);
}
final URL[] filtered = jars.toArray(new URL[jars.size()]);
// some lib (DS for instance) rely on AppClassLoader for CDI bean manager usage (common for tests cases where you
// try to get the app BM from the AppClassLoader having stored it in a map).
// since we don't really need to create a classloader here when starting from classpath just let skip this step
if (skipLoaderIfPossible) { // TODO: maybe use a boolean to know if all urls comes from the classpath to avoid this validation
if ("classpath.ear".equals(appInfo.appId)) {
return parent;
}
final Collection urls = new HashSet();
for (final URL url : ClassLoaders.findUrls(parent)) { // need to convert it to file since urls can be file:/xxx or jar:file:///xxx
try {
urls.add(URLs.toFile(url).getCanonicalFile());
} catch (final Exception error) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to determine url for: " + url.toExternalForm(), error);
}
}
}
boolean allIsIntheClasspath = true;
for (final URL url : filtered) {
try {
if (!urls.contains(URLs.toFile(url).getCanonicalFile())) {
allIsIntheClasspath = false;
if (logger.isDebugEnabled()) {
logger.debug(url.toExternalForm() + " (" + URLs.toFile(url)
+ ") is not in the classloader so we'll create a dedicated classloader for this app");
}
break;
}
} catch (final Exception ignored) {
allIsIntheClasspath = false;
if (logger.isDebugEnabled()) {
logger.debug(url.toExternalForm() + " (" + URLs.toFile(url) + ") is not in the classloader", ignored);
}
break;
}
}
if (allIsIntheClasspath) {
logger.info("Not creating another application classloader for " + appInfo.appId);
return parent;
} else if (logger.isDebugEnabled()) {
logger.debug("Logging all urls from the app since we don't skip the app classloader creation:");
for (final URL url : filtered) {
logger.debug(" -> " + url.toExternalForm());
}
logger.debug("Logging all urls from the classloader since we don't skip the app classloader creation:");
for (final File url : urls) {
logger.debug(" -> " + url.getAbsolutePath());
}
}
}
logger.info("Creating dedicated application classloader for " + appInfo.appId);
if (!appInfo.delegateFirst) {
return ClassLoaderUtil.createClassLoader(appInfo.path, filtered, parent);
}
return ClassLoaderUtil.createClassLoaderFirst(appInfo.path, filtered, parent);
}
public void createExternalContext(final JndiContextInfo contextInfo) throws OpenEJBException {
logger.getChildLogger("service").info("createService", contextInfo.service, contextInfo.id, contextInfo.className);
final InitialContext initialContext;
try {
initialContext = new InitialContext(contextInfo.properties);
} catch (final NamingException ne) {
throw new OpenEJBException(String.format("JndiProvider(id=\"%s\") could not be created. Failed to create the InitialContext using the supplied properties",
contextInfo.id), ne);
}
try {
containerSystem.getJNDIContext().bind("openejb/remote_jndi_contexts/" + contextInfo.id, initialContext);
} catch (final NamingException e) {
throw new OpenEJBException("Cannot bind " + contextInfo.service + " with id " + contextInfo.id, e);
}
// Update the config tree
config.facilities.remoteJndiContexts.add(contextInfo);
logger.getChildLogger("service").debug("createService.success", contextInfo.service, contextInfo.id, contextInfo.className);
}
public void createContainer(final ContainerInfo serviceInfo) throws OpenEJBException {
final ObjectRecipe serviceRecipe = createRecipe(serviceInfo);
serviceRecipe.setProperty("id", serviceInfo.id);
serviceRecipe.setProperty("transactionManager", props.get(TransactionManager.class.getName()));
serviceRecipe.setProperty("securityService", props.get(SecurityService.class.getName()));
serviceRecipe.setProperty("properties", new UnsetPropertiesRecipe());
// MDB container has a resource adapter string name that
// must be replaced with the real resource adapter instance
replaceResourceAdapterProperty(serviceRecipe);
final Object service = serviceRecipe.create();
logUnusedProperties(serviceRecipe, serviceInfo);
final Class interfce = serviceInterfaces.get(serviceInfo.service);
checkImplementation(interfce, service.getClass(), serviceInfo.service, serviceInfo.id);
bindService(serviceInfo, service);
setSystemInstanceComponent(interfce, service);
props.put(interfce.getName(), service);
props.put(serviceInfo.service, service);
props.put(serviceInfo.id, service);
containerSystem.addContainer(serviceInfo.id, (Container) service);
// Update the config tree
config.containerSystem.containers.add(serviceInfo);
logger.getChildLogger("service").debug("createService.success", serviceInfo.service, serviceInfo.id, serviceInfo.className);
if (Container.class.isInstance(service) && LocalMBeanServer.isJMXActive()) {
final ObjectName objectName = ObjectNameBuilder.uniqueName("containers", serviceInfo.id, service);
try {
LocalMBeanServer.get().registerMBean(new DynamicMBeanWrapper(new JMXContainer(serviceInfo, (Container) service)), objectName);
containerObjectNames.add(objectName);
} catch (final Exception e) {
// no-op
} catch (final NoClassDefFoundError ncdfe) {
// no-op
}
}
}
private void bindService(final ServiceInfo serviceInfo, final Object service) throws OpenEJBException {
try {
this.containerSystem.getJNDIContext().bind(JAVA_OPENEJB_NAMING_CONTEXT + serviceInfo.service + "/" + serviceInfo.id, service);
} catch (final NamingException e) {
throw new OpenEJBException(messages.format("assembler.cannotBindServiceWithId", serviceInfo.service, serviceInfo.id), e);
}
}
public void removeContainer(final String containerId) {
containerSystem.removeContainer(containerId);
// Update the config tree
for (final Iterator iterator = config.containerSystem.containers.iterator(); iterator.hasNext(); ) {
final ContainerInfo containerInfo = iterator.next();
if (containerInfo.id.equals(containerId)) {
iterator.remove();
try {
this.containerSystem.getJNDIContext().unbind(JAVA_OPENEJB_NAMING_CONTEXT + containerInfo.service + "/" + containerInfo.id);
} catch (final Exception e) {
logger.error("removeContainer.unbindFailed", containerId);
}
}
}
}
public void createService(final ServiceInfo serviceInfo) throws OpenEJBException {
final ObjectRecipe serviceRecipe = createRecipe(serviceInfo);
serviceRecipe.setProperty("properties", new UnsetPropertiesRecipe());
final Object service = serviceRecipe.create();
SystemInstance.get().addObserver(service);
logUnusedProperties(serviceRecipe, serviceInfo);
final Class> serviceClass = service.getClass();
getContext().put(serviceClass.getName(), service);
props.put(serviceClass.getName(), service);
props.put(serviceInfo.service, service);
props.put(serviceInfo.id, service);
config.facilities.services.add(serviceInfo);
logger.getChildLogger("service").debug("createService.success", serviceInfo.service, serviceInfo.id, serviceInfo.className);
}
public void createProxyFactory(final ProxyFactoryInfo serviceInfo) throws OpenEJBException {
final ObjectRecipe serviceRecipe = createRecipe(serviceInfo);
final Object service = serviceRecipe.create();
logUnusedProperties(serviceRecipe, serviceInfo);
final Class interfce = serviceInterfaces.get(serviceInfo.service);
checkImplementation(interfce, service.getClass(), serviceInfo.service, serviceInfo.id);
ProxyManager.registerFactory(serviceInfo.id, (ProxyFactory) service);
ProxyManager.setDefaultFactory(serviceInfo.id);
bindService(serviceInfo, service);
setSystemInstanceComponent(interfce, service);
getContext().put(interfce.getName(), service);
props.put(interfce.getName(), service);
props.put(serviceInfo.service, service);
props.put(serviceInfo.id, service);
// Update the config tree
config.facilities.intraVmServer = serviceInfo;
logger.getChildLogger("service").debug("createService.success", serviceInfo.service, serviceInfo.id, serviceInfo.className);
}
private void replaceResourceAdapterProperty(final ObjectRecipe serviceRecipe) throws OpenEJBException {
final Object resourceAdapterId = serviceRecipe.getProperty("ResourceAdapter");
if (String.class.isInstance(resourceAdapterId)) {
String id = String.class.cast(resourceAdapterId);
id = id.trim();
Object resourceAdapter = null;
try {
resourceAdapter = containerSystem.getJNDIContext().lookup("openejb/Resource/" + id);
} catch (final NamingException e) {
// handled below
}
if (resourceAdapter == null) {
throw new OpenEJBException("No existing resource adapter defined with id '" + id + "'.");
}
if (!ResourceAdapter.class.isInstance(resourceAdapter)) {
throw new OpenEJBException(messages.format("assembler.resourceAdapterNotResourceAdapter", id, resourceAdapter.getClass()));
}
serviceRecipe.setProperty("ResourceAdapter", resourceAdapter);
}
}
public void createResource(final ResourceInfo serviceInfo) throws OpenEJBException {
final Object service = "true".equalsIgnoreCase(String.valueOf(serviceInfo.properties.remove("Lazy"))) ?
newLazyResource(serviceInfo) :
doCreateResource(serviceInfo);
bindResource(serviceInfo.id, service, false);
for (final String alias : serviceInfo.aliases) {
bindResource(alias, service, false);
}
if (serviceInfo.originAppName != null && !serviceInfo.originAppName.isEmpty() && !"/".equals(serviceInfo.originAppName)
&& !serviceInfo.id.startsWith("global")) {
final String baseJndiName = serviceInfo.id.substring(serviceInfo.originAppName.length() + 1);
serviceInfo.aliases.add(baseJndiName);
final ContextualJndiReference ref = new ContextualJndiReference(baseJndiName);
ref.addPrefix(serviceInfo.originAppName);
bindResource(baseJndiName, ref, false);
}
// Update the config tree
config.facilities.resources.add(serviceInfo);
if (logger.isDebugEnabled()) { // weird to check parent logger but save time and it is almost never activated
logger.getChildLogger("service").debug("createService.success", serviceInfo.service, serviceInfo.id, serviceInfo.className);
}
}
private LazyResource newLazyResource(final ResourceInfo serviceInfo) {
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
return new LazyResource(new Callable() {
@Override
public Object call() throws Exception {
final boolean appClassLoader = "true".equals(serviceInfo.properties.remove("UseAppClassLoader"));
ClassLoader old = null;
if (!appClassLoader) {
old = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(loader);
}
try {
return doCreateResource(serviceInfo);
} finally {
if (old != null) {
Thread.currentThread().setContextClassLoader(old);
}
}
}
});
}
private Object doCreateResource(final ResourceInfo serviceInfo) throws OpenEJBException {
final ObjectRecipe serviceRecipe = createRecipe(serviceInfo);
final boolean properties = PropertiesFactory.class.getName().equals(serviceInfo.className);
if ("false".equalsIgnoreCase(serviceInfo.properties.getProperty("SkipImplicitAttributes", "false")) && !properties) {
serviceRecipe.setProperty("transactionManager", transactionManager);
serviceRecipe.setProperty("ServiceId", serviceInfo.id);
}
serviceInfo.properties.remove("SkipImplicitAttributes");
final AtomicReference injectedProperties = new AtomicReference();
serviceRecipe.setProperty("properties", new UnsetPropertiesRecipe() {
@Override
protected Object internalCreate(final Type expectedType, final boolean lazyRefAllowed) throws ConstructionException {
final Map original = serviceRecipe.getUnsetProperties();
final Properties properties = new SuperProperties() {
@Override
public Object remove(final Object key) { // avoid to log them then
original.remove(key);
return super.remove(key);
}
}.caseInsensitive(true); // keep our nice case insensitive feature
for (final Map.Entry entry : original.entrySet()) {
properties.put(entry.getKey(), entry.getValue());
}
injectedProperties.set(properties);
return properties;
}
});
final Properties props = PropertyPlaceHolderHelper.simpleHolds(serviceInfo.properties);
if (serviceInfo.properties.containsKey("Definition")) {
try { // we catch classcast etc..., if it fails it is not important
final InputStream is = new ByteArrayInputStream(serviceInfo.properties.getProperty("Definition").getBytes());
final Properties p = new SuperProperties();
IO.readProperties(is, p);
for (final Entry entry : p.entrySet()) {
final String key = entry.getKey().toString();
if (!props.containsKey(key)
// never override from Definition, just use it to complete the properties set
&&
!(key.equalsIgnoreCase("url") &&
props.containsKey("JdbcUrl"))) { // with @DataSource we can get both, see org.apache.openejb.config.ConvertDataSourceDefinitions.rawDefinition()
props.put(key, entry.getValue());
}
}
} catch (final Exception e) {
// ignored
}
}
serviceRecipe.setProperty("Definition", PropertiesHelper.propertiesToString(props));
replaceResourceAdapterProperty(serviceRecipe);
ClassLoader loader = Thread.currentThread().getContextClassLoader();
boolean customLoader = false;
try {
if (serviceInfo.classpath != null && serviceInfo.classpath.length > 0) {
final URL[] urls = new URL[serviceInfo.classpath.length];
for (int i = 0; i < serviceInfo.classpath.length; i++) {
urls[i] = serviceInfo.classpath[i].toURL();
}
loader = new URLClassLoaderFirst(urls, loader);
customLoader = true;
serviceRecipe.setProperty("OpenEJBResourceClasspath", "true");
}
} catch (final MalformedURLException e) {
throw new OpenEJBException("Unable to create a classloader for " + serviceInfo.id, e);
}
Object service = serviceRecipe.create(loader);
if (customLoader) {
final Collection> apis = new ArrayList>(Arrays.asList(service.getClass().getInterfaces()));
if (apis.size() - (apis.contains(Serializable.class) ? 1 : 0) - (apis.contains(Externalizable.class) ? 1 : 0) > 0) {
service = Proxy.newProxyInstance(loader, apis.toArray(new Class>[apis.size()]), new ClassLoaderAwareHandler(null, service, loader));
} // else proxy would be useless
}
serviceInfo.unsetProperties = injectedProperties.get();
// Java Connector spec ResourceAdapters and ManagedConnectionFactories need special activation
if (ResourceAdapter.class.isInstance(service)) {
final ResourceAdapter resourceAdapter = ResourceAdapter.class.cast(service);
// Create a thead pool for work manager
final int threadPoolSize = getIntProperty(serviceInfo.properties, "threadPoolSize", 30);
final Executor threadPool;
if (threadPoolSize <= 0) {
logger.warning("Thread pool for '" + serviceInfo.id + "' is (unbounded), consider setting a size using: " + serviceInfo.id + ".QueueSize=[size]");
threadPool = Executors.newCachedThreadPool(new DaemonThreadFactory(serviceInfo.id + "-worker-"));
} else {
threadPool = new ExecutorBuilder()
.size(threadPoolSize)
.prefix(serviceInfo.id)
.threadFactory(new DaemonThreadFactory(serviceInfo.id + "-worker-"))
.build(new Options(serviceInfo.properties, SystemInstance.get().getOptions()));
logger.info("Thread pool size for '" + serviceInfo.id + "' is (" + threadPoolSize + ")");
}
// WorkManager: the resource adapter can use this to dispatch messages or perform tasks
final WorkManager workManager;
if (GeronimoTransactionManager.class.isInstance(transactionManager)) {
final GeronimoTransactionManager geronimoTransactionManager = (GeronimoTransactionManager) transactionManager;
final TransactionContextHandler txWorkContextHandler = new TransactionContextHandler(geronimoTransactionManager);
// use id as default realm name if realm is not specified in service properties
final String securityRealmName = getStringProperty(serviceInfo.properties, "realm", serviceInfo.id);
final SecurityContextHandler securityContextHandler = new SecurityContextHandler(securityRealmName);
final HintsContextHandler hintsContextHandler = new HintsContextHandler();
final Collection workContextHandlers = new ArrayList();
workContextHandlers.add(txWorkContextHandler);
workContextHandlers.add(securityContextHandler);
workContextHandlers.add(hintsContextHandler);
workManager = new GeronimoWorkManager(threadPool, threadPool, threadPool, workContextHandlers);
} else {
workManager = new SimpleWorkManager(threadPool);
}
// BootstrapContext: wraps the WorkMananger and XATerminator
final BootstrapContext bootstrapContext;
if (GeronimoTransactionManager.class.isInstance(transactionManager)) {
bootstrapContext = new GeronimoBootstrapContext(GeronimoWorkManager.class.cast(workManager),
(GeronimoTransactionManager) transactionManager,
(GeronimoTransactionManager) transactionManager);
} else if (XATerminator.class.isInstance(transactionManager)) {
bootstrapContext = new SimpleBootstrapContext(workManager, XATerminator.class.cast(transactionManager));
} else {
bootstrapContext = new SimpleBootstrapContext(workManager);
}
// start the resource adapter
try {
logger.debug("createResource.startingResourceAdapter", serviceInfo.id, service.getClass().getName());
resourceAdapter.start(bootstrapContext);
} catch (final ResourceAdapterInternalException e) {
throw new OpenEJBException(e);
}
final Map unset = serviceRecipe.getUnsetProperties();
unset.remove("threadPoolSize");
logUnusedProperties(unset, serviceInfo);
service = new ResourceAdapterReference(resourceAdapter, threadPool, OPENEJB_RESOURCE_JNDI_PREFIX + serviceInfo.id);
} else if (ManagedConnectionFactory.class.isInstance(service)) {
final ManagedConnectionFactory managedConnectionFactory = ManagedConnectionFactory.class.cast(service);
// connection manager is constructed via a recipe so we automatically expose all cmf properties
final ObjectRecipe connectionManagerRecipe = new ObjectRecipe(GeronimoConnectionManagerFactory.class, "create");
connectionManagerRecipe.allow(Option.CASE_INSENSITIVE_PROPERTIES);
connectionManagerRecipe.allow(Option.IGNORE_MISSING_PROPERTIES);
connectionManagerRecipe.setAllProperties(serviceInfo.properties);
connectionManagerRecipe.setProperty("name", serviceInfo.id);
connectionManagerRecipe.setProperty("mcf", managedConnectionFactory);
// standard properties
connectionManagerRecipe.setProperty("transactionManager", transactionManager);
ClassLoader classLoader = loader;
if (classLoader == null) {
classLoader = getClass().getClassLoader();
}
if (classLoader == null) {
classLoader = ClassLoader.getSystemClassLoader();
}
connectionManagerRecipe.setProperty("classLoader", classLoader);
logger.getChildLogger("service").info("createResource.createConnectionManager", serviceInfo.id, service.getClass().getName());
// create the connection manager
final ConnectionManager connectionManager = (ConnectionManager) connectionManagerRecipe.create();
if (connectionManager == null) {
throw new OpenEJBRuntimeException(messages.format("assembler.invalidConnectionManager", serviceInfo.id));
}
final Map unsetA = serviceRecipe.getUnsetProperties();
final Map unsetB = connectionManagerRecipe.getUnsetProperties();
final Map unset = new HashMap();
for (final Entry entry : unsetA.entrySet()) {
if (unsetB.containsKey(entry.getKey())) {
unset.put(entry.getKey(), entry.getValue());
}
}
// service becomes a ConnectorReference which merges connection manager and mcf
service = new ConnectorReference(connectionManager, managedConnectionFactory);
// init cm if needed
final Object eagerInit = unset.remove("eagerInit");
if (eagerInit != null && String.class.isInstance(eagerInit) && "true".equalsIgnoreCase(String.class.cast(eagerInit))
&& AbstractConnectionManager.class.isInstance(connectionManager)) {
try {
AbstractConnectionManager.class.cast(connectionManager).doStart();
try {
final Object cf = managedConnectionFactory.createConnectionFactory(connectionManager);
if (ConnectionFactory.class.isInstance(cf)) {
final Connection connection = ConnectionFactory.class.cast(cf).getConnection();
connection.getMetaData();
connection.close();
}
} catch (final Exception e) {
// no-op: just to force eager init of pool
}
} catch (final Exception e) {
logger.warning("Failed to start connection manager", e);
}
}
logUnusedProperties(unset, serviceInfo);
} else if (DataSource.class.isInstance(service)) {
ClassLoader classLoader = loader;
if (classLoader == null) {
classLoader = getClass().getClassLoader();
}
final ImportSql importer = new ImportSql(classLoader, serviceInfo.id, DataSource.class.cast(service));
if (importer.hasSomethingToImport()) {
importer.doImport();
}
final ObjectRecipe recipe = DataSourceFactory.forgetRecipe(service, serviceRecipe);
if (recipe != serviceRecipe || !serviceInfo.properties.containsKey("XaDataSource")) {
logUnusedProperties(recipe, serviceInfo);
} // else logged on xadatasource itself
final Properties prop = serviceInfo.properties;
String url = prop.getProperty("JdbcUrl", prop.getProperty("url"));
if (url == null) {
url = prop.getProperty("jdbcUrl");
}
if (url == null) {
logger.debug("Failed to find url for " + serviceInfo.id + " will not monitor it");
} else {
final String host = extractHost(url);
if (host != null) {
remoteResourceMonitor.addHost(host);
remoteResourceMonitor.registerIfNot();
}
}
} else if (!Properties.class.isInstance(service)) {
if (serviceInfo.unsetProperties == null || isTemplatizedResource(serviceInfo)) {
logUnusedProperties(serviceRecipe, serviceInfo);
} // else wait post construct
}
return service;
}
private void bindResource(final String id, final Object service, final boolean canReplace) throws OpenEJBException {
final String name = OPENEJB_RESOURCE_JNDI_PREFIX + id;
final Context jndiContext = containerSystem.getJNDIContext();
Object existing = null;
try {
ContextualJndiReference.followReference.set(false);
existing = jndiContext.lookup(name);
} catch (final Exception ignored) {
// no-op
} finally {
ContextualJndiReference.followReference.remove(); // if the lookup fails the remove is not done
}
boolean rebind = false;
if (existing != null) {
final boolean existingIsContextual = ContextualJndiReference.class.isInstance(existing);
final boolean serviceIsExisting = ContextualJndiReference.class.isInstance(service);
if (!existingIsContextual && serviceIsExisting) {
ContextualJndiReference.class.cast(service).setDefaultValue(existing);
rebind = true;
} else if (existingIsContextual && !serviceIsExisting) {
ContextualJndiReference.class.cast(existing).setDefaultValue(service);
} else if (existingIsContextual) { // && serviceIsExisting is always true here
final ContextualJndiReference contextual = ContextualJndiReference.class.cast(existing);
if (canReplace && contextual.prefixesSize() == 1) { // replace!
contextual.removePrefix(contextual.lastPrefix());
contextual.setDefaultValue(service);
} else {
contextual.addPrefix(ContextualJndiReference.class.cast(service).lastPrefix());
}
return;
}
}
try {
if (canReplace && existing != null) {
jndiContext.unbind(name);
}
if (rebind) {
jndiContext.rebind(name, service);
} else {
jndiContext.bind(name, service);
}
} catch (final NameAlreadyBoundException nabe) {
logger.warning("unbounding resource " + name + " can happen because of a redeployment or because of a duplicated id");
try {
jndiContext.unbind(name);
jndiContext.bind(name, service);
} catch (final NamingException e) {
throw new OpenEJBException("Cannot bind resource adapter with id " + id, e);
}
} catch (final NamingException e) {
throw new OpenEJBException("Cannot bind resource adapter with id " + id, e);
}
}
private static String extractHost(final String url) { // can be enhanced
if (url == null || !url.contains("://")) {
return null;
}
final int idx = url.indexOf("://");
final String subUrl = url.substring(idx + 3);
final int port = subUrl.indexOf(':');
final int slash = subUrl.indexOf('/');
int end = port;
if (end < 0 || slash > 0 && slash < end) {
end = slash;
}
if (end > 0) {
return subUrl.substring(0, end);
}
return subUrl;
}
private int getIntProperty(final Properties properties, final String propertyName, final int defaultValue) {
final String propertyValue = getStringProperty(properties, propertyName, Integer.toString(defaultValue));
if (propertyValue == null) {
return defaultValue;
}
try {
return Integer.parseInt(propertyValue);
} catch (final NumberFormatException e) {
throw new IllegalArgumentException(propertyName + " is not an integer " + propertyValue, e);
}
}
private String getStringProperty(final Properties properties, final String propertyName, final String defaultValue) {
final String propertyValue = properties.getProperty(propertyName);
if (propertyValue == null) {
return defaultValue;
}
return propertyValue;
}
public void createConnectionManager(final ConnectionManagerInfo serviceInfo) throws OpenEJBException {
final ObjectRecipe serviceRecipe = createRecipe(serviceInfo);
final Object object = props.get("TransactionManager");
serviceRecipe.setProperty("transactionManager", object);
final Object service = serviceRecipe.create();
logUnusedProperties(serviceRecipe, serviceInfo);
final Class interfce = serviceInterfaces.get(serviceInfo.service);
checkImplementation(interfce, service.getClass(), serviceInfo.service, serviceInfo.id);
bindService(serviceInfo, service);
setSystemInstanceComponent(interfce, service);
getContext().put(interfce.getName(), service);
props.put(interfce.getName(), service);
props.put(serviceInfo.service, service);
props.put(serviceInfo.id, service);
// Update the config tree
config.facilities.connectionManagers.add(serviceInfo);
logger.getChildLogger("service").debug("createService.success", serviceInfo.service, serviceInfo.id, serviceInfo.className);
}
public void createSecurityService(final SecurityServiceInfo serviceInfo) throws OpenEJBException {
Object service = SystemInstance.get().getComponent(SecurityService.class);
if (service == null) {
final ObjectRecipe serviceRecipe = createRecipe(serviceInfo);
service = serviceRecipe.create();
logUnusedProperties(serviceRecipe, serviceInfo);
}
final Class interfce = serviceInterfaces.get(serviceInfo.service);
checkImplementation(interfce, service.getClass(), serviceInfo.service, serviceInfo.id);
try {
this.containerSystem.getJNDIContext().bind(JAVA_OPENEJB_NAMING_CONTEXT + serviceInfo.service, service);
} catch (final NamingException e) {
throw new OpenEJBException("Cannot bind " + serviceInfo.service + " with id " + serviceInfo.id, e);
}
setSystemInstanceComponent(interfce, service);
getContext().put(interfce.getName(), service);
props.put(interfce.getName(), service);
props.put(serviceInfo.service, service);
props.put(serviceInfo.id, service);
this.securityService = (SecurityService) service;
// Update the config tree
config.facilities.securityService = serviceInfo;
logger.getChildLogger("service").debug("createService.success", serviceInfo.service, serviceInfo.id, serviceInfo.className);
}
public void createTransactionManager(final TransactionServiceInfo serviceInfo) throws OpenEJBException {
Object service = SystemInstance.get().getComponent(TransactionManager.class);
if (service == null) {
final ObjectRecipe serviceRecipe = createRecipe(serviceInfo);
service = serviceRecipe.create();
logUnusedProperties(serviceRecipe, serviceInfo);
} else {
logger.info("Reusing provided TransactionManager " + service);
}
final Class interfce = serviceInterfaces.get(serviceInfo.service);
checkImplementation(interfce, service.getClass(), serviceInfo.service, serviceInfo.id);
try {
this.containerSystem.getJNDIContext().bind(JAVA_OPENEJB_NAMING_CONTEXT + serviceInfo.service, service);
this.containerSystem.getJNDIContext().bind("comp/UserTransaction", new CoreUserTransaction((TransactionManager) service));
this.containerSystem.getJNDIContext().bind("comp/TransactionManager", service);
} catch (final NamingException e) {
throw new OpenEJBException("Cannot bind " + serviceInfo.service + " with id " + serviceInfo.id, e);
}
setSystemInstanceComponent(interfce, service);
getContext().put(interfce.getName(), service);
props.put(interfce.getName(), service);
props.put(serviceInfo.service, service);
props.put(serviceInfo.id, service);
this.transactionManager = (TransactionManager) service;
// Update the config tree
config.facilities.transactionService = serviceInfo;
// todo find a better place for this
// TransactionSynchronizationRegistry
final TransactionSynchronizationRegistry synchronizationRegistry;
if (TransactionSynchronizationRegistry.class.isInstance(transactionManager)) {
synchronizationRegistry = TransactionSynchronizationRegistry.class.cast(transactionManager);
} else {
// todo this should be built
synchronizationRegistry = new SimpleTransactionSynchronizationRegistry(transactionManager);
}
Assembler.getContext().put(TransactionSynchronizationRegistry.class.getName(), synchronizationRegistry);
SystemInstance.get().setComponent(TransactionSynchronizationRegistry.class, synchronizationRegistry);
try {
this.containerSystem.getJNDIContext().bind("comp/TransactionSynchronizationRegistry", new TransactionSynchronizationRegistryWrapper());
} catch (final NamingException e) {
throw new OpenEJBException("Cannot bind java:comp/TransactionSynchronizationRegistry", e);
}
// JtaEntityManagerRegistry
// todo this should be built
final JtaEntityManagerRegistry jtaEntityManagerRegistry = new JtaEntityManagerRegistry(synchronizationRegistry);
Assembler.getContext().put(JtaEntityManagerRegistry.class.getName(), jtaEntityManagerRegistry);
SystemInstance.get().setComponent(JtaEntityManagerRegistry.class, jtaEntityManagerRegistry);
logger.getChildLogger("service").debug("createService.success", serviceInfo.service, serviceInfo.id, serviceInfo.className);
}
public static void logUnusedProperties(final ObjectRecipe serviceRecipe, final ServiceInfo info) {
final Map unsetProperties = serviceRecipe.getUnsetProperties();
logUnusedProperties(unsetProperties, info);
}
private static void logUnusedProperties(final Map unsetProperties, final ServiceInfo info) {
Logger logger = null;
for (final String property : unsetProperties.keySet()) {
//TODO: DMB: Make more robust later
if (property.equalsIgnoreCase("Definition")) {
return;
}
if (property.equalsIgnoreCase("SkipImplicitAttributes")) {
return;
}
if (property.equalsIgnoreCase("JndiName")) {
return;
}
if (property.equalsIgnoreCase("Origin")) {
return;
}
if (property.equalsIgnoreCase("DatabaseName")) {
return;
}
if (property.equalsIgnoreCase("connectionAttributes")) {
return;
}
if (property.equalsIgnoreCase("properties")) {
return;
}
if (property.equalsIgnoreCase("ApplicationWide")) {
return;
}
if (property.equalsIgnoreCase("OpenEJBResourceClasspath")) {
continue;
}
if (property.equalsIgnoreCase("transactionManager")) {
return;
}
if (info.types.contains("javax.mail.Session")) {
return;
}
//---
if (info.types.isEmpty() && "class".equalsIgnoreCase(property)) {
continue; // inline service (no sp)
}
if (logger == null) {
final Assembler a = SystemInstance.get().getComponent(Assembler.class);
if (a != null) {
logger = a.logger;
}
}
unusedProperty(info.id, logger, property);
}
}
private static void unusedProperty(final String id, final Logger parentLogger, final String property) {
parentLogger.getChildLogger("service").warning("unusedProperty", property, id);
}
public static ObjectRecipe prepareRecipe(final ServiceInfo info) {
final String[] constructorArgs = info.constructorArgs.toArray(new String[info.constructorArgs.size()]);
final ObjectRecipe serviceRecipe = new ObjectRecipe(info.className, info.factoryMethod, constructorArgs, null);
serviceRecipe.allow(Option.CASE_INSENSITIVE_PROPERTIES);
serviceRecipe.allow(Option.IGNORE_MISSING_PROPERTIES);
serviceRecipe.allow(Option.PRIVATE_PROPERTIES);
return serviceRecipe;
}
private ObjectRecipe createRecipe(final ServiceInfo info) {
final Logger serviceLogger = logger.getChildLogger("service");
if (ResourceInfo.class.isInstance(info)) {
final List aliasesList = ResourceInfo.class.cast(info).aliases;
if (!aliasesList.isEmpty()) {
final String aliases = Join.join(", ", aliasesList);
serviceLogger.info("createServiceWithAliases", info.service, info.id, aliases);
} else {
serviceLogger.info("createService", info.service, info.id);
}
} else {
serviceLogger.info("createService", info.service, info.id);
}
final ObjectRecipe serviceRecipe = prepareRecipe(info);
final Object value = info.properties.remove("SkipImplicitAttributes"); // we don't want this one to go in recipe
serviceRecipe.setAllProperties(info.properties);
if (value != null) {
info.properties.put("SkipImplicitAttributes", value);
}
if (serviceLogger.isDebugEnabled()) {
for (final Map.Entry entry : serviceRecipe.getProperties().entrySet()) {
serviceLogger.debug("createService.props", entry.getKey(), entry.getValue());
}
}
return serviceRecipe;
}
@SuppressWarnings({"unchecked"})
private void setSystemInstanceComponent(final Class interfce, final Object service) {
SystemInstance.get().setComponent(interfce, service);
}
private URL toUrl(final String jarPath) throws OpenEJBException {
try {
return new File(jarPath).toURI().toURL();
} catch (final MalformedURLException e) {
throw new OpenEJBException(messages.format("cl0001", jarPath, e.getMessage()), e);
}
}
public Logger getLogger() {
return logger;
}
private static class PersistenceClassLoaderHandlerImpl implements PersistenceClassLoaderHandler {
private static final AtomicBoolean logged = new AtomicBoolean(false);
private final Map> transformers = new TreeMap>();
@Override
public void addTransformer(final String unitId, final ClassLoader classLoader, final ClassFileTransformer classFileTransformer) {
final Instrumentation instrumentation = Agent.getInstrumentation();
if (instrumentation != null) {
instrumentation.addTransformer(classFileTransformer);
if (unitId != null) {
List transformers = this.transformers.get(unitId);
if (transformers == null) {
transformers = new ArrayList(1);
this.transformers.put(unitId, transformers);
}
transformers.add(classFileTransformer);
}
} else if (!logged.getAndSet(true)) {
final Assembler a = SystemInstance.get().getComponent(Assembler.class);
if (a != null) {
a.getLogger().warning("assembler.noAgent");
}
}
}
@Override
public void destroy(final String unitId) {
final List transformers = this.transformers.remove(unitId);
if (transformers != null) {
final Instrumentation instrumentation = Agent.getInstrumentation();
if (instrumentation != null) {
for (final ClassFileTransformer transformer : transformers) {
instrumentation.removeTransformer(transformer);
}
} else {
final Assembler a = SystemInstance.get().getComponent(Assembler.class);
if (a != null) {
a.getLogger().error("assembler.noAgent");
}
}
}
}
@Override
public ClassLoader getNewTempClassLoader(final ClassLoader classLoader) {
return ClassLoaderUtil.createTempClassLoader(classLoader);
}
}
public static class DeploymentListenerObserver {
private final DeploymentListener delegate;
public DeploymentListenerObserver(final DeploymentListener deploymentListener) {
delegate = deploymentListener;
}
public void afterApplicationCreated(@Observes final AssemblerAfterApplicationCreated event) {
delegate.afterApplicationCreated(event.getApp());
}
public void beforeApplicationDestroyed(@Observes final AssemblerBeforeApplicationDestroyed event) {
delegate.beforeApplicationDestroyed(event.getApp());
}
@Override
public boolean equals(final Object o) {
if (this == o) {
return true;
}
if (!DeploymentListenerObserver.class.isInstance(o)) {
return false;
}
final DeploymentListenerObserver that = DeploymentListenerObserver.class.cast(o);
return !(delegate != null ? !delegate.equals(that.delegate) : that.delegate != null);
}
@Override
public int hashCode() {
return delegate != null ? delegate.hashCode() : 0;
}
}
private static final class DestroyingResource {
private final String name;
private final String clazz;
private final Object instance;
private DestroyingResource(final String name, final String clazz, final Object instance) {
this.name = name;
this.clazz = clazz;
this.instance = instance;
}
}
public static final class ResourceAdapterReference extends Reference {
private final transient ResourceAdapter ra;
private final transient Executor pool;
private final String jndi;
public ResourceAdapterReference(final ResourceAdapter ra, final Executor pool, final String jndi) {
this.ra = ra;
this.pool = pool;
this.jndi = jndi;
}
public Executor getPool() {
return pool;
}
public ResourceAdapter getRa() {
return ra;
}
public String getJndi() {
return jndi;
}
@Override
public Object getObject() throws NamingException {
return ra;
}
protected Object readResolve() throws ObjectStreamException {
try {
final ContainerSystem containerSystem = SystemInstance.get().getComponent(ContainerSystem.class);
if (containerSystem != null) {
return containerSystem.getJNDIContext().lookup(jndi);
}
} catch (final Exception e) {
throw new InvalidObjectException("name not found: " + jndi);
}
return null;
}
}
public static class LazyResource extends LazyObjectReference {
public LazyResource(final Callable creator) {
super(creator);
}
Object writeReplace() throws ObjectStreamException {
try {
return getObject();
} catch (final NamingException e) {
return null;
}
}
}
public static class ResourceInstance extends Reference implements Serializable, DestroyableResource {
private final String name;
private final Object delegate;
private final transient Collection preDestroys;
private final transient CreationalContext> context;
public ResourceInstance(final String name, final Object delegate, final Collection preDestroys, final CreationalContext> context) {
this.name = name;
this.delegate = delegate;
this.preDestroys = preDestroys;
this.context = context;
}
@Override
public Object getObject() throws NamingException {
return delegate;
}
@Override
public void destroyResource() {
final Object o = unwrapReference(delegate);
for (final Method m : preDestroys) {
try {
if (!m.isAccessible()) {
SetAccessible.on(m);
}
m.invoke(o);
} catch (final Exception e) {
final Assembler assembler = SystemInstance.get().getComponent(Assembler.class);
if (assembler != null) {
assembler.getLogger().error(e.getMessage(), e);
}
}
}
try {
if (context != null) {
context.release();
}
} catch (final Exception e) {
// no-op
}
}
// we don't care unwrapping the resource here since we want to keep ResourceInstance data for destruction
// which is never serialized (IvmContext)
Object readResolve() throws ObjectStreamException {
try {
final ContainerSystem containerSystem = SystemInstance.get().getComponent(ContainerSystem.class);
if (containerSystem != null) {
return containerSystem.getJNDIContext().lookup(name);
}
} catch (final NamingException e) {
throw new IllegalStateException(e);
}
return null;
}
}
}