Factor out appInfo.containerIds as we now have appInfo.containers
[tomee.git] / container / openejb-core / src / main / java / org / apache / openejb / assembler / classic / Assembler.java
1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.openejb.assembler.classic;
19
20 import org.apache.geronimo.connector.GeronimoBootstrapContext;
21 import org.apache.geronimo.connector.outbound.AbstractConnectionManager;
22 import org.apache.geronimo.connector.work.GeronimoWorkManager;
23 import org.apache.geronimo.connector.work.HintsContextHandler;
24 import org.apache.geronimo.connector.work.TransactionContextHandler;
25 import org.apache.geronimo.connector.work.WorkContextHandler;
26 import org.apache.geronimo.transaction.manager.GeronimoTransactionManager;
27 import org.apache.openejb.AppContext;
28 import org.apache.openejb.BeanContext;
29 import org.apache.openejb.BeanType;
30 import org.apache.openejb.ClassLoaderUtil;
31 import org.apache.openejb.Container;
32 import org.apache.openejb.DeploymentContext;
33 import org.apache.openejb.DuplicateDeploymentIdException;
34 import org.apache.openejb.Extensions;
35 import org.apache.openejb.Injection;
36 import org.apache.openejb.JndiConstants;
37 import org.apache.openejb.MethodContext;
38 import org.apache.openejb.NoSuchApplicationException;
39 import org.apache.openejb.OpenEJBException;
40 import org.apache.openejb.OpenEJBRuntimeException;
41 import org.apache.openejb.UndeployException;
42 import org.apache.openejb.api.jmx.MBean;
43 import org.apache.openejb.api.resource.DestroyableResource;
44 import org.apache.openejb.assembler.classic.event.AssemblerAfterApplicationCreated;
45 import org.apache.openejb.assembler.classic.event.AssemblerBeforeApplicationDestroyed;
46 import org.apache.openejb.assembler.classic.event.AssemblerCreated;
47 import org.apache.openejb.assembler.classic.event.AssemblerDestroyed;
48 import org.apache.openejb.assembler.classic.event.BeforeStartEjbs;
49 import org.apache.openejb.assembler.classic.event.ContainerSystemPostCreate;
50 import org.apache.openejb.assembler.classic.event.ContainerSystemPreDestroy;
51 import org.apache.openejb.assembler.classic.event.ResourceBeforeDestroyed;
52 import org.apache.openejb.assembler.classic.event.ResourceCreated;
53 import org.apache.openejb.assembler.classic.util.ServiceInfos;
54 import org.apache.openejb.assembler.monitoring.JMXContainer;
55 import org.apache.openejb.async.AsynchronousPool;
56 import org.apache.openejb.batchee.BatchEEServiceManager;
57 import org.apache.openejb.cdi.CdiAppContextsService;
58 import org.apache.openejb.cdi.CdiBuilder;
59 import org.apache.openejb.cdi.CdiPlugin;
60 import org.apache.openejb.cdi.CdiResourceInjectionService;
61 import org.apache.openejb.cdi.CdiScanner;
62 import org.apache.openejb.cdi.CustomELAdapter;
63 import org.apache.openejb.cdi.ManagedSecurityService;
64 import org.apache.openejb.cdi.OpenEJBBeanInfoService;
65 import org.apache.openejb.cdi.OpenEJBJndiService;
66 import org.apache.openejb.cdi.OpenEJBTransactionService;
67 import org.apache.openejb.cdi.OptimizedLoaderService;
68 import org.apache.openejb.classloader.ClassLoaderConfigurer;
69 import org.apache.openejb.classloader.CompositeClassLoaderConfigurer;
70 import org.apache.openejb.component.ClassLoaderEnricher;
71 import org.apache.openejb.config.ConfigurationFactory;
72 import org.apache.openejb.config.NewLoaderLogic;
73 import org.apache.openejb.config.QuickJarsTxtParser;
74 import org.apache.openejb.config.TldScanner;
75 import org.apache.openejb.core.ConnectorReference;
76 import org.apache.openejb.core.CoreContainerSystem;
77 import org.apache.openejb.core.CoreUserTransaction;
78 import org.apache.openejb.core.JndiFactory;
79 import org.apache.openejb.core.ParentClassLoaderFinder;
80 import org.apache.openejb.core.ServerFederation;
81 import org.apache.openejb.core.SimpleTransactionSynchronizationRegistry;
82 import org.apache.openejb.core.TransactionSynchronizationRegistryWrapper;
83 import org.apache.openejb.core.WebContext;
84 import org.apache.openejb.core.ivm.ContextHandler;
85 import org.apache.openejb.core.ivm.IntraVmProxy;
86 import org.apache.openejb.core.ivm.naming.ContextualJndiReference;
87 import org.apache.openejb.core.ivm.naming.IvmContext;
88 import org.apache.openejb.core.ivm.naming.IvmJndiFactory;
89 import org.apache.openejb.core.ivm.naming.JndiUrlReference;
90 import org.apache.openejb.core.ivm.naming.LazyObjectReference;
91 import org.apache.openejb.core.ivm.naming.Reference;
92 import org.apache.openejb.core.security.SecurityContextHandler;
93 import org.apache.openejb.core.timer.EjbTimerServiceImpl;
94 import org.apache.openejb.core.timer.MemoryTimerStore;
95 import org.apache.openejb.core.timer.NullEjbTimerServiceImpl;
96 import org.apache.openejb.core.timer.ScheduleData;
97 import org.apache.openejb.core.timer.TimerStore;
98 import org.apache.openejb.core.transaction.JtaTransactionPolicyFactory;
99 import org.apache.openejb.core.transaction.SimpleBootstrapContext;
100 import org.apache.openejb.core.transaction.SimpleWorkManager;
101 import org.apache.openejb.core.transaction.TransactionPolicyFactory;
102 import org.apache.openejb.core.transaction.TransactionType;
103 import org.apache.openejb.javaagent.Agent;
104 import org.apache.openejb.jpa.integration.MakeTxLookup;
105 import org.apache.openejb.loader.IO;
106 import org.apache.openejb.loader.JarLocation;
107 import org.apache.openejb.loader.Options;
108 import org.apache.openejb.loader.ProvisioningUtil;
109 import org.apache.openejb.loader.SystemInstance;
110 import org.apache.openejb.monitoring.DynamicMBeanWrapper;
111 import org.apache.openejb.monitoring.LocalMBeanServer;
112 import org.apache.openejb.monitoring.ObjectNameBuilder;
113 import org.apache.openejb.monitoring.remote.RemoteResourceMonitor;
114 import org.apache.openejb.observer.Observes;
115 import org.apache.openejb.persistence.JtaEntityManagerRegistry;
116 import org.apache.openejb.persistence.PersistenceClassLoaderHandler;
117 import org.apache.openejb.quartz.Scheduler;
118 import org.apache.openejb.resource.GeronimoConnectionManagerFactory;
119 import org.apache.openejb.resource.PropertiesFactory;
120 import org.apache.openejb.resource.jdbc.DataSourceFactory;
121 import org.apache.openejb.spi.ApplicationServer;
122 import org.apache.openejb.spi.ContainerSystem;
123 import org.apache.openejb.spi.SecurityService;
124 import org.apache.openejb.util.Contexts;
125 import org.apache.openejb.util.DaemonThreadFactory;
126 import org.apache.openejb.util.Duration;
127 import org.apache.openejb.util.ExecutorBuilder;
128 import org.apache.openejb.util.JavaSecurityManagers;
129 import org.apache.openejb.util.Join;
130 import org.apache.openejb.util.LogCategory;
131 import org.apache.openejb.util.Logger;
132 import org.apache.openejb.util.Messages;
133 import org.apache.openejb.util.OpenEJBErrorHandler;
134 import org.apache.openejb.util.PropertiesHelper;
135 import org.apache.openejb.util.PropertyPlaceHolderHelper;
136 import org.apache.openejb.util.References;
137 import org.apache.openejb.util.SafeToolkit;
138 import org.apache.openejb.util.SetAccessible;
139 import org.apache.openejb.util.SuperProperties;
140 import org.apache.openejb.util.URISupport;
141 import org.apache.openejb.util.URLs;
142 import org.apache.openejb.util.classloader.ClassLoaderAwareHandler;
143 import org.apache.openejb.util.classloader.URLClassLoaderFirst;
144 import org.apache.openejb.util.proxy.ProxyFactory;
145 import org.apache.openejb.util.proxy.ProxyManager;
146 import org.apache.webbeans.component.ResourceBean;
147 import org.apache.webbeans.config.WebBeansContext;
148 import org.apache.webbeans.container.BeanManagerImpl;
149 import org.apache.webbeans.inject.OWBInjector;
150 import org.apache.webbeans.logger.JULLoggerFactory;
151 import org.apache.webbeans.spi.BeanArchiveService;
152 import org.apache.webbeans.spi.ContainerLifecycle;
153 import org.apache.webbeans.spi.ContextsService;
154 import org.apache.webbeans.spi.JNDIService;
155 import org.apache.webbeans.spi.LoaderService;
156 import org.apache.webbeans.spi.ResourceInjectionService;
157 import org.apache.webbeans.spi.ScannerService;
158 import org.apache.webbeans.spi.TransactionService;
159 import org.apache.webbeans.spi.adaptor.ELAdaptor;
160 import org.apache.webbeans.spi.api.ResourceReference;
161 import org.apache.xbean.finder.AnnotationFinder;
162 import org.apache.xbean.finder.ClassLoaders;
163 import org.apache.xbean.finder.ResourceFinder;
164 import org.apache.xbean.finder.UrlSet;
165 import org.apache.xbean.finder.archive.ClassesArchive;
166 import org.apache.xbean.recipe.ConstructionException;
167 import org.apache.xbean.recipe.ObjectRecipe;
168 import org.apache.xbean.recipe.Option;
169 import org.apache.xbean.recipe.UnsetPropertiesRecipe;
170
171 import javax.annotation.PostConstruct;
172 import javax.annotation.PreDestroy;
173 import javax.annotation.Resource;
174 import javax.ejb.EJB;
175 import javax.enterprise.context.Dependent;
176 import javax.enterprise.context.spi.CreationalContext;
177 import javax.enterprise.inject.spi.Bean;
178 import javax.enterprise.inject.spi.BeanManager;
179 import javax.enterprise.inject.spi.DefinitionException;
180 import javax.enterprise.inject.spi.DeploymentException;
181 import javax.management.InstanceNotFoundException;
182 import javax.management.MBeanRegistrationException;
183 import javax.management.MBeanServer;
184 import javax.management.MalformedObjectNameException;
185 import javax.management.ObjectName;
186 import javax.naming.Binding;
187 import javax.naming.Context;
188 import javax.naming.InitialContext;
189 import javax.naming.NameAlreadyBoundException;
190 import javax.naming.NamingEnumeration;
191 import javax.naming.NamingException;
192 import javax.resource.cci.Connection;
193 import javax.resource.cci.ConnectionFactory;
194 import javax.resource.spi.BootstrapContext;
195 import javax.resource.spi.ConnectionManager;
196 import javax.resource.spi.ManagedConnectionFactory;
197 import javax.resource.spi.ResourceAdapter;
198 import javax.resource.spi.ResourceAdapterInternalException;
199 import javax.resource.spi.XATerminator;
200 import javax.resource.spi.work.WorkManager;
201 import javax.servlet.ServletContext;
202 import javax.sql.DataSource;
203 import javax.transaction.TransactionManager;
204 import javax.transaction.TransactionSynchronizationRegistry;
205 import javax.validation.ValidationException;
206 import javax.validation.Validator;
207 import javax.validation.ValidatorFactory;
208 import java.io.ByteArrayInputStream;
209 import java.io.ByteArrayOutputStream;
210 import java.io.Externalizable;
211 import java.io.File;
212 import java.io.IOException;
213 import java.io.InputStream;
214 import java.io.InvalidObjectException;
215 import java.io.ObjectStreamException;
216 import java.io.PrintStream;
217 import java.io.Serializable;
218 import java.lang.instrument.ClassFileTransformer;
219 import java.lang.instrument.Instrumentation;
220 import java.lang.management.ManagementFactory;
221 import java.lang.management.ThreadInfo;
222 import java.lang.reflect.Constructor;
223 import java.lang.reflect.Method;
224 import java.lang.reflect.Proxy;
225 import java.lang.reflect.Type;
226 import java.net.MalformedURLException;
227 import java.net.URISyntaxException;
228 import java.net.URL;
229 import java.util.ArrayList;
230 import java.util.Arrays;
231 import java.util.Collection;
232 import java.util.Collections;
233 import java.util.Comparator;
234 import java.util.HashMap;
235 import java.util.HashSet;
236 import java.util.Iterator;
237 import java.util.LinkedList;
238 import java.util.List;
239 import java.util.Map;
240 import java.util.Map.Entry;
241 import java.util.Properties;
242 import java.util.Set;
243 import java.util.TreeMap;
244 import java.util.concurrent.Callable;
245 import java.util.concurrent.ExecutionException;
246 import java.util.concurrent.Executor;
247 import java.util.concurrent.ExecutorService;
248 import java.util.concurrent.Executors;
249 import java.util.concurrent.TimeoutException;
250 import java.util.concurrent.atomic.AtomicBoolean;
251 import java.util.concurrent.atomic.AtomicReference;
252 import java.util.concurrent.locks.ReentrantLock;
253
254 import static org.apache.openejb.util.Classes.ancestors;
255
256 @SuppressWarnings({"UnusedDeclaration", "UnqualifiedFieldAccess", "UnqualifiedMethodAccess"})
257 public class Assembler extends AssemblerTool implements org.apache.openejb.spi.Assembler, JndiConstants {
258
259 static {
260 // avoid linkage error on mac
261 // adding just in case others run into in their tests
262 JULLoggerFactory.class.getName();
263 }
264
265 public static final String OPENEJB_URL_PKG_PREFIX = IvmContext.class.getPackage().getName();
266 public static final String OPENEJB_JPA_DEPLOY_TIME_ENHANCEMENT_PROP = "openejb.jpa.deploy-time-enhancement";
267 public static final String PROPAGATE_APPLICATION_EXCEPTIONS = "openejb.propagate.application-exceptions";
268 private static final String GLOBAL_UNIQUE_ID = "global";
269 public static final String TIMER_STORE_CLASS = "timerStore.class";
270 private static final ReentrantLock lock = new ReentrantLock(true);
271 public static final String OPENEJB_TIMERS_ON = "openejb.timers.on";
272 static final String FORCE_READ_ONLY_APP_NAMING = "openejb.forceReadOnlyAppNamingContext";
273
274 public static final Class<?>[] VALIDATOR_FACTORY_INTERFACES = new Class<?>[]{ValidatorFactory.class, Serializable.class};
275 public static final Class<?>[] VALIDATOR_INTERFACES = new Class<?>[]{Validator.class};
276 private final boolean skipLoaderIfPossible;
277
278 Messages messages = new Messages(Assembler.class.getPackage().getName());
279 public final Logger logger;
280 public final String resourceDestroyTimeout;
281 public final boolean threadStackOnTimeout;
282 private final CoreContainerSystem containerSystem;
283 private final PersistenceClassLoaderHandler persistenceClassLoaderHandler;
284 private final JndiBuilder jndiBuilder;
285 private TransactionManager transactionManager;
286 private SecurityService securityService;
287 protected OpenEjbConfigurationFactory configFactory;
288 private final Map<String, AppInfo> deployedApplications = new HashMap<String, AppInfo>();
289 private final Map<ObjectName, CreationalContext> creationalContextForAppMbeans = new HashMap<ObjectName, CreationalContext>();
290 private final Set<ObjectName> containerObjectNames = new HashSet<ObjectName>();
291 private final RemoteResourceMonitor remoteResourceMonitor = new RemoteResourceMonitor();
292
293 @Override
294 public ContainerSystem getContainerSystem() {
295 return containerSystem;
296 }
297
298 @Override
299 public TransactionManager getTransactionManager() {
300 return transactionManager;
301 }
302
303 @Override
304 public SecurityService getSecurityService() {
305 return securityService;
306 }
307
308 public void addDeploymentListener(final DeploymentListener deploymentListener) {
309
310 final ReentrantLock l = lock;
311 l.lock();
312
313 try {
314 logger.warning("DeploymentListener API is replaced by @Observes event");
315 SystemInstance.get().addObserver(new DeploymentListenerObserver(deploymentListener));
316 } finally {
317 l.unlock();
318 }
319 }
320
321 public void removeDeploymentListener(final DeploymentListener deploymentListener) {
322
323 final ReentrantLock l = lock;
324 l.lock();
325
326 try {
327 // the wrapping is done here to get the correct equals/hashcode methods
328 SystemInstance.get().removeObserver(new DeploymentListenerObserver(deploymentListener));
329 } finally {
330 l.unlock();
331 }
332 }
333
334 protected SafeToolkit toolkit = SafeToolkit.getToolkit("Assembler");
335 protected OpenEjbConfiguration config;
336
337 public Assembler() {
338 this(new IvmJndiFactory());
339 }
340
341 public Assembler(final JndiFactory jndiFactory) {
342 logger = Logger.getInstance(LogCategory.OPENEJB_STARTUP, Assembler.class);
343 skipLoaderIfPossible = "true".equalsIgnoreCase(SystemInstance.get().getProperty("openejb.classloader.skip-app-loader-if-possible", "true"));
344 resourceDestroyTimeout = SystemInstance.get().getProperty("openejb.resources.destroy.timeout");
345 threadStackOnTimeout = "true".equals(SystemInstance.get().getProperty("openejb.resources.destroy.stack-on-timeout", "false"));
346 persistenceClassLoaderHandler = new PersistenceClassLoaderHandlerImpl();
347
348 installNaming();
349
350 final SystemInstance system = SystemInstance.get();
351
352 system.setComponent(org.apache.openejb.spi.Assembler.class, this);
353 system.setComponent(Assembler.class, this);
354
355 containerSystem = new CoreContainerSystem(jndiFactory);
356 system.setComponent(ContainerSystem.class, containerSystem);
357
358 jndiBuilder = new JndiBuilder(containerSystem.getJNDIContext());
359
360 setConfiguration(new OpenEjbConfiguration());
361
362 final ApplicationServer appServer = system.getComponent(ApplicationServer.class);
363 if (appServer == null) {
364 system.setComponent(ApplicationServer.class, new ServerFederation());
365 }
366
367 system.setComponent(EjbResolver.class, new EjbResolver(null, EjbResolver.Scope.GLOBAL));
368
369 installExtensions();
370
371 system.fireEvent(new AssemblerCreated());
372
373 initBValFiltering();
374 }
375
376 private void initBValFiltering() {
377 if ("true".equals(SystemInstance.get().getProperty("openejb.cdi.bval.filter", "true"))) {
378 try { // bval jars are optional so do it by reflection
379 final ClassLoader loader = ParentClassLoaderFinder.Helper.get();
380 final Object filter = loader.loadClass("org.apache.openejb.bval.BValCdiFilter").newInstance();
381 loader.loadClass("org.apache.bval.cdi.BValExtension")
382 .getMethod(
383 "setAnnotatedTypeFilter",
384 loader.loadClass("org.apache.bval.cdi.BValExtension$AnnotatedTypeFilter"))
385 .invoke(null, filter);
386 } catch (final Throwable th) {
387 // ignore, bval not compatible or not present
388 }
389 }
390 }
391
392 private void installExtensions() {
393 try {
394 final Collection<URL> urls = NewLoaderLogic.applyBuiltinExcludes(new UrlSet(Assembler.class.getClassLoader()).excludeJvm()).getUrls();
395 Extensions.installExtensions(new Extensions.Finder("META-INF", false, urls.toArray(new URL[urls.size()])));
396 return;
397 } catch (final IOException e) {
398 // no-op
399 }
400
401 // if an error occurred do it brutely
402 Extensions.installExtensions(new Extensions.Finder("META-INF", true));
403 }
404
405 private void setConfiguration(final OpenEjbConfiguration config) {
406 this.config = config;
407 if (config.containerSystem == null) {
408 config.containerSystem = new ContainerSystemInfo();
409 }
410
411 if (config.facilities == null) {
412 config.facilities = new FacilitiesInfo();
413 }
414
415 SystemInstance.get().setComponent(OpenEjbConfiguration.class, this.config);
416 }
417
418 @Override
419 public void init(final Properties props) throws OpenEJBException {
420 this.props = new Properties(props);
421 final Options options = new Options(props, SystemInstance.get().getOptions());
422 final String className = options.get("openejb.configurator", "org.apache.openejb.config.ConfigurationFactory");
423
424 if ("org.apache.openejb.config.ConfigurationFactory".equals(className)) {
425 configFactory = new ConfigurationFactory(); // no need to use reflection
426 } else {
427 configFactory = (OpenEjbConfigurationFactory) toolkit.newInstance(className);
428 }
429 configFactory.init(props);
430 SystemInstance.get().setComponent(OpenEjbConfigurationFactory.class, configFactory);
431 }
432
433 public static void installNaming() {
434 if (SystemInstance.get().hasProperty("openejb.geronimo")) {
435 return;
436 }
437
438 /* Add IntraVM JNDI service /////////////////////*/
439 installNaming(OPENEJB_URL_PKG_PREFIX);
440 /*\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*/
441 }
442
443 public static void installNaming(final String prefix) {
444 installNaming(prefix, false);
445 }
446
447 public static void installNaming(final String prefix, final boolean clean) {
448
449 final ReentrantLock l = lock;
450 l.lock();
451
452 try {
453 final Properties systemProperties = JavaSecurityManagers.getSystemProperties();
454
455 String str = systemProperties.getProperty(Context.URL_PKG_PREFIXES);
456 if (str == null || clean) {
457 str = prefix;
458 } else if (!str.contains(prefix)) {
459 str = str + ":" + prefix;
460 }
461 systemProperties.setProperty(Context.URL_PKG_PREFIXES, str);
462 } finally {
463 l.unlock();
464 }
465 }
466
467 private static final ThreadLocal<Map<String, Object>> context = new ThreadLocal<Map<String, Object>>();
468
469 public static void setContext(final Map<String, Object> map) {
470 context.set(map);
471 }
472
473 public static Map<String, Object> getContext() {
474 Map<String, Object> map = context.get();
475 if (map == null) {
476 map = new HashMap<String, Object>();
477 context.set(map);
478 }
479 return map;
480 }
481
482 @Override
483 public void build() throws OpenEJBException {
484 setContext(new HashMap<String, Object>());
485 try {
486 final OpenEjbConfiguration config = getOpenEjbConfiguration();
487 buildContainerSystem(config);
488 } catch (final OpenEJBException ae) {
489 /* OpenEJBExceptions contain useful information and are debbugable.
490 * Let the exception pass through to the top and be logged.
491 */
492 throw ae;
493 } catch (final Exception e) {
494 /* General Exceptions at this level are too generic and difficult to debug.
495 * These exceptions are considered unknown bugs and are fatal.
496 * If you get an error at this level, please trap and handle the error
497 * where it is most relevant.
498 */
499 OpenEJBErrorHandler.handleUnknownError(e, "Assembler");
500 throw new OpenEJBException(e);
501 } finally {
502 context.set(null);
503 }
504 }
505
506 protected OpenEjbConfiguration getOpenEjbConfiguration() throws OpenEJBException {
507 return configFactory.getOpenEjbConfiguration();
508 }
509
510 /////////////////////////////////////////////////////////////////////
511 ////
512 //// Public Methods Used for Assembly
513 ////
514 /////////////////////////////////////////////////////////////////////
515
516 /**
517 * When given a complete OpenEjbConfiguration graph this method
518 * will construct an entire container system and return a reference to that
519 * container system, as ContainerSystem instance.
520 * <p/>
521 * This method leverage the other assemble and apply methods which
522 * can be used independently.
523 * <p/>
524 * Assembles and returns the {@link CoreContainerSystem} using the
525 * information from the {@link OpenEjbConfiguration} object passed in.
526 * <pre>
527 * This method performs the following actions(in order):
528 *
529 * 1 Assembles ProxyFactory
530 * 2 Assembles External JNDI Contexts
531 * 3 Assembles TransactionService
532 * 4 Assembles SecurityService
533 * 5 Assembles ConnectionManagers
534 * 6 Assembles Connectors
535 * 7 Assembles Containers
536 * 8 Assembles Applications
537 * </pre>
538 *
539 * @param configInfo OpenEjbConfiguration
540 * @throws Exception if there was a problem constructing the ContainerSystem.
541 * @see OpenEjbConfiguration
542 */
543 @SuppressWarnings("ThrowableResultOfMethodCallIgnored")
544 public void buildContainerSystem(final OpenEjbConfiguration configInfo) throws Exception {
545 final SystemInstance systemInstance = SystemInstance.get();
546 if (systemInstance.getOptions().get(OPENEJB_JPA_DEPLOY_TIME_ENHANCEMENT_PROP, false)) {
547 systemInstance.addObserver(new DeployTimeEnhancer());
548 }
549 if (hasBatchEE()) {
550 systemInstance.addObserver(new BatchEEServiceManager());
551 }
552
553 for (final ServiceInfo serviceInfo : configInfo.facilities.services) {
554 createService(serviceInfo);
555 }
556
557 final ContainerSystemInfo containerSystemInfo = configInfo.containerSystem;
558
559 if (configInfo.facilities.intraVmServer != null) {
560 createProxyFactory(configInfo.facilities.intraVmServer);
561 }
562
563 for (final JndiContextInfo contextInfo : configInfo.facilities.remoteJndiContexts) {
564 createExternalContext(contextInfo);
565 }
566
567 createTransactionManager(configInfo.facilities.transactionService);
568
569 createSecurityService(configInfo.facilities.securityService);
570
571 final Set<String> reservedResourceIds = new HashSet<>(configInfo.facilities.resources.size());
572 for (final AppInfo appInfo : containerSystemInfo.applications) {
573 reservedResourceIds.addAll(appInfo.resourceIds);
574 }
575
576 final Map<AppInfo, ClassLoader> appInfoClassLoaders = new HashMap<AppInfo, ClassLoader>();
577 final Map<String, ClassLoader> appClassLoaders = new HashMap<String, ClassLoader>();
578
579 for (final AppInfo appInfo : containerSystemInfo.applications) {
580 appInfoClassLoaders.put(appInfo, createAppClassLoader(appInfo));
581 appClassLoaders.put(appInfo.appId, createAppClassLoader(appInfo));
582 }
583
584 final Set<String> rIds = new HashSet<>(configInfo.facilities.resources.size());
585 for (final ResourceInfo resourceInfo : configInfo.facilities.resources) {
586 createResource(configInfo.facilities.services, resourceInfo);
587 rIds.add(resourceInfo.id);
588 }
589 rIds.removeAll(reservedResourceIds);
590 final ContainerSystem component = systemInstance.getComponent(ContainerSystem.class);
591 if (component != null) {
592 postConstructResources(rIds, ParentClassLoaderFinder.Helper.get(), component.getJNDIContext(), null);
593 }else {
594 throw new RuntimeException("ContainerSystem has not been initialzed");
595 }
596
597 // Containers - create containers using the application's classloader
598 final Map<String, List<ContainerInfo>> appContainers = new HashMap<String, List<ContainerInfo>>();
599
600 for (final ContainerInfo serviceInfo : containerSystemInfo.containers) {
601 List<ContainerInfo> containerInfos = appContainers.get(serviceInfo.originAppName);
602 if (containerInfos == null) {
603 containerInfos = new ArrayList<ContainerInfo>();
604 appContainers.put(serviceInfo.originAppName, containerInfos);
605 }
606
607 containerInfos.add(serviceInfo);
608 }
609
610 final Set<String> apps = appContainers.keySet();
611 for (final String app : apps) {
612 final List<ContainerInfo> containerInfos = appContainers.get(app);
613 final ClassLoader classLoader = appClassLoaders.get(app);
614
615 final ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
616
617 try {
618 if (classLoader != null) {
619 Thread.currentThread().setContextClassLoader(classLoader);
620 }
621
622 for (final ContainerInfo containerInfo : containerInfos) {
623 createContainer(containerInfo);
624 }
625 } finally {
626 Thread.currentThread().setContextClassLoader(oldCl);
627 }
628 }
629
630 createJavaGlobal(); // before any deployment bind global to be able to share the same context
631
632 for (final AppInfo appInfo : containerSystemInfo.applications) {
633
634 try {
635 createApplication(appInfo, appInfoClassLoaders.get(appInfo)); // use the classloader from the map above
636 } catch (final DuplicateDeploymentIdException e) {
637 // already logged.
638 } catch (final Throwable e) {
639 logger.error("appNotDeployed", e, appInfo.path);
640
641 final DeploymentExceptionManager exceptionManager = systemInstance.getComponent(DeploymentExceptionManager.class);
642 if (exceptionManager != null && e instanceof Exception) {
643 exceptionManager.saveDeploymentException(appInfo, (Exception) e);
644 }
645 }
646 }
647
648 systemInstance.fireEvent(new ContainerSystemPostCreate());
649 }
650
651 private static boolean hasBatchEE() {
652 try {
653 Class.forName("org.apache.batchee.container.services.ServicesManager", true, Assembler.class.getClassLoader());
654 return true;
655 } catch (final Throwable e) {
656 return false;
657 }
658 }
659
660 private void createJavaGlobal() {
661 try {
662 containerSystem.getJNDIContext().createSubcontext("global");
663 } catch (final NamingException e) {
664 // no-op
665 }
666 }
667
668 public AppInfo getAppInfo(final String path) {
669 return deployedApplications.get(ProvisioningUtil.realLocation(path).iterator().next());
670 }
671
672 public boolean isDeployed(final String path) {
673 return deployedApplications.containsKey(ProvisioningUtil.realLocation(path).iterator().next());
674 }
675
676 public Collection<AppInfo> getDeployedApplications() {
677 return new ArrayList<AppInfo>(deployedApplications.values());
678 }
679
680 public AppContext createApplication(final EjbJarInfo ejbJar) throws NamingException, IOException, OpenEJBException {
681 return createEjbJar(ejbJar);
682 }
683
684 public AppContext createEjbJar(final EjbJarInfo ejbJar) throws NamingException, IOException, OpenEJBException {
685 final AppInfo appInfo = new AppInfo();
686 appInfo.path = ejbJar.path;
687 appInfo.appId = ejbJar.moduleName;
688 appInfo.ejbJars.add(ejbJar);
689 return createApplication(appInfo);
690 }
691
692 public AppContext createApplication(final EjbJarInfo ejbJar, final ClassLoader classLoader) throws NamingException, IOException, OpenEJBException {
693 return createEjbJar(ejbJar, classLoader);
694 }
695
696 public AppContext createEjbJar(final EjbJarInfo ejbJar, final ClassLoader classLoader) throws NamingException, IOException, OpenEJBException {
697 final AppInfo appInfo = new AppInfo();
698 appInfo.path = ejbJar.path;
699 appInfo.appId = ejbJar.moduleName;
700 appInfo.ejbJars.add(ejbJar);
701 return createApplication(appInfo, classLoader);
702 }
703
704 public AppContext createClient(final ClientInfo clientInfo) throws NamingException, IOException, OpenEJBException {
705 final AppInfo appInfo = new AppInfo();
706 appInfo.path = clientInfo.path;
707 appInfo.appId = clientInfo.moduleId;
708 appInfo.clients.add(clientInfo);
709 return createApplication(appInfo);
710 }
711
712 public AppContext createClient(final ClientInfo clientInfo, final ClassLoader classLoader) throws NamingException, IOException, OpenEJBException {
713 final AppInfo appInfo = new AppInfo();
714 appInfo.path = clientInfo.path;
715 appInfo.appId = clientInfo.moduleId;
716 appInfo.clients.add(clientInfo);
717 return createApplication(appInfo, classLoader);
718 }
719
720 public AppContext createConnector(final ConnectorInfo connectorInfo) throws NamingException, IOException, OpenEJBException {
721 final AppInfo appInfo = new AppInfo();
722 appInfo.path = connectorInfo.path;
723 appInfo.appId = connectorInfo.moduleId;
724 appInfo.connectors.add(connectorInfo);
725 return createApplication(appInfo);
726 }
727
728 public AppContext createConnector(final ConnectorInfo connectorInfo, final ClassLoader classLoader) throws NamingException, IOException, OpenEJBException {
729 final AppInfo appInfo = new AppInfo();
730 appInfo.path = connectorInfo.path;
731 appInfo.appId = connectorInfo.moduleId;
732 appInfo.connectors.add(connectorInfo);
733 return createApplication(appInfo, classLoader);
734 }
735
736 public AppContext createWebApp(final WebAppInfo webAppInfo) throws NamingException, IOException, OpenEJBException {
737 final AppInfo appInfo = new AppInfo();
738 appInfo.path = webAppInfo.path;
739 appInfo.appId = webAppInfo.moduleId;
740 appInfo.webApps.add(webAppInfo);
741 return createApplication(appInfo);
742 }
743
744 public AppContext createWebApp(final WebAppInfo webAppInfo, final ClassLoader classLoader) throws NamingException, IOException, OpenEJBException {
745 final AppInfo appInfo = new AppInfo();
746 appInfo.path = webAppInfo.path;
747 appInfo.appId = webAppInfo.moduleId;
748 appInfo.webApps.add(webAppInfo);
749 return createApplication(appInfo, classLoader);
750 }
751
752 public AppContext createApplication(final AppInfo appInfo) throws OpenEJBException, IOException, NamingException {
753 return createApplication(appInfo, createAppClassLoader(appInfo));
754 }
755
756 public AppContext createApplication(final AppInfo appInfo, final ClassLoader classLoader) throws OpenEJBException, IOException, NamingException {
757 return createApplication(appInfo, classLoader, true);
758 }
759
760 private AppContext createApplication(final AppInfo appInfo, ClassLoader classLoader, final boolean start) throws OpenEJBException, IOException, NamingException {
761 try {
762 try {
763 mergeServices(appInfo);
764 } catch (final URISyntaxException e) {
765 logger.info("Can't merge resources.xml services and appInfo.properties");
766 }
767
768 // The path is used in the UrlCache, command line deployer, JNDI name templates, tomcat integration and a few other places
769 if (appInfo.appId == null) {
770 throw new IllegalArgumentException("AppInfo.appId cannot be null");
771 }
772 if (appInfo.path == null) {
773 appInfo.path = appInfo.appId;
774 }
775
776 Extensions.addExtensions(classLoader, appInfo.eventClassesNeedingAppClassloader);
777 logger.info("createApplication.start", appInfo.path);
778 final Context containerSystemContext = containerSystem.getJNDIContext();
779
780 // To start out, ensure we don't already have any beans deployed with duplicate IDs. This
781 // is a conflict we can't handle.
782 final List<String> used = getDuplicates(appInfo);
783
784 if (used.size() > 0) {
785 String message = logger.error("createApplication.appFailedDuplicateIds", appInfo.path);
786 for (final String id : used) {
787 logger.error("createApplication.deploymentIdInUse", id);
788 message += "\n " + id;
789 }
790 throw new DuplicateDeploymentIdException(message);
791 }
792
793 final ClassLoader oldCl = Thread.currentThread().getContextClassLoader();
794 try {
795 Thread.currentThread().setContextClassLoader(classLoader);
796 for (final ContainerInfo container : appInfo.containers) {
797 createContainer(container);
798 }
799 } finally {
800 Thread.currentThread().setContextClassLoader(oldCl);
801 }
802
803 //Construct the global and app jndi contexts for this app
804 final InjectionBuilder injectionBuilder = new InjectionBuilder(classLoader);
805
806 final Set<Injection> injections = new HashSet<Injection>();
807 injections.addAll(injectionBuilder.buildInjections(appInfo.globalJndiEnc));
808 injections.addAll(injectionBuilder.buildInjections(appInfo.appJndiEnc));
809
810 final JndiEncBuilder globalBuilder = new JndiEncBuilder(appInfo.globalJndiEnc, injections, appInfo.appId, null, GLOBAL_UNIQUE_ID, classLoader, appInfo.properties);
811 final Map<String, Object> globalBindings = globalBuilder.buildBindings(JndiEncBuilder.JndiScope.global);
812 final Context globalJndiContext = globalBuilder.build(globalBindings);
813
814 final JndiEncBuilder appBuilder = new JndiEncBuilder(appInfo.appJndiEnc, injections, appInfo.appId, null, appInfo.appId, classLoader, appInfo.properties);
815 final Map<String, Object> appBindings = appBuilder.buildBindings(JndiEncBuilder.JndiScope.app);
816 final Context appJndiContext = appBuilder.build(appBindings);
817
818 final boolean cdiActive = shouldStartCdi(appInfo);
819
820 try {
821 // Generate the cmp2/cmp1 concrete subclasses
822 final CmpJarBuilder cmpJarBuilder = new CmpJarBuilder(appInfo, classLoader);
823 final File generatedJar = cmpJarBuilder.getJarFile();
824 if (generatedJar != null) {
825 classLoader = ClassLoaderUtil.createClassLoader(appInfo.path, new URL[]{generatedJar.toURI().toURL()}, classLoader);
826 }
827
828 final AppContext appContext = new AppContext(appInfo.appId, SystemInstance.get(), classLoader, globalJndiContext, appJndiContext, appInfo.standaloneModule);
829 appContext.getProperties().putAll(appInfo.properties);
830 appContext.getInjections().addAll(injections);
831 appContext.getBindings().putAll(globalBindings);
832 appContext.getBindings().putAll(appBindings);
833
834 containerSystem.addAppContext(appContext);
835
836 appContext.set(AsynchronousPool.class, AsynchronousPool.create(appContext));
837
838 final Map<String, LazyValidatorFactory> lazyValidatorFactories = new HashMap<String, LazyValidatorFactory>();
839 final Map<String, LazyValidator> lazyValidators = new HashMap<String, LazyValidator>();
840 final boolean isGeronimo = SystemInstance.get().hasProperty("openejb.geronimo");
841
842 // try to not create N times the same validator for a single app
843 final Map<ComparableValidationConfig, ValidatorFactory> validatorFactoriesByConfig = new HashMap<ComparableValidationConfig, ValidatorFactory>();
844 if (!isGeronimo) {
845 // Bean Validation
846 // ValidatorFactory needs to be put in the map sent to the entity manager factory
847 // so it has to be constructed before
848 final List<CommonInfoObject> vfs = listCommonInfoObjectsForAppInfo(appInfo);
849 final Map<String, ValidatorFactory> validatorFactories = new HashMap<String, ValidatorFactory>();
850
851 for (final CommonInfoObject info : vfs) {
852 if (info.validationInfo == null) {
853 continue;
854 }
855
856 final ComparableValidationConfig conf = new ComparableValidationConfig(
857 info.validationInfo.providerClassName, info.validationInfo.messageInterpolatorClass,
858 info.validationInfo.traversableResolverClass, info.validationInfo.constraintFactoryClass,
859 info.validationInfo.parameterNameProviderClass, info.validationInfo.version,
860 info.validationInfo.propertyTypes, info.validationInfo.constraintMappings,
861 info.validationInfo.executableValidationEnabled, info.validationInfo.validatedTypes
862 );
863 ValidatorFactory factory = validatorFactoriesByConfig.get(conf);
864 if (factory == null) {
865 try { // lazy cause of CDI :(
866 final LazyValidatorFactory handler = new LazyValidatorFactory(classLoader, info.validationInfo);
867 factory = (ValidatorFactory) Proxy.newProxyInstance(
868 appContext.getClassLoader(), VALIDATOR_FACTORY_INTERFACES, handler);
869 lazyValidatorFactories.put(info.uniqueId, handler);
870 } catch (final ValidationException ve) {
871 logger.warning("can't build the validation factory for module " + info.uniqueId, ve);
872 continue;
873 }
874 validatorFactoriesByConfig.put(conf, factory);
875 } else {
876 lazyValidatorFactories.put(info.uniqueId, LazyValidatorFactory.class.cast(Proxy.getInvocationHandler(factory)));
877 }
878 validatorFactories.put(info.uniqueId, factory);
879 }
880
881 // validators bindings
882 for (final Entry<String, ValidatorFactory> validatorFactory : validatorFactories.entrySet()) {
883 final String id = validatorFactory.getKey();
884 final ValidatorFactory factory = validatorFactory.getValue();
885 try {
886 containerSystemContext.bind(VALIDATOR_FACTORY_NAMING_CONTEXT + id, factory);
887
888 final Validator validator;
889 try {
890 final LazyValidator lazyValidator = new LazyValidator(factory);
891 validator = (Validator) Proxy.newProxyInstance(appContext.getClassLoader(), VALIDATOR_INTERFACES, lazyValidator);
892 lazyValidators.put(id, lazyValidator);
893 } catch (final Exception e) {
894 logger.error(e.getMessage(), e);
895 continue;
896 }
897
898 containerSystemContext.bind(VALIDATOR_NAMING_CONTEXT + id, validator);
899 } catch (final NameAlreadyBoundException e) {
900 throw new OpenEJBException("ValidatorFactory already exists for module " + id, e);
901 } catch (final Exception e) {
902 throw new OpenEJBException(e);
903 }
904 }
905
906 validatorFactories.clear();
907 }
908
909 // JPA - Persistence Units MUST be processed first since they will add ClassFileTransformers
910 // to the class loader which must be added before any classes are loaded
911 final Map<String, String> units = new HashMap<String, String>();
912 final PersistenceBuilder persistenceBuilder = new PersistenceBuilder(persistenceClassLoaderHandler);
913 for (final PersistenceUnitInfo info : appInfo.persistenceUnits) {
914 final ReloadableEntityManagerFactory factory;
915 try {
916 factory = persistenceBuilder.createEntityManagerFactory(info, classLoader, validatorFactoriesByConfig, cdiActive);
917 containerSystem.getJNDIContext().bind(PERSISTENCE_UNIT_NAMING_CONTEXT + info.id, factory);
918 units.put(info.name, PERSISTENCE_UNIT_NAMING_CONTEXT + info.id);
919 } catch (final NameAlreadyBoundException e) {
920 throw new OpenEJBException("PersistenceUnit already deployed: " + info.persistenceUnitRootUrl);
921 } catch (final Exception e) {
922 throw new OpenEJBException(e);
923 }
924
925 factory.register();
926 }
927
928 logger.debug("Loaded peristence units: " + units);
929
930 // Connectors
931 for (final ConnectorInfo connector : appInfo.connectors) {
932 final ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
933 Thread.currentThread().setContextClassLoader(classLoader);
934 try {
935 // todo add undeployment code for these
936 if (connector.resourceAdapter != null) {
937 createResource(null, connector.resourceAdapter);
938 }
939 for (final ResourceInfo outbound : connector.outbound) {
940 createResource(null, outbound);
941 outbound.properties.setProperty("openejb.connector", "true"); // set it after as a marker but not as an attribute (no getOpenejb().setConnector(...))
942 }
943 for (final MdbContainerInfo inbound : connector.inbound) {
944 createContainer(inbound);
945 }
946 for (final ResourceInfo adminObject : connector.adminObject) {
947 createResource(null, adminObject);
948 }
949 } finally {
950 Thread.currentThread().setContextClassLoader(oldClassLoader);
951 }
952 }
953
954 final List<BeanContext> allDeployments = initEjbs(classLoader, appInfo, appContext, injections, new ArrayList<BeanContext>(), null);
955
956 if ("true".equalsIgnoreCase(SystemInstance.get()
957 .getProperty(PROPAGATE_APPLICATION_EXCEPTIONS,
958 appInfo.properties.getProperty(PROPAGATE_APPLICATION_EXCEPTIONS, "false")))) {
959 propagateApplicationExceptions(appInfo, classLoader, allDeployments);
960 }
961
962 if (cdiActive) {
963 new CdiBuilder().build(appInfo, appContext, allDeployments);
964 ensureWebBeansContext(appContext);
965 appJndiContext.bind("app/BeanManager", appContext.getBeanManager());
966 appContext.getBindings().put("app/BeanManager", appContext.getBeanManager());
967 } else { // ensure we can reuse it in tomcat to remove OWB filters
968 appInfo.properties.setProperty("openejb.cdi.activated", "false");
969 }
970
971 // now cdi is started we can try to bind real validator factory and validator
972 if (!isGeronimo) {
973 for (final Entry<String, LazyValidator> lazyValidator : lazyValidators.entrySet()) {
974 final String id = lazyValidator.getKey();
975 final ValidatorFactory factory = lazyValidatorFactories.get(lazyValidator.getKey()).getFactory();
976 try {
977 final String factoryName = VALIDATOR_FACTORY_NAMING_CONTEXT + id;
978 containerSystemContext.unbind(factoryName);
979 containerSystemContext.bind(factoryName, factory);
980
981 final String validatoryName = VALIDATOR_NAMING_CONTEXT + id;
982 try { // do it after factory cause of TCKs which expects validator to be created later
983 final Validator val = lazyValidator.getValue().getValidator();
984 containerSystemContext.unbind(validatoryName);
985 containerSystemContext.bind(validatoryName, val);
986 } catch (final Exception e) {
987 logger.error(e.getMessage(), e);
988 }
989 } catch (final NameAlreadyBoundException e) {
990 throw new OpenEJBException("ValidatorFactory already exists for module " + id, e);
991 } catch (final Exception e) {
992 throw new OpenEJBException(e);
993 }
994 }
995 }
996
997 startEjbs(start, allDeployments);
998
999 // App Client
1000 for (final ClientInfo clientInfo : appInfo.clients) {
1001 // determine the injections
1002 final List<Injection> clientInjections = injectionBuilder.buildInjections(clientInfo.jndiEnc);
1003
1004 // build the enc
1005 final JndiEncBuilder jndiEncBuilder = new JndiEncBuilder(clientInfo.jndiEnc, clientInjections, "Bean", clientInfo.moduleId, null, clientInfo.uniqueId, classLoader, new Properties());
1006 // if there is at least a remote client classes
1007 // or if there is no local client classes
1008 // then, we can set the client flag
1009 if (clientInfo.remoteClients.size() > 0 || clientInfo.localClients.size() == 0) {
1010 jndiEncBuilder.setClient(true);
1011
1012 }
1013 jndiEncBuilder.setUseCrossClassLoaderRef(false);
1014 final Context context = jndiEncBuilder.build(JndiEncBuilder.JndiScope.comp);
1015
1016 // Debug.printContext(context);
1017
1018 containerSystemContext.bind("openejb/client/" + clientInfo.moduleId, context);
1019
1020 if (clientInfo.path != null) {
1021 context.bind("info/path", clientInfo.path);
1022 }
1023 if (clientInfo.mainClass != null) {
1024 context.bind("info/mainClass", clientInfo.mainClass);
1025 }
1026 if (clientInfo.callbackHandler != null) {
1027 context.bind("info/callbackHandler", clientInfo.callbackHandler);
1028 }
1029 context.bind("info/injections", clientInjections);
1030
1031 for (final String clientClassName : clientInfo.remoteClients) {
1032 containerSystemContext.bind("openejb/client/" + clientClassName, clientInfo.moduleId);
1033 }
1034
1035 for (final String clientClassName : clientInfo.localClients) {
1036 containerSystemContext.bind("openejb/client/" + clientClassName, clientInfo.moduleId);
1037 logger.getChildLogger("client").info("createApplication.createLocalClient", clientClassName, clientInfo.moduleId);
1038 }
1039 }
1040
1041 // WebApp
1042 final SystemInstance systemInstance = SystemInstance.get();
1043
1044 final WebAppBuilder webAppBuilder = systemInstance.getComponent(WebAppBuilder.class);
1045 if (webAppBuilder != null) {
1046 webAppBuilder.deployWebApps(appInfo, classLoader);
1047 }
1048
1049 if (start) {
1050 final EjbResolver globalEjbResolver = systemInstance.getComponent(EjbResolver.class);
1051 globalEjbResolver.addAll(appInfo.ejbJars);
1052 }
1053
1054 // bind all global values on global context
1055 bindGlobals(appContext.getBindings());
1056
1057 validateCdiResourceProducers(appContext, appInfo);
1058
1059 // deploy MBeans
1060 for (final String mbean : appInfo.mbeans) {
1061 deployMBean(appContext.getWebBeansContext(), classLoader, mbean, appInfo.jmx, appInfo.appId);
1062 }
1063 for (final EjbJarInfo ejbJarInfo : appInfo.ejbJars) {
1064 for (final String mbean : ejbJarInfo.mbeans) {
1065 deployMBean(appContext.getWebBeansContext(), classLoader, mbean, appInfo.jmx, ejbJarInfo.moduleName);
1066 }
1067 }
1068 for (final ConnectorInfo connectorInfo : appInfo.connectors) {
1069 for (final String mbean : connectorInfo.mbeans) {
1070 deployMBean(appContext.getWebBeansContext(), classLoader, mbean, appInfo.jmx, appInfo.appId + ".add-lib");
1071 }
1072 }
1073
1074 postConstructResources(appInfo.resourceIds, classLoader, containerSystemContext, appContext);
1075
1076 deployedApplications.put(appInfo.path, appInfo);
1077 resumePersistentSchedulers(appContext);
1078
1079 systemInstance.fireEvent(new AssemblerAfterApplicationCreated(appInfo, appContext, allDeployments));
1080 logger.info("createApplication.success", appInfo.path);
1081
1082 //required by spec EE.5.3.4
1083 if(setAppNamingContextReadOnly(allDeployments)) {
1084 logger.info("createApplication.naming", appInfo.path);
1085 }
1086
1087 return appContext;
1088 } catch (final ValidationException | DeploymentException ve) {
1089 throw ve;
1090 } catch (final Throwable t) {
1091 try {
1092 destroyApplication(appInfo);
1093 } catch (final Exception e1) {
1094 logger.debug("createApplication.undeployFailed", e1, appInfo.path);
1095 }
1096 throw new OpenEJBException(messages.format("createApplication.failed", appInfo.path), t);
1097 }
1098 } finally {
1099 // cleanup there as well by safety cause we have multiple deployment mode (embedded, tomcat...)
1100 for (final WebAppInfo webApp : appInfo.webApps) {
1101 appInfo.properties.remove(webApp);
1102 }
1103 }
1104 }
1105
1106 boolean setAppNamingContextReadOnly(final List<BeanContext> allDeployments) {
1107 if("true".equals(SystemInstance.get().getProperty(FORCE_READ_ONLY_APP_NAMING, "false"))) {
1108 for(BeanContext beanContext : allDeployments) {
1109 Context ctx = beanContext.getJndiContext();
1110
1111 if(IvmContext.class.isInstance(ctx)) {
1112 IvmContext.class.cast(ctx).setReadOnly(true);
1113 } else if(ContextHandler.class.isInstance(ctx)) {
1114 ContextHandler.class.cast(ctx).setReadOnly();
1115 }
1116 }
1117 return true;
1118 }
1119 return false;
1120 }
1121
1122 private List<String> getDuplicates(final AppInfo appInfo) {
1123 final List<String> used = new ArrayList<String>();
1124 for (final EjbJarInfo ejbJarInfo : appInfo.ejbJars) {
1125 for (final EnterpriseBeanInfo beanInfo : ejbJarInfo.enterpriseBeans) {
1126 if (containerSystem.getBeanContext(beanInfo.ejbDeploymentId) != null) {
1127 used.add(beanInfo.ejbDeploymentId);
1128 }
1129 }
1130 }
1131 return used;
1132 }
1133
1134 private boolean shouldStartCdi(final AppInfo appInfo) {
1135 if (!"true".equalsIgnoreCase(appInfo.properties.getProperty("openejb.cdi.activated", "true"))) {
1136 return false;
1137 }
1138 for (final EjbJarInfo ejbJarInfo : appInfo.ejbJars) {
1139 if (ejbJarInfo.beans != null
1140 && (!ejbJarInfo.beans.bdas.isEmpty() || !ejbJarInfo.beans.noDescriptorBdas.isEmpty())) {
1141 return true;
1142 }
1143 }
1144 return false;
1145 }
1146
1147 private void validateCdiResourceProducers(final AppContext appContext, final AppInfo info) {
1148 if (appContext.getWebBeansContext() == null) {
1149 return;
1150 }
1151 // validate @Produces @Resource/@PersistenceX/@EJB once all is bound to JNDI - best case - or with our model
1152 if (appContext.isStandaloneModule() && !appContext.getProperties().containsKey("openejb.cdi.skip-resource-validation")) {
1153 final Map<String, Object> bindings =
1154 appContext.getWebContexts().isEmpty() ? appContext.getBindings() : appContext.getWebContexts().iterator().next().getBindings();
1155 if (bindings != null && appContext.getWebBeansContext() != null && appContext.getWebBeansContext().getBeanManagerImpl().isInUse()) {
1156 for (final Bean<?> bean : appContext.getWebBeansContext().getBeanManagerImpl().getBeans()) {
1157 if (ResourceBean.class.isInstance(bean)) {
1158 final ResourceReference reference = ResourceBean.class.cast(bean).getReference();
1159 String jndi = reference.getJndiName().replace("java:", "");
1160 if (reference.getJndiName().startsWith("java:/")) {
1161 jndi = jndi.substring(1);
1162 }
1163 Object lookup = bindings.get(jndi);
1164 if (lookup == null && reference.getAnnotation(EJB.class) != null) {
1165 final CdiPlugin plugin = CdiPlugin.class.cast(appContext.getWebBeansContext().getPluginLoader().getEjbPlugin());
1166 if (!plugin.isSessionBean(reference.getResourceType())) { // local beans are here and access is O(1) instead of O(n)
1167 boolean ok = false;
1168 for (final BeanContext bc : appContext.getBeanContexts()) {
1169 if (bc.getBusinessLocalInterfaces().contains(reference.getResourceType())
1170 || bc.getBusinessRemoteInterfaces().contains(reference.getResourceType())) {
1171 ok = true;
1172 break;
1173 }
1174 }
1175 if (!ok) {
1176 throw new DefinitionException(
1177 "EJB " + reference.getJndiName() + " in " + reference.getOwnerClass() + " can't be cast to " + reference.getResourceType());
1178 }
1179 }
1180 }
1181 if (Reference.class.isInstance(lookup)) {
1182 try {
1183 lookup = Reference.class.cast(lookup).getContent();
1184 } catch (final Exception e) { // surely too early, let's try some known locations
1185 if (JndiUrlReference.class.isInstance(lookup)) {
1186 checkBuiltInResourceTypes(reference, JndiUrlReference.class.cast(lookup).getJndiName());
1187 }
1188 continue;
1189 }
1190 } else if (lookup == null) { // TODO: better validation with lookups in tomee, should be in TWAB surely but would split current code
1191 final Resource r = Resource.class.cast(reference.getAnnotation(Resource.class));
1192 if (r != null) {
1193 if (!r.lookup().isEmpty()) {
1194 checkBuiltInResourceTypes(reference, r.lookup());
1195 } else if (!r.name().isEmpty()) {
1196 final String name = "comp/env/" + r.name();
1197 boolean done = false;
1198 for (final WebAppInfo w : info.webApps) {
1199 for (final EnvEntryInfo e : w.jndiEnc.envEntries) {
1200 if (name.equals(e.referenceName)) {
1201 if (e.type != null && !reference.getResourceType().getName().equals(e.type)) {
1202 throw new DefinitionException(
1203 "Env Entry " + reference.getJndiName() + " in " + reference.getOwnerClass() + " can't be cast to " + reference.getResourceType());
1204 }
1205 done = true;
1206 break;
1207 }
1208 }
1209 if (done) {
1210 break;
1211 }
1212 }
1213 }
1214 }
1215 }
1216 if (lookup != null && !reference.getResourceType().isInstance(lookup)) {
1217 throw new DefinitionException(
1218 "Resource " + reference.getJndiName() + " in " + reference.getOwnerClass() + " can't be cast, instance is " + lookup);
1219 }
1220 }
1221 }
1222 }
1223 }
1224 }
1225
1226 private void checkBuiltInResourceTypes(final ResourceReference reference, final String jndi) {
1227 final Class<?> resourceType = reference.getResourceType();
1228 if ("java:comp/BeanManager".equals(jndi) && resourceType != BeanManager.class) {
1229 throw new DefinitionException(
1230 "Resource " + reference.getJndiName() + " in " + reference.getOwnerClass() + " can't be cast to a BeanManager");
1231 } else if ("java:comp/TransactionSynchronizationRegistry".equals(jndi) && resourceType != TransactionSynchronizationRegistry.class) {
1232 throw new DefinitionException(
1233 "Resource " + reference.getJndiName() + " in " + reference.getOwnerClass() + " can't be cast to a TransactionSynchronizationRegistry");
1234 } else if ("java:comp/TransactionManager".equals(jndi) && resourceType != TransactionManager.class) {
1235 throw new DefinitionException(
1236 "Resource " + reference.getJndiName() + " in " + reference.getOwnerClass() + " can't be cast to a TransactionManager");
1237 } else if ("java:comp/ValidatorFactory".equals(jndi) && resourceType != ValidatorFactory.class) {
1238 throw new DefinitionException(
1239 "Resource " + reference.getJndiName() + " in " + reference.getOwnerClass() + " can't be cast to a ValidatorFactory");
1240 } else if ("java:comp/Validator".equals(jndi) && resourceType != Validator.class) {
1241 throw new DefinitionException(
1242 "Resource " + reference.getJndiName() + " in " + reference.getOwnerClass() + " can't be cast to a Validator");
1243 }
1244 }
1245
1246 private void postConstructResources(
1247 final Set<String> resourceIds, final ClassLoader classLoader,
1248 final Context containerSystemContext, final AppContext appContext) throws NamingException, OpenEJBException {
1249 final Thread thread = Thread.currentThread();
1250 final ClassLoader oldCl = thread.getContextClassLoader();
1251
1252 try {
1253 thread.setContextClassLoader(classLoader);
1254
1255 final List<ResourceInfo> resourceList = config.facilities.resources;
1256
1257 for (final ResourceInfo resourceInfo : resourceList) {
1258 if (!resourceIds.contains(resourceInfo.id)) {
1259 continue;
1260 }
1261 if (isTemplatizedResource(resourceInfo)) {
1262 continue;
1263 }
1264
1265 try {
1266 Class<?> clazz;
1267 try {
1268 clazz = classLoader.loadClass(resourceInfo.className);
1269 } catch (final ClassNotFoundException cnfe) { // custom classpath
1270 clazz = containerSystemContext.lookup(OPENEJB_RESOURCE_JNDI_PREFIX + resourceInfo.id).getClass();
1271 }
1272
1273 final boolean initialize = "true".equalsIgnoreCase(String.valueOf(resourceInfo.properties.remove("InitializeAfterDeployment")));
1274 final AnnotationFinder finder = Proxy.isProxyClass(clazz) ?
1275 null : new AnnotationFinder(new ClassesArchive(ancestors(clazz)));
1276 final List<Method> postConstructs = finder == null ?
1277 Collections.<Method>emptyList() : finder.findAnnotatedMethods(PostConstruct.class);
1278 final List<Method> preDestroys = finder == null ?
1279 Collections.<Method>emptyList() : finder.findAnnotatedMethods(PreDestroy.class);
1280
1281 resourceInfo.postConstructMethods = new ArrayList<>();
1282 resourceInfo.preDestroyMethods = new ArrayList<>();
1283
1284 addMethodsToResourceInfo(resourceInfo.postConstructMethods, PostConstruct.class, postConstructs);
1285 addMethodsToResourceInfo(resourceInfo.preDestroyMethods, PreDestroy.class, preDestroys);
1286
1287 CreationalContext<?> creationalContext = null;
1288 Object originalResource = null;
1289 if (!postConstructs.isEmpty() || initialize) {
1290 originalResource = containerSystemContext.lookup(OPENEJB_RESOURCE_JNDI_PREFIX + resourceInfo.id);
1291 Object resource = originalResource;
1292 if (resource instanceof Reference) {
1293 resource = unwrapReference(resource);
1294 this.bindResource(resourceInfo.id, resource, true);
1295 }
1296
1297 try {
1298 // wire up CDI
1299 if (appContext != null && appContext.getWebBeansContext() != null) {
1300 final BeanManagerImpl beanManager = appContext.getWebBeansContext().getBeanManagerImpl();
1301 if (beanManager.isInUse()) {
1302 creationalContext = beanManager.createCreationalContext(null);
1303 OWBInjector.inject(beanManager, resource, creationalContext);
1304 }
1305 }
1306
1307 if (!"none".equals(resourceInfo.postConstruct)) {
1308 if (resourceInfo.postConstruct != null) {
1309 final Method p = clazz.getDeclaredMethod(resourceInfo.postConstruct);
1310 if (!p.isAccessible()) {
1311 SetAccessible.on(p);
1312 }
1313 p.invoke(resource);
1314 }
1315
1316 for (final Method m : postConstructs) {
1317 if (!m.isAccessible()) {
1318 SetAccessible.on(m);
1319 }
1320 m.invoke(resource);
1321 }
1322 }
1323 } catch (final Exception e) {
1324 logger.fatal("Error calling @PostConstruct method on " + resource.getClass().getName());
1325 throw new OpenEJBException(e);
1326 }
1327 }
1328
1329 if (!"none".equals(resourceInfo.preDestroy)) {
1330 if (resourceInfo.preDestroy != null) {
1331 final Method p = clazz.getDeclaredMethod(resourceInfo.preDestroy);
1332 if (!p.isAccessible()) {
1333 SetAccessible.on(p);
1334 }
1335 preDestroys.add(p);
1336 }
1337
1338 if (!preDestroys.isEmpty() || creationalContext != null) {
1339 final String name = OPENEJB_RESOURCE_JNDI_PREFIX + resourceInfo.id;
1340 if (originalResource == null) {
1341 originalResource = containerSystemContext.lookup(name);
1342 }
1343
1344 this.bindResource(resourceInfo.id, new ResourceInstance(name, originalResource, preDestroys, creationalContext), true);
1345 }
1346 }
1347
1348 // log unused now for these resources now we built the resource completely and @PostConstruct can have used injected properties
1349 if (resourceInfo.unsetProperties != null && !isPassthroughType(resourceInfo)) {
1350 final Set<String> unsetKeys = resourceInfo.unsetProperties.stringPropertyNames();
1351 for (final String key : unsetKeys) { // don't use keySet to auto filter txMgr for instance and not real properties!
1352 unusedProperty(resourceInfo.id, logger, key);
1353 }
1354 }
1355 } catch (final Exception e) {
1356 logger.fatal("Error calling PostConstruct method on " + resourceInfo.id);
1357 logger.fatal("Resource " + resourceInfo.id + " could not be initialized. Application will be undeployed.");
1358 throw new OpenEJBException(e);
1359 }
1360 }
1361 } finally {
1362 thread.setContextClassLoader(oldCl);
1363 }
1364 }
1365
1366 private void addMethodsToResourceInfo(final List<String> list, final Class type, final List<Method> methodList) throws OpenEJBException {
1367 for (final Method method : methodList) {
1368 if (method.getParameterTypes().length > 0) {
1369 throw new OpenEJBException(type.getSimpleName() + " method " +
1370 method.getDeclaringClass().getName() + "."
1371 + method.getName() + " should have zero arguments");
1372 }
1373
1374 list.add(method.getName());
1375 }
1376 }
1377
1378 private static boolean isTemplatizedResource(final ResourceInfo resourceInfo) { // ~ container resource even if not 100% right
1379 return resourceInfo.className == null || resourceInfo.className.isEmpty();
1380 }
1381
1382 public static void mergeServices(final AppInfo appInfo) throws URISyntaxException {
1383 // used lazily by JaxWsServiceObjectFactory so merge both to keep same config
1384 // note: we could do the same for resources
1385 for (final ServiceInfo si : appInfo.services) {
1386 if (!appInfo.properties.containsKey(si.id)) {
1387 final Map<String, String> query = new HashMap<>();
1388 if (si.types != null && !si.types.isEmpty()) {
1389 query.put("type", si.types.iterator().next());
1390 }
1391 if (si.className != null) {
1392 query.put("class-name", si.className);
1393 }
1394 if (si.factoryMethod != null) {
1395 query.put("factory-name", si.factoryMethod);
1396 }
1397 if (si.constructorArgs != null && !si.constructorArgs.isEmpty()) {
1398 query.put("constructor", Join.join(",", si.constructorArgs));
1399 }
1400 appInfo.properties.put(si.id, "new://Service?" + URISupport.createQueryString(query));
1401 if (si.properties != null) {
1402 for (final String k : si.properties.stringPropertyNames()) {
1403 appInfo.properties.setProperty(si.id + "." + k, si.properties.getProperty(k));
1404 }
1405 }
1406 }
1407 }
1408 }
1409
1410 private static List<CommonInfoObject> listCommonInfoObjectsForAppInfo(final AppInfo appInfo) {
1411 final List<CommonInfoObject> vfs = new ArrayList<CommonInfoObject>(
1412 appInfo.clients.size() + appInfo.connectors.size() +
1413 appInfo.ejbJars.size() + appInfo.webApps.size());
1414 for (final ClientInfo clientInfo : appInfo.clients) {
1415 vfs.add(clientInfo);
1416 }
1417 for (final ConnectorInfo connectorInfo : appInfo.connectors) {
1418 vfs.add(connectorInfo);
1419 }
1420 for (final EjbJarInfo ejbJarInfo : appInfo.ejbJars) {
1421 vfs.add(ejbJarInfo);
1422 }
1423 for (final WebAppInfo webAppInfo : appInfo.webApps) {
1424 vfs.add(webAppInfo);
1425 }
1426 return vfs;
1427 }
1428
1429 public void bindGlobals(final Map<String, Object> bindings) throws NamingException {
1430 final Context containerSystemContext = containerSystem.getJNDIContext();
1431 for (final Entry<String, Object> value : bindings.entrySet()) {
1432 final String path = value.getKey();
1433 // keep only global bindings
1434 if (path.startsWith("module/") || path.startsWith("app/") || path.startsWith("comp/") || path.equalsIgnoreCase("global/dummy")) {
1435 continue;
1436 }
1437
1438 // a bit weird but just to be consistent if user doesn't lookup directly the resource
1439 final Context lastContext = Contexts.createSubcontexts(containerSystemContext, path);
1440 try {
1441 lastContext.rebind(path.substring(path.lastIndexOf("/") + 1, path.length()), value.getValue());
1442 } catch (final NameAlreadyBoundException nabe) {
1443 nabe.printStackTrace();
1444 }
1445 containerSystemContext.rebind(path, value.getValue());
1446 }
1447 }
1448
1449 private void propagateApplicationExceptions(final AppInfo appInfo, final ClassLoader classLoader, final List<BeanContext> allDeployments) {
1450 for (final BeanContext context : allDeployments) {
1451 if (BeanContext.Comp.class.equals(context.getBeanClass())) {
1452 continue;
1453 }
1454
1455 for (final EjbJarInfo jar : appInfo.ejbJars) {
1456 for (final ApplicationExceptionInfo exception : jar.applicationException) {
1457 try {
1458 final Class<?> exceptionClass = classLoader.loadClass(exception.exceptionClass);
1459 context.addApplicationException(exceptionClass, exception.rollback, exception.inherited);
1460 } catch (final Exception e) {
1461 // no-op: not a big deal since by jar config is respected, mainly means propagation didn't work because of classloader constraints
1462 }
1463 }
1464 }
1465 }
1466 }
1467
1468 private void resumePersistentSchedulers(final AppContext appContext) {
1469 try { // if quartz is missing
1470 final Scheduler globalScheduler = SystemInstance.get().getComponent(Scheduler.class);
1471 final Collection<Scheduler> schedulers = new ArrayList<Scheduler>();
1472 for (final BeanContext ejb : appContext.getBeanContexts()) {
1473 final Scheduler scheduler = ejb.get(Scheduler.class);
1474 if (scheduler == null || scheduler == globalScheduler || schedulers.contains(scheduler)) {
1475 continue;
1476 }
1477
1478 schedulers.add(scheduler);
1479 try {
1480 scheduler.resumeAll();
1481 } catch (final Exception e) {
1482 logger.warning("Can't resume scheduler for " + ejb.getEjbName(), e);
1483 }
1484 }
1485 } catch (final NoClassDefFoundError ncdfe) {
1486 // no-op
1487 }
1488 }
1489
1490 public List<BeanContext> initEjbs(final ClassLoader classLoader, final AppInfo appInfo, final AppContext appContext,
1491 final Set<Injection> injections, final List<BeanContext> allDeployments, final String webappId) throws OpenEJBException {
1492 final String globalTimersOn = SystemInstance.get().getProperty(OPENEJB_TIMERS_ON, "true");
1493
1494 final EjbJarBuilder ejbJarBuilder = new EjbJarBuilder(props, appContext);
1495 for (final EjbJarInfo ejbJar : appInfo.ejbJars) {
1496
1497 if (isSkip(appInfo, webappId, ejbJar)) {
1498 continue;
1499 }
1500
1501 final HashMap<String, BeanContext> deployments = ejbJarBuilder.build(ejbJar, injections, classLoader);
1502
1503 final JaccPermissionsBuilder jaccPermissionsBuilder = new JaccPermissionsBuilder();
1504 final PolicyContext policyContext = jaccPermissionsBuilder.build(ejbJar, deployments);
1505 jaccPermissionsBuilder.install(policyContext);
1506
1507 final TransactionPolicyFactory transactionPolicyFactory = createTransactionPolicyFactory(ejbJar, classLoader);
1508 for (final BeanContext beanContext : deployments.values()) {
1509 beanContext.setTransactionPolicyFactory(transactionPolicyFactory);
1510 }
1511
1512 final MethodTransactionBuilder methodTransactionBuilder = new MethodTransactionBuilder();
1513 methodTransactionBuilder.build(deployments, ejbJar.methodTransactions);
1514
1515 final MethodConcurrencyBuilder methodConcurrencyBuilder = new MethodConcurrencyBuilder();
1516 methodConcurrencyBuilder.build(deployments, ejbJar.methodConcurrency);
1517
1518 for (final BeanContext beanContext : deployments.values()) {
1519 containerSystem.addDeployment(beanContext);
1520 }
1521
1522 //bind ejbs into global jndi
1523 jndiBuilder.build(ejbJar, deployments);
1524
1525 // setup timers/asynchronous methods - must be after transaction attributes are set
1526 for (final BeanContext beanContext : deployments.values()) {
1527 if (beanContext.getComponentType() != BeanType.STATEFUL) {
1528 final Method ejbTimeout = beanContext.getEjbTimeout();
1529 boolean timerServiceRequired = false;
1530 if (ejbTimeout != null) {
1531 // If user set the tx attribute to RequiresNew change it to Required so a new transaction is not started
1532 if (beanContext.getTransactionType(ejbTimeout) == TransactionType.RequiresNew) {
1533 beanContext.setMethodTransactionAttribute(ejbTimeout, TransactionType.Required);
1534 }
1535 timerServiceRequired = true;
1536 }
1537 for (final Iterator<Map.Entry<Method, MethodContext>> it = beanContext.iteratorMethodContext(); it.hasNext(); ) {
1538 final Map.Entry<Method, MethodContext> entry = it.next();
1539 final MethodContext methodContext = entry.getValue();
1540 if (methodContext.getSchedules().size() > 0) {
1541 timerServiceRequired = true;
1542 final Method method = entry.getKey();
1543 //TODO Need ?
1544 if (beanContext.getTransactionType(method) == TransactionType.RequiresNew) {
1545 beanContext.setMethodTransactionAttribute(method, TransactionType.Required);
1546 }
1547 }
1548 }
1549
1550 if (timerServiceRequired && "true".equalsIgnoreCase(appInfo.properties.getProperty(OPENEJB_TIMERS_ON, globalTimersOn))) {
1551 // Create the timer
1552 final EjbTimerServiceImpl timerService = new EjbTimerServiceImpl(beanContext, newTimerStore(beanContext));
1553 //Load auto-start timers
1554 final TimerStore timerStore = timerService.getTimerStore();
1555 for (final Iterator<Map.Entry<Method, MethodContext>> it = beanContext.iteratorMethodContext(); it.hasNext(); ) {
1556 final Map.Entry<Method, MethodContext> entry = it.next();
1557 final MethodContext methodContext = entry.getValue();
1558 for (final ScheduleData scheduleData : methodContext.getSchedules()) {
1559 timerStore.createCalendarTimer(timerService,
1560 (String) beanContext.getDeploymentID(),
1561 null,
1562 entry.getKey(),
1563 scheduleData.getExpression(),
1564 scheduleData.getConfig(),
1565 true);
1566 }
1567 }
1568 beanContext.setEjbTimerService(timerService);
1569 } else {
1570 beanContext.setEjbTimerService(new NullEjbTimerServiceImpl());
1571 }
1572 }
1573 //set asynchronous methods transaction
1574 //TODO ???
1575 for (final Iterator<Entry<Method, MethodContext>> it = beanContext.iteratorMethodContext(); it.hasNext(); ) {
1576 final Entry<Method, MethodContext> entry = it.next();
1577 if (entry.getValue().isAsynchronous() && beanContext.getTransactionType(entry.getKey()) == TransactionType.RequiresNew) {
1578 beanContext.setMethodTransactionAttribute(entry.getKey(), TransactionType.Required);
1579 }
1580 }
1581
1582 // if local bean or mdb generate proxy class now to avoid bottleneck on classloader later
1583 if (beanContext.isLocalbean() && !beanContext.getComponentType().isMessageDriven() && !beanContext.isDynamicallyImplemented()) {
1584 final List<Class> interfaces = new ArrayList<Class>(3);
1585 interfaces.add(Serializable.class);
1586 interfaces.add(IntraVmProxy.class);
1587 final BeanType type = beanContext.getComponentType();
1588 if (BeanType.STATEFUL.equals(type) || BeanType.MANAGED.equals(type)) {
1589 interfaces.add(BeanContext.Removable.class);
1590 }
1591
1592 beanContext.set(
1593 BeanContext.ProxyClass.class,
1594 new BeanContext.ProxyClass(
1595 beanContext,
1596 interfaces.toArray(new Class<?>[interfaces.size()])
1597 ));
1598 }
1599 }
1600 // process application exceptions
1601 for (final ApplicationExceptionInfo exceptionInfo : ejbJar.applicationException) {
1602 try {
1603 final Class exceptionClass = classLoader.loadClass(exceptionInfo.exceptionClass);
1604 for (final BeanContext beanContext : deployments.values()) {
1605 beanContext.addApplicationException(exceptionClass, exceptionInfo.rollback, exceptionInfo.inherited);
1606 }
1607 } catch (final ClassNotFoundException e) {
1608 logger.error("createApplication.invalidClass", e, exceptionInfo.exceptionClass, e.getMessage());
1609 }
1610 }
1611
1612 allDeployments.addAll(deployments.values());
1613 }
1614
1615 final List<BeanContext> ejbs = sort(allDeployments);
1616 for (final BeanContext b : ejbs) { // otherwise for ears we have duplicated beans
1617 if (appContext.getBeanContexts().contains(b)) {
1618 continue;
1619 }
1620 appContext.getBeanContexts().add(b);
1621 }
1622 return ejbs;
1623 }
1624
1625 private boolean isSkip(final AppInfo appInfo, final String webappId, final EjbJarInfo ejbJar) {
1626 boolean skip = false;
1627 if (!appInfo.webAppAlone) {
1628 if (webappId == null) {
1629 skip = ejbJar.webapp; // we look for the lib part of the ear so deploy only if not a webapp
1630 } else if (!ejbJar.webapp
1631 || (!ejbJar.moduleId.equals(webappId) && !ejbJar.properties.getProperty("openejb.ejbmodule.webappId", "-").equals(webappId))) {
1632 skip = true; // we look for a particular webapp deployment so deploy only if this webapp
1633 }
1634 }
1635 return skip;
1636 }
1637
1638 private TimerStore newTimerStore(final BeanContext beanContext) {
1639 for (final DeploymentContext context : Arrays.asList(beanContext, beanContext.getModuleContext(), beanContext.getModuleContext().getAppContext())) {
1640 final String timerStoreClass = context.getProperties().getProperty(TIMER_STORE_CLASS);
1641 if (timerStoreClass != null) {
1642 logger.info("Found timer class: " + timerStoreClass);
1643
1644 try {
1645 final Class<?> clazz = beanContext.getClassLoader().loadClass(timerStoreClass);
1646 try {
1647 final Constructor<?> constructor = clazz.getConstructor(TransactionManager.class);
1648 return TimerStore.class.cast(constructor.newInstance(EjbTimerServiceImpl.getDefaultTransactionManager()));
1649 } catch (final Exception ignored) {
1650 return TimerStore.class.cast(clazz.newInstance());
1651 }
1652 } catch (final Exception e) {
1653 logger.error("Can't instantiate " + timerStoreClass + ", using default memory timer store");
1654 }
1655 }
1656 }
1657
1658 return new MemoryTimerStore(EjbTimerServiceImpl.getDefaultTransactionManager());
1659 }
1660
1661 public void startEjbs(final boolean start, final List<BeanContext> allDeployments) throws OpenEJBException {
1662 // now that everything is configured, deploy to the container
1663 if (start) {
1664 SystemInstance.get().fireEvent(new BeforeStartEjbs(allDeployments));
1665
1666 final Collection<BeanContext> toStart = new ArrayList<BeanContext>();
1667
1668 // deploy
1669 for (final BeanContext deployment : allDeployments) {
1670 try {
1671 final Container container = deployment.getContainer();
1672 if (container.getBeanContext(deployment.getDeploymentID()) == null) {
1673 container.deploy(deployment);
1674 if (!((String) deployment.getDeploymentID()).endsWith(".Comp")
1675 && !deployment.isHidden()) {
1676 logger.info("createApplication.createdEjb", deployment.getDeploymentID(), deployment.getEjbName(), container.getContainerID());
1677 }
1678 if (logger.isDebugEnabled()) {
1679 for (final Map.Entry<Object, Object> entry : deployment.getProperties().entrySet()) {
1680 logger.info("createApplication.createdEjb.property", deployment.getEjbName(), entry.getKey(), entry.getValue());
1681 }
1682 }
1683 toStart.add(deployment);
1684 }
1685 } catch (final Throwable t) {
1686 throw new OpenEJBException("Error deploying '" + deployment.getEjbName() + "'. Exception: " + t.getClass() + ": " + t.getMessage(), t);
1687 }
1688 }
1689
1690 // start
1691 for (final BeanContext deployment : toStart) {
1692 try {
1693 final Container container = deployment.getContainer();
1694 container.start(deployment);
1695 if (!((String) deployment.getDeploymentID()).endsWith(".Comp")
1696 && !deployment.isHidden()) {
1697 logger.info("createApplication.startedEjb", deployment.getDeploymentID(), deployment.getEjbName(), container.getContainerID());
1698 }
1699 } catch (final Throwable t) {
1700 throw new OpenEJBException("Error starting '" + deployment.getEjbName() + "'. Exception: " + t.getClass() + ": " + t.getMessage(), t);
1701 }
1702 }
1703 }
1704 }
1705
1706 @SuppressWarnings("unchecked")
1707 private void deployMBean(final WebBeansContext wc, final ClassLoader cl, final String mbeanClass, final Properties appMbeans, final String id) {
1708 if (LocalMBeanServer.isJMXActive()) {
1709 final Class<?> clazz;
1710 try {
1711 clazz = cl.loadClass(mbeanClass);
1712 } catch (final ClassNotFoundException e) {
1713 throw new OpenEJBRuntimeException(e);
1714 }
1715
1716 // cdi can be off so init with null bean in this case
1717 final Bean<?> bean;
1718 final BeanManager bm;
1719 if (wc == null) {
1720 bm = null;
1721 bean = null;
1722 } else {
1723 bm = wc.getBeanManagerImpl();
1724 final Set<Bean<?>> beans = bm.getBeans(clazz);
1725 bean = bm.resolve(beans);
1726 }
1727
1728 // create the MBean instance with cdi if possible or manually otherwise
1729 final Object instance;
1730 final CreationalContext creationalContext;
1731 if (bean == null) {
1732 try {
1733 instance = clazz.newInstance();
1734 } catch (final InstantiationException e) {
1735 logger.error("the mbean " + mbeanClass + " can't be registered because it can't be instantiated", e);
1736 return;
1737 } catch (final IllegalAccessException e) {
1738 logger.error("the mbean " + mbeanClass + " can't be registered because it can't be accessed", e);
1739 return;
1740 }
1741 creationalContext = null;
1742 } else {
1743 creationalContext = bm.createCreationalContext(bean);
1744 instance = bm.getReference(bean, clazz, creationalContext);
1745 }
1746
1747 final MBeanServer server = LocalMBeanServer.get();
1748 try {
1749 final MBean annotation = clazz.getAnnotation(MBean.class);
1750 final ObjectName leaf = annotation == null || annotation.objectName().isEmpty() ? new ObjectNameBuilder("openejb.user.mbeans")
1751 .set("application", id)
1752 .set("group", clazz.getPackage().getName())
1753 .set("name", clazz.getSimpleName())
1754 .build() : new ObjectName(annotation.objectName());
1755
1756 server.registerMBean(new DynamicMBeanWrapper(wc, instance), leaf);
1757 appMbeans.put(mbeanClass, leaf.getCanonicalName());
1758 if (creationalContext != null && (bean.getScope() == null || Dependent.class.equals(bean.getScope()))) {
1759 creationalContextForAppMbeans.put(leaf, creationalContext);
1760 }
1761 logger.info("Deployed MBean(" + leaf.getCanonicalName() + ")");
1762 } catch (final Exception e) {
1763 logger.error("the mbean " + mbeanClass + " can't be registered", e);
1764 }
1765 }
1766 }
1767
1768 private void ensureWebBeansContext(final AppContext appContext) {
1769 WebBeansContext webBeansContext = appContext.get(WebBeansContext.class);
1770 if (webBeansContext == null) {
1771 webBeansContext = appContext.getWebBeansContext();
1772 }else{
1773 if (null == appContext.getWebBeansContext()){
1774 appContext.setWebBeansContext(webBeansContext);
1775 }
1776 return;
1777 }
1778
1779 if (webBeansContext == null) {
1780
1781 final Map<Class<?>, Object> services = new HashMap<Class<?>, Object>();
1782
1783 services.put(JNDIService.class, new OpenEJBJndiService());
1784 services.put(AppContext.class, appContext);
1785 services.put(ScannerService.class, new CdiScanner());
1786 services.put(BeanArchiveService.class, new OpenEJBBeanInfoService());
1787 services.put(ELAdaptor.class, new CustomELAdapter(appContext));
1788 services.put(LoaderService.class, new OptimizedLoaderService(appContext.getProperties()));
1789
1790 final Properties properties = new Properties();
1791 properties.setProperty(org.apache.webbeans.spi.SecurityService.class.getName(), ManagedSecurityService.class.getName());
1792 properties.setProperty(ContextsService.class.getName(), CdiAppContextsService.class.getName());
1793 properties.setProperty(ResourceInjectionService.class.getName(), CdiResourceInjectionService.class.getName());
1794 properties.setProperty(TransactionService.class.getName(), OpenEJBTransactionService.class.getName());
1795
1796 webBeansContext = new WebBeansContext(services, properties);
1797
1798 appContext.setCdiEnabled(false);
1799 appContext.set(WebBeansContext.class, webBeansContext);
1800 appContext.setWebBeansContext(webBeansContext);
1801 }
1802 }
1803
1804 private TransactionPolicyFactory createTransactionPolicyFactory(final EjbJarInfo ejbJar, final ClassLoader classLoader) {
1805 TransactionPolicyFactory factory = null;
1806
1807 final Object value = ejbJar.properties.get(TransactionPolicyFactory.class.getName());
1808 if (value instanceof TransactionPolicyFactory) {
1809 factory = (TransactionPolicyFactory) value;
1810 } else if (value instanceof String) {
1811 try {
1812 final String[] parts = ((String) value).split(":", 2);
1813
1814 final ResourceFinder finder = new ResourceFinder("META-INF", classLoader);
1815 final Map<String, Class<? extends TransactionPolicyFactory>> plugins = finder.mapAvailableImplementations(TransactionPolicyFactory.class);
1816 final Class<? extends TransactionPolicyFactory> clazz = plugins.get(parts[0]);
1817 if (clazz != null) {
1818 if (parts.length == 1) {
1819 factory = clazz.getConstructor(String.class).newInstance(parts[1]);
1820 } else {
1821 factory = clazz.newInstance();
1822 }
1823 }
1824 } catch (final Exception ignored) {
1825 // couldn't determine the plugins, which isn't fatal
1826 }
1827 }
1828
1829 if (factory == null) {
1830 factory = new JtaTransactionPolicyFactory(transactionManager);
1831 }
1832 return factory;
1833 }
1834
1835 private static List<BeanContext> sort(List<BeanContext> deployments) {
1836 // Sort all the singletons to the back of the list. We want to make sure
1837 // all non-singletons are created first so that if a singleton refers to them
1838 // they are available.
1839 Collections.sort(deployments, new Comparator<BeanContext>() {
1840 @Override
1841 public int compare(final BeanContext a, final BeanContext b) {
1842 final int aa = a.getComponentType() == BeanType.SINGLETON ? 1 : 0;
1843 final int bb = b.getComponentType() == BeanType.SINGLETON ? 1 : 0;
1844 return aa - bb;
1845 }
1846 });
1847
1848 // Sort all the beans with references to the back of the list. Beans
1849 // without references to ther beans will be deployed first.
1850 deployments = References.sort(deployments, new References.Visitor<BeanContext>() {
1851 @Override
1852 public String getName(final BeanContext t) {
1853 return (String) t.getDeploymentID();
1854 }
1855
1856 @Override
1857 public Set<String> getReferences(final BeanContext t) {
1858 return t.getDependsOn();
1859 }
1860 });
1861
1862 // Now Sort all the MDBs to the back of the list. The Resource Adapter
1863 // may attempt to use the MDB on endpointActivation and the MDB may have
1864 // references to other ejbs that would need to be available first.
1865 Collections.sort(deployments, new Comparator<BeanContext>() {
1866 @Override
1867 public int compare(final BeanContext a, final BeanContext b) {
1868 final int aa = a.getComponentType() == BeanType.MESSAGE_DRIVEN ? 1 : 0;
1869 final int bb = b.getComponentType() == BeanType.MESSAGE_DRIVEN ? 1 : 0;
1870 return aa - bb;
1871 }
1872 });
1873
1874 return deployments;
1875 }
1876
1877 @Override
1878 public void destroy() {
1879
1880 final ReentrantLock l = lock;
1881 l.lock();
1882
1883 try {
1884 final SystemInstance systemInstance = SystemInstance.get();
1885 systemInstance.fireEvent(new ContainerSystemPreDestroy());
1886
1887 try {
1888 EjbTimerServiceImpl.shutdown();
1889 } catch (final Exception e) {
1890 logger.warning("Unable to shutdown scheduler", e);
1891 } catch (final NoClassDefFoundError ncdfe) {
1892 // no-op
1893 }
1894
1895 logger.debug("Undeploying Applications");
1896 final Assembler assembler = this;
1897 final List<AppInfo> deployedApps = new ArrayList<AppInfo>(assembler.getDeployedApplications());
1898 Collections.reverse(deployedApps); // if an app relies on the previous one it surely relies on it too at undeploy time
1899 for (final AppInfo appInfo : deployedApps) {
1900 try {
1901 assembler.destroyApplication(appInfo.path);
1902 } catch (final UndeployException e) {
1903 logger.error("Undeployment failed: " + appInfo.path, e);
1904 } catch (final NoSuchApplicationException e) {
1905 //Ignore
1906 }
1907 }
1908
1909 final Iterator<ObjectName> it = containerObjectNames.iterator();
1910 final MBeanServer server = LocalMBeanServer.get();
1911 while (it.hasNext()) {
1912 try {
1913 server.unregisterMBean(it.next());
1914 } catch (final Exception ignored) {
1915 // no-op
1916 }
1917 it.remove();
1918 }
1919 try {
1920 remoteResourceMonitor.unregister();
1921 } catch (final Exception ignored) {
1922 // no-op
1923 }
1924
1925 NamingEnumeration<Binding> namingEnumeration = null;
1926 try {
1927 namingEnumeration = containerSystem.getJNDIContext().listBindings("openejb/Resource");
1928 } catch (final NamingException ignored) {
1929 // no resource adapters were created
1930 }
1931 destroyResourceTree("", namingEnumeration);
1932
1933 try {
1934 containerSystem.getJNDIContext().unbind("java:global");
1935 } catch (final NamingException ignored) {
1936 // no-op
1937 }
1938
1939 systemInstance.removeComponent(OpenEjbConfiguration.class);
1940 systemInstance.removeComponent(JtaEntityManagerRegistry.class);
1941 systemInstance.removeComponent(TransactionSynchronizationRegistry.class);
1942 systemInstance.removeComponent(EjbResolver.class);
1943 systemInstance.fireEvent(new AssemblerDestroyed());
1944 systemInstance.removeObservers();
1945
1946 if (DestroyableResource.class.isInstance(this.securityService)) {
1947 DestroyableResource.class.cast(this.securityService).destroyResource();
1948 }
1949 if (DestroyableResource.class.isInstance(this.transactionManager)) {
1950 DestroyableResource.class.cast(this.transactionManager).destroyResource();
1951 }
1952
1953 for (final Container c : this.containerSystem.containers()) {
1954 if (DestroyableResource.class.isInstance(c)) { // TODO: should we use auto closeable there?
1955 DestroyableResource.class.cast(c).destroyResource();
1956 }
1957 }
1958
1959 SystemInstance.reset();
1960 } finally {
1961 l.unlock();
1962 }
1963 }
1964
1965 private Collection<DestroyingResource> destroyResourceTree(final String base, final NamingEnumeration<Binding> namingEnumeration) {
1966 final List<DestroyingResource> resources = new LinkedList<>();
1967 while (namingEnumeration != null && namingEnumeration.hasMoreElements()) {
1968 final Binding binding = namingEnumeration.nextElement();
1969 final Object object = binding.getObject();
1970 if (Context.class.isInstance(object)) {
1971 try {
1972 resources.addAll(destroyResourceTree(
1973 IvmContext.class.isInstance(object) ? IvmContext.class.cast(object).mynode.getAtomicName() : "",
1974 Context.class.cast(object).listBindings("")));
1975 } catch (final Exception ignored) {
1976 // no-op
1977 }
1978 } else {
1979 resources.add(new DestroyingResource((base == null || base.isEmpty() ? "" : (base + '/')) + binding.getName(), binding.getClassName(), object));
1980 }
1981 }
1982
1983 Collections.sort(resources, new Comparator<DestroyingResource>() { // end by destroying RA after having closed CF pool (for jms for instance)
1984 @Override
1985 public int compare(final DestroyingResource o1, final DestroyingResource o2) {
1986 final boolean ra1 = isRa(o1.instance);
1987 final boolean ra2 = isRa(o2.instance);
1988 if (ra2 && !ra1) {
1989 return -1;
1990 }
1991 if (ra1 && !ra2) {
1992 return 1;
1993 }
1994 // TODO: handle dependencies there too
1995 return o1.name.compareTo(o2.name);
1996 }
1997
1998 private boolean isRa(final Object instance) {
1999 return ResourceAdapter.class.isInstance(instance) || ResourceAdapterReference.class.isInstance(instance);
2000 }
2001 });
2002
2003 for (final DestroyingResource resource : resources) {
2004 try {
2005 destroyResource(resource.name, resource.clazz, resource.instance);
2006 } catch (final Throwable th) {
2007 logger.debug(th.getMessage(), th);
2008 }
2009 }
2010
2011 return resources;
2012 }
2013
2014 private void destroyResource(final String name, final String className, final Object inObject) {
2015 Object object;
2016 try {
2017 object = LazyResource.class.isInstance(inObject) && LazyResource.class.cast(inObject).isInitialized() ?
2018 LazyResource.class.cast(inObject).getObject() : inObject;
2019 } catch (final NamingException e) {
2020 object = inObject; // in case it impl DestroyableResource
2021 }
2022
2023 final Collection<Method> preDestroy = null;
2024
2025 if (resourceDestroyTimeout != null) {
2026 final Duration d = new Duration(resourceDestroyTimeout);
2027 final ExecutorService es = Executors.newSingleThreadExecutor(new DaemonThreadFactory("openejb-resource-destruction-" + name));
2028 final Object o = object;
2029 try {
2030 es.submit(new Runnable() {
2031 @Override
2032 public void run() {
2033 doResourceDestruction(name, className, o);
2034 }
2035 }).get(d.getTime(), d.getUnit());
2036 } catch (final InterruptedException e) {
2037 Thread.interrupted();
2038 } catch (final ExecutionException e) {
2039 throw RuntimeException.class.cast(e.getCause());
2040 } catch (final TimeoutException e) {
2041 logger.error("Can't destroy " + name + " in " + resourceDestroyTimeout + ", giving up.", e);
2042 if (threadStackOnTimeout) {
2043 final ThreadInfo[] dump = ManagementFactory.getThreadMXBean().dumpAllThreads(false, false);
2044 final ByteArrayOutputStream writer = new ByteArrayOutputStream();
2045 final PrintStream stream = new PrintStream(writer);
2046 for (final ThreadInfo info : dump) {
2047 stream.println('"' + info.getThreadName() + "\" suspended=" + info.isSuspended() + " state=" + info.getThreadState());
2048 for (final StackTraceElement traceElement : info.getStackTrace()) {
2049 stream.println("\tat " + traceElement);
2050 }
2051 }
2052 logger.info("Dump on " + name + " destruction timeout:\n" + new String(writer.toByteArray()));
2053 }
2054 }
2055 } else {
2056 doResourceDestruction(name, className, object);
2057 }
2058
2059 callPreDestroy(name, object);
2060 removeResourceInfo(name);
2061 }
2062
2063 private void callPreDestroy(final String name, final Object object) {
2064 if (object == null) {
2065 return;
2066 }
2067
2068 if (ResourceInstance.class.isInstance(object)) {
2069 ResourceInstance.class.cast(object).destroyResource();
2070 return;
2071 }
2072
2073 final Class<?> objectClass = object.getClass();
2074
2075 final ResourceInfo ri = findResourceInfo(name);
2076 if (ri == null) {
2077 return;
2078 }
2079
2080 final Set<String> destroyMethods = new HashSet<>();
2081 if (ri.preDestroy != null) {
2082 destroyMethods.add(ri.preDestroy);
2083 }
2084
2085 if (ri.preDestroyMethods != null && ri.preDestroyMethods.size() > 0) {
2086 destroyMethods.addAll(ri.preDestroyMethods);
2087 }
2088
2089 for (final String destroyMethod : destroyMethods) {
2090 try {
2091 final Method p = objectClass.getDeclaredMethod(destroyMethod);
2092 if (!p.isAccessible()) {
2093 SetAccessible.on(p);
2094 }
2095 p.invoke(object);
2096 } catch (Exception e) {
2097 logger.error("Unable to call pre destroy method " + destroyMethod + " on "
2098 + objectClass.getName() + ". Continuing with resource destruction.", e);
2099 }
2100 }
2101 }
2102
2103 private ResourceInfo findResourceInfo(String name) {
2104 List<ResourceInfo> resourceInfos = config.facilities.resources;
2105 for (final ResourceInfo resourceInfo : resourceInfos) {
2106 if (resourceInfo.id.equals(name)) {
2107 return resourceInfo;
2108 }
2109 }
2110
2111 return null;
2112 }
2113
2114 private void doResourceDestruction(final String name, final String className, final Object jndiObject) {
2115 final ResourceBeforeDestroyed event = new ResourceBeforeDestroyed(jndiObject, name);
2116 SystemInstance.get().fireEvent(event);
2117 final Object object = event.getReplacement() == null ? jndiObject : event.getReplacement();
2118 if (object instanceof ResourceAdapterReference) {
2119 final ResourceAdapterReference resourceAdapter = (ResourceAdapterReference) object;
2120 try {
2121 logger.info("Stopping ResourceAdapter: " + name);
2122
2123 if (logger.isDebugEnabled()) {
2124 logger.debug("Stopping ResourceAdapter: " + className);
2125 }
2126
2127 if (resourceAdapter.pool != null && ExecutorService.class.isInstance(resourceAdapter.pool)) {
2128 ExecutorService.class.cast(resourceAdapter.pool).shutdownNow();
2129 }
2130 resourceAdapter.ra.stop();
2131 } catch (final Throwable t) {
2132 logger.fatal("ResourceAdapter Shutdown Failed: " + name, t);
2133 }
2134 } else if (object instanceof ResourceAdapter) {
2135 final ResourceAdapter resourceAdapter = (ResourceAdapter) object;
2136 try {
2137 logger.info("Stopping ResourceAdapter: " + name);
2138
2139 if (logger.isDebugEnabled()) {
2140 logger.debug("Stopping ResourceAdapter: " + className);
2141 }
2142
2143 resourceAdapter.stop();
2144 } catch (final Throwable t) {
2145 logger.fatal("ResourceAdapter Shutdown Failed: " + name, t);
2146 }
2147 } else if (DataSourceFactory.knows(object)) {
2148 logger.info("Closing DataSource: " + name);
2149
2150 try {
2151 DataSourceFactory.destroy(object);
2152 } catch (final Throwable t) {
2153 //Ignore
2154 }
2155 } else if (object instanceof ConnectorReference) {
2156 final ConnectorReference cr = (ConnectorReference) object;
2157 try {
2158 final ConnectionManager cm = cr.getConnectionManager();
2159 if (cm != null && cm instanceof AbstractConnectionManager) {
2160 ((AbstractConnectionManager) cm).doStop();
2161 }
2162 } catch (final Exception e) {
2163 logger.debug("Not processing resource on destroy: " + className, e);
2164 }
2165 } else if (DestroyableResource.class.isInstance(object)) {
2166 try {
2167 DestroyableResource.class.cast(object).destroyResource();
2168 } catch (final RuntimeException e) {
2169 logger.error(e.getMessage(), e);
2170 }
2171 } else if (logger.isDebugEnabled() && !DataSource.class.isInstance(object)) {
2172 logger.debug("Not processing resource on destroy: " + className);
2173 }
2174 }
2175
2176 public ResourceInfo removeResourceInfo(final String name) {
2177 try {
2178 //Ensure ResourceInfo for this resource is removed
2179 final OpenEjbConfiguration configuration = SystemInstance.get().getComponent(OpenEjbConfiguration.class);
2180 final Iterator<ResourceInfo> iterator;
2181 if (configuration != null) {
2182 iterator = configuration.facilities.resources.iterator();
2183 }else{
2184 throw new Exception("OpenEjbConfiguration has not been initialized");
2185 }
2186 while (iterator.hasNext()) {
2187 final ResourceInfo info = iterator.next();
2188 if (name.equals(info.id)) {
2189 iterator.remove();
2190 return info;
2191 }
2192 }
2193 } catch (final Exception e) {
2194 logger.debug("Failed to purge resource on destroy: " + e.getMessage());
2195 }
2196
2197 return null;
2198 }
2199
2200 private static Object unwrapReference(final Object object) {
2201 Object o = object;
2202 while (o != null && Reference.class.isInstance(o)) {
2203 try {
2204 o = Reference.class.cast(o).getObject();
2205 } catch (final NamingException e) {
2206 // break
2207 }
2208 }
2209 if (o == null) {
2210 o = object;
2211 }
2212 return o;
2213 }
2214
2215 public void destroyApplication(final String filePath) throws UndeployException, NoSuchApplicationException {
2216
2217 final ReentrantLock l = lock;
2218 l.lock();
2219
2220 try {
2221 final AppInfo appInfo = deployedApplications.remove(filePath);
2222 if (appInfo == null) {
2223 throw new NoSuchApplicationException(filePath);
2224 }
2225 destroyApplication(appInfo);
2226 } finally {
2227 l.unlock();
2228 }
2229 }
2230
2231 public void destroyApplication(final AppContext appContext) throws UndeployException {
2232
2233 final ReentrantLock l = lock;
2234 l.lock();
2235
2236 try {
2237 final AppInfo appInfo = deployedApplications.remove(appContext.getId());
2238 if (appInfo == null) {
2239 throw new IllegalStateException(String.format("Cannot find AppInfo for app: %s", appContext.getId()));
2240 }
2241 destroyApplication(appInfo);
2242 } finally {
2243 l.unlock();
2244 }
2245 }
2246
2247 public void destroyApplication(final AppInfo appInfo) throws UndeployException {
2248
2249 final ReentrantLock l = lock;
2250 l.lock();
2251
2252 try {
2253 deployedApplications.remove(appInfo.path);
2254 logger.info("destroyApplication.start", appInfo.path);
2255
2256 final Context globalContext = containerSystem.getJNDIContext();
2257 final AppContext appContext = containerSystem.getAppContext(appInfo.appId);
2258 final ClassLoader classLoader = appContext.getClassLoader();
2259
2260 SystemInstance.get().fireEvent(new AssemblerBeforeApplicationDestroyed(appInfo, appContext));
2261
2262 //noinspection ConstantConditions
2263 if (null == appContext) {
2264 logger.warning("Application id '" + appInfo.appId + "' not found in: " + Arrays.toString(containerSystem.getAppContextKeys()));
2265 return;
2266 } else {
2267 final WebBeansContext webBeansContext = appContext.getWebBeansContext();
2268 if (webBeansContext != null) {
2269 final ClassLoader old = Thread.currentThread().getContextClassLoader();
2270 Thread.currentThread().setContextClassLoader(classLoader);
2271 try {
2272 final ServletContext context = appContext.isStandaloneModule() && appContext.getWebContexts().iterator().hasNext() ?
2273 appContext.getWebContexts().iterator().next().getServletContext() : null;
2274 webBeansContext.getService(ContainerLifecycle.class).stopApplication(context);
2275 } finally {
2276 Thread.currentThread().setContextClassLoader(old);
2277 }
2278 }
2279 final Map<String, Object> cb = appContext.getBindings();
2280 for (final Entry<String, Object> value : cb.entrySet()) {
2281 String path = value.getKey();
2282 if (path.startsWith("global")) {
2283 path = "java:" + path;
2284 }
2285 if (!path.startsWith("java:global")) {
2286 continue;
2287 }
2288
2289 if(IvmContext.class.isInstance(globalContext)) {
2290 IvmContext.class.cast(globalContext).setReadOnly(false);
2291 }
2292
2293 unbind(globalContext, path);
2294 unbind(globalContext, "openejb/global/" + path.substring("java:".length()));
2295 unbind(globalContext, path.substring("java:global".length()));
2296 }
2297 if (appInfo.appId != null && !appInfo.appId.isEmpty() && !"openejb".equals(appInfo.appId)) {
2298 unbind(globalContext, "global/" + appInfo.appId);
2299 unbind(globalContext, appInfo.appId);
2300 }
2301 }
2302
2303 final EjbResolver globalResolver = new EjbResolver(null, EjbResolver.Scope.GLOBAL);
2304 for (final AppInfo info : deployedApplications.values()) {
2305 globalResolver.addAll(info.ejbJars);
2306 }
2307 SystemInstance.get().setComponent(EjbResolver.class, globalResolver);
2308
2309 final UndeployException undeployException = new UndeployException(messages.format("destroyApplication.failed", appInfo.path));
2310
2311 final WebAppBuilder webAppBuilder = SystemInstance.get().getComponent(WebAppBuilder.class);
2312 if (webAppBuilder != null && !appInfo.webAppAlone) {
2313 try {
2314 webAppBuilder.undeployWebApps(appInfo);
2315 } catch (final Exception e) {
2316 undeployException.getCauses().add(new Exception("App: " + appInfo.path + ": " + e.getMessage(), e));
2317 }
2318 }
2319
2320 // get all of the ejb deployments
2321 List<BeanContext> deployments = new ArrayList<BeanContext>();
2322 for (final EjbJarInfo ejbJarInfo : appInfo.ejbJars) {
2323 for (final EnterpriseBeanInfo beanInfo : ejbJarInfo.enterpriseBeans) {
2324 final String deploymentId = beanInfo.ejbDeploymentId;
2325 final BeanContext beanContext = containerSystem.getBeanContext(deploymentId);
2326 if (beanContext == null) {
2327 undeployException.getCauses().add(new Exception("deployment not found: " + deploymentId));
2328 } else {
2329 deployments.add(beanContext);
2330 }
2331 }
2332 }
2333
2334 // Just as with startup we need to get things in an
2335 // order that respects the singleton @DependsOn information
2336 // Theoreticlly if a Singleton depends on something in its
2337 // @PostConstruct, it can depend on it in its @PreDestroy.
2338 // Therefore we want to make sure that if A dependsOn B,
2339 // that we destroy A first then B so that B will still be
2340 // usable in the @PreDestroy method of A.
2341
2342 // Sort them into the original starting order
2343 deployments = sort(deployments);
2344 // reverse that to get the stopping order
2345 Collections.reverse(deployments);
2346
2347 // stop
2348 for (final BeanContext deployment : deployments) {
2349 final String deploymentID = String.valueOf(deployment.getDeploymentID());
2350 try {
2351 final Container container = deployment.getContainer();
2352 container.stop(deployment);
2353 } catch (final Throwable t) {
2354 undeployException.getCauses().add(new Exception("bean: " + deploymentID + ": " + t.getMessage(), t));
2355 }
2356 }
2357
2358 // undeploy
2359 for (final BeanContext bean : deployments) {
2360 final String deploymentID = String.valueOf(bean.getDeploymentID());
2361 try {
2362 final Container container = bean.getContainer();
2363 container.undeploy(bean);
2364 bean.setContainer(null);
2365 } catch (final Throwable t) {
2366 undeployException.getCauses().add(new Exception("bean: " + deploymentID + ": " + t.getMessage(), t));
2367 } finally {
2368 bean.setDestroyed(true);
2369 }
2370 }
2371
2372 if (webAppBuilder != null && appInfo.webAppAlone) { // now that EJB are stopped we can undeploy webapps
2373 try {
2374 webAppBuilder.undeployWebApps(appInfo);
2375 } catch (final Exception e) {
2376 undeployException.getCauses().add(new Exception("App: " + appInfo.path + ": " + e.getMessage(), e));
2377 }
2378 }
2379
2380 // get the client ids
2381 final List<String> clientIds = new ArrayList<String>();
2382 for (final ClientInfo clientInfo : appInfo.clients) {
2383 clientIds.add(clientInfo.moduleId);
2384 for (final String className : clientInfo.localClients) {
2385 clientIds.add(className);
2386 }
2387 for (final String className : clientInfo.remoteClients) {
2388 clientIds.add(className);
2389 }
2390 }
2391
2392 for (final WebContext webContext : appContext.getWebContexts()) {
2393 containerSystem.removeWebContext(webContext);
2394 }
2395 TldScanner.forceCompleteClean(classLoader);
2396
2397 // Clear out naming for all components first
2398 for (final BeanContext deployment : deployments) {
2399 final String deploymentID = String.valueOf(deployment.getDeploymentID());
2400 try {
2401 containerSystem.removeBeanContext(deployment);
2402 } catch (final Throwable t) {
2403 undeployException.getCauses().add(new Exception(deploymentID, t));
2404 }
2405
2406 final JndiBuilder.Bindings bindings = deployment.get(JndiBuilder.Bindings.class);
2407 if (bindings != null) {
2408 for (final String name : bindings.getBindings()) {
2409 try {
2410 globalContext.unbind(name);
2411 } catch (final Throwable t) {
2412 undeployException.getCauses().add(new Exception("bean: " + deploymentID + ": " + t.getMessage(), t));
2413 }
2414 }
2415 }
2416 }
2417
2418 // stop this executor only now since @PreDestroy can trigger some stop events
2419 final AsynchronousPool pool = appContext.get(AsynchronousPool.class);
2420 if (pool != null) {
2421 pool.stop();
2422 }
2423
2424 for (final CommonInfoObject jar : listCommonInfoObjectsForAppInfo(appInfo)) {
2425 try {
2426 globalContext.unbind(VALIDATOR_FACTORY_NAMING_CONTEXT + jar.uniqueId);
2427 globalContext.unbind(VALIDATOR_NAMING_CONTEXT + jar.uniqueId);
2428 } catch (final NamingException e) {
2429 if (EjbJarInfo.class.isInstance(jar)) {
2430 undeployException.getCauses().add(new Exception("validator: " + jar.uniqueId + ": " + e.getMessage(), e));
2431 } // else an error but not that important
2432 }
2433 }
2434 try {
2435 if (globalContext instanceof IvmContext) {
2436 final IvmContext ivmContext = (IvmContext) globalContext;
2437 ivmContext.prune("openejb/Deployment");
2438 ivmContext.prune("openejb/local");
2439 ivmContext.prune("openejb/remote");
2440 ivmContext.prune("openejb/global");
2441 }
2442 } catch (final NamingException e) {
2443 undeployException.getCauses().add(new Exception("Unable to prune openejb/Deployments and openejb/local namespaces, this could cause future deployments to fail.",
2444 e));
2445 }
2446
2447 deployments.clear();
2448
2449 for (final String clientId : clientIds) {
2450 try {
2451 globalContext.unbind("/openejb/client/" + clientId);
2452 } catch (final Throwable t) {
2453 undeployException.getCauses().add(new Exception("client: " + clientId + ": " + t.getMessage(), t));
2454 }
2455 }
2456
2457 // mbeans
2458 final MBeanServer server = LocalMBeanServer.get();
2459 for (final Object objectName : appInfo.jmx.values()) {
2460 try {
2461 final ObjectName on = new ObjectName((String) objectName);
2462 if (server.isRegistered(on)) {
2463 server.unregisterMBean(on);
2464 }
2465 final CreationalContext cc = creationalContextForAppMbeans.remove(on);
2466 if (cc != null) {
2467 cc.release();
2468 }
2469 } catch (final InstanceNotFoundException e) {
2470 logger.warning("can't unregister " + objectName + " because the mbean was not found", e);
2471 } catch (final MBeanRegistrationException e) {
2472 logger.warning("can't unregister " + objectName, e);
2473 } catch (final MalformedObjectNameException mone) {
2474 logger.warning("can't unregister because the ObjectName is malformed: " + objectName, mone);
2475 }
2476 }
2477
2478 // destroy PUs before resources since the JPA provider can use datasources
2479 for (final PersistenceUnitInfo unitInfo : appInfo.persistenceUnits) {
2480 try {
2481 final Object object = globalContext.lookup(PERSISTENCE_UNIT_NAMING_CONTEXT + unitInfo.id);
2482 globalContext.unbind(PERSISTENCE_UNIT_NAMING_CONTEXT + unitInfo.id);
2483
2484 // close EMF so all resources are released
2485 final ReloadableEntityManagerFactory remf = (ReloadableEntityManagerFactory) object;
2486 remf.close();
2487 persistenceClassLoaderHandler.destroy(unitInfo.id);
2488 remf.unregister();
2489 } catch (final Throwable t) {
2490 undeployException.getCauses().add(new Exception("persistence-unit: " + unitInfo.id + ": " + t.getMessage(), t));
2491 }
2492 }
2493
2494 for (final String id : appInfo.resourceAliases) {
2495 final String name = OPENEJB_RESOURCE_JNDI_PREFIX + id;
2496 ContextualJndiReference.followReference.set(false);
2497 try {
2498 final Object object;
2499 try {
2500 object = globalContext.lookup(name);
2501 } finally {
2502 ContextualJndiReference.followReference.remove();
2503 }
2504 if (object instanceof ContextualJndiReference) {
2505 final ContextualJndiReference contextualJndiReference = ContextualJndiReference.class.cast(object);
2506 contextualJndiReference.removePrefix(appContext.getId());
2507 if (contextualJndiReference.hasNoMorePrefix()) {
2508 globalContext.unbind(name);
2509 } // else not the last deployed application to use this resource so keep it
2510 } else {
2511 globalContext.unbind(name);
2512 }
2513 } catch (final NamingException e) {
2514 logger.warning("can't unbind resource '{0}'", id);
2515 }
2516 }
2517 for (final String id : appInfo.resourceIds) {
2518 final String name = OPENEJB_RESOURCE_JNDI_PREFIX + id;
2519 try {
2520 destroyLookedUpResource(globalContext, id, name);
2521 } catch (final NamingException e) {
2522 logger.warning("can't unbind resource '{0}'", id);
2523 }
2524 }
2525 for (final ConnectorInfo connector : appInfo.connectors) {
2526 if (connector.resourceAdapter == null || connector.resourceAdapter.id == null) {
2527 continue;
2528 }
2529
2530 final String name = OPENEJB_RESOURCE_JNDI_PREFIX + connector.resourceAdapter.id;
2531 try {
2532 destroyLookedUpResource(globalContext, connector.resourceAdapter.id, name);
2533 } catch (final NamingException e) {
2534 logger.warning("can't unbind resource '{0}'", connector);
2535 }
2536
2537 for (final ResourceInfo outbound : connector.outbound) {
2538 try {
2539 destroyLookedUpResource(globalContext, outbound.id, OPENEJB_RESOURCE_JNDI_PREFIX + outbound.id);
2540 } catch (final Exception e) {
2541 // no-op
2542 }
2543 }
2544 for (final ResourceInfo outbound : connector.adminObject) {
2545 try {
2546 destroyLookedUpResource(globalContext, outbound.id, OPENEJB_RESOURCE_JNDI_PREFIX + outbound.id);
2547 } catch (final Exception e) {
2548 // no-op
2549 }
2550 }
2551 for (final MdbContainerInfo container : connector.inbound) {
2552 try {
2553 containerSystem.removeContainer(container.id);
2554 config.containerSystem.containers.remove(container);
2555 this.containerSystem.getJNDIContext().unbind(JAVA_OPENEJB_NAMING_CONTEXT + container.service + "/" + container.id);
2556 } catch (final Exception e) {
2557 // no-op
2558 }
2559 }
2560 }
2561
2562 for (final ContainerInfo containerInfo : appInfo.containers) {
2563 removeContainer(containerInfo.id);
2564 }
2565
2566 containerSystem.removeAppContext(appInfo.appId);
2567
2568 if (!appInfo.properties.containsKey("tomee.destroying")) { // destroy tomee classloader after resources cleanup
2569 try {
2570 final Method m = classLoader.getClass().getMethod("internalStop");
2571 m.invoke(classLoader);
2572 } catch (final NoSuchMethodException nsme) {
2573 // no-op
2574 } catch (final Exception e) {
2575 logger.error("error stopping classloader of webapp " + appInfo.appId, e);
2576 }
2577 ClassLoaderUtil.cleanOpenJPACache(classLoader);
2578 }
2579 ClassLoaderUtil.destroyClassLoader(appInfo.appId, appInfo.path);
2580
2581 if (undeployException.getCauses().size() > 0) {
2582 // logging causes here otherwise it will be eaten in later logs.
2583 for (Throwable cause : undeployException.getCauses()) {
2584 logger.error("undeployException original cause", cause);
2585 }
2586 throw undeployException;
2587 }
2588
2589 logger.debug("destroyApplication.success", appInfo.path);
2590 } finally {
2591 l.unlock();
2592 }
2593 }
2594
2595 private void destroyLookedUpResource(final Context globalContext, final String id, final String name) throws NamingException {
2596
2597 final Object object;
2598
2599 try {
2600 object = globalContext.lookup(name);
2601 } catch (final NamingException e) {
2602 // if we catch a NamingException, check to see if the resource is a LaztObjectReference that has not been initialized correctly
2603 final String ctx = name.substring(0, name.lastIndexOf("/"));
2604 final String objName = name.substring(ctx.length() + 1);
2605 final NamingEnumeration<Binding> bindings = globalContext.listBindings(ctx);
2606 while (bindings.hasMoreElements()) {
2607 final Binding binding = bindings.nextElement();
2608 if (!binding.getName().equals(objName)) {
2609 continue;
2610 }
2611
2612 if (!LazyObjectReference.class.isInstance(binding.getObject())) {
2613 continue;
2614 }
2615
2616 final LazyObjectReference<?> ref = LazyObjectReference.class.cast(binding.getObject());
2617 if (! ref.isInitialized()) {
2618 globalContext.unbind(name);
2619 removeResourceInfo(name);
2620 return;
2621 }
2622 }
2623
2624 throw e;
2625 }
2626
2627 final String clazz;
2628 if (object == null) { // should it be possible?
2629 clazz = "?";
2630 } else {
2631 clazz = object.getClass().getName();
2632 }
2633 destroyResource(id, clazz, object);
2634 globalContext.unbind(name);
2635 }
2636
2637 private void unbind(final Context context, final String name) {
2638 try {
2639 context.unbind(name);
2640 } catch (final NamingException e) {
2641 // no-op
2642 }
2643 }
2644
2645 public ClassLoader createAppClassLoader(final AppInfo appInfo) throws OpenEJBException, IOException {
2646 if ("openejb".equals(appInfo.appId)) {
2647 return ParentClassLoaderFinder.Helper.get();
2648 }
2649
2650 final Set<URL> jars = new HashSet<>();
2651 for (final EjbJarInfo info : appInfo.ejbJars) {
2652 if (info.path != null) {
2653 jars.add(toUrl(info.path));
2654 }
2655 }
2656 for (final ClientInfo info : appInfo.clients) {
2657 if (info.path != null) {
2658 jars.add(toUrl(info.path));
2659 }
2660 }
2661 for (final ConnectorInfo info : appInfo.connectors) {
2662 for (final String jarPath : info.libs) {
2663 jars.add(toUrl(jarPath));
2664 }
2665 }
2666 for (final String jarPath : appInfo.libs) {
2667 jars.add(toUrl(jarPath));
2668 }
2669
2670 // add openejb-jpa-integration if the jpa provider is in lib/
2671 if (appInfo.libs.size() > 0) { // the test could be enhanced
2672 try {
2673 final File jpaIntegrationFile = JarLocation.jarLocation(MakeTxLookup.class);
2674 final URL url = jpaIntegrationFile.toURI().toURL();
2675 if (!jars.contains(url)) { // could have been done before (webapp enrichment or manually for instance)
2676 jars.add(url);
2677 }
2678 } catch (final RuntimeException re) {
2679 logger.warning("Unable to find the open-jpa-integration jar");
2680 }
2681 }
2682 final ClassLoaderEnricher component = SystemInstance.get().getComponent(ClassLoaderEnricher.class);
2683 if (component != null) {
2684 jars.addAll(Arrays.asList(component.applicationEnrichment()));
2685 }else {
2686 logger.warning("Unable to find open-jpa-integration jar");
2687 }
2688
2689 // Create the class loader
2690 final ClassLoader parent = ParentClassLoaderFinder.Helper.get();
2691
2692 final String prefix;
2693 if (appInfo.webAppAlone) {
2694 prefix = "WEB-INF/";
2695 } else {
2696 prefix = "META-INF/";
2697 }
2698 final ClassLoaderConfigurer configurer1 = QuickJarsTxtParser.parse(new File(appInfo.path, prefix + QuickJarsTxtParser.FILE_NAME));
2699 final ClassLoaderConfigurer configurer2 = ClassLoaderUtil.configurer(appInfo.appId);
2700
2701 if (configurer1 != null || configurer2 != null) {
2702 final ClassLoaderConfigurer configurer = new CompositeClassLoaderConfigurer(configurer1, configurer2);
2703 ClassLoaderConfigurer.Helper.configure(jars, configurer);
2704 }
2705
2706 final URL[] filtered = jars.toArray(new URL[jars.size()]);
2707
2708 // some lib (DS for instance) rely on AppClassLoader for CDI bean manager usage (common for tests cases where you
2709 // try to get the app BM from the AppClassLoader having stored it in a map).
2710 // since we don't really need to create a classloader here when starting from classpath just let skip this step
2711 if (skipLoaderIfPossible) { // TODO: maybe use a boolean to know if all urls comes from the classpath to avoid this validation
2712 if ("classpath.ear".equals(appInfo.appId)) {
2713 return parent;
2714 }
2715
2716 final Collection<File> urls = new HashSet<>();
2717 for (final URL url : ClassLoaders.findUrls(parent)) { // need to convert it to file since urls can be file:/xxx or jar:file:///xxx
2718 try {
2719 urls.add(URLs.toFile(url).getCanonicalFile());
2720 } catch (final Exception error) {
2721 if (logger.isDebugEnabled()) {
2722 logger.debug("Can't determine url for: " + url.toExternalForm(), error);
2723 }
2724 }
2725 }
2726
2727 boolean allIsIntheClasspath = true;
2728 for (final URL url : filtered) {
2729 try {
2730 if (!urls.contains(URLs.toFile(url).getCanonicalFile())) {
2731 allIsIntheClasspath = false;
2732 if (logger.isDebugEnabled()) {
2733 logger.debug(url.toExternalForm() + " (" + URLs.toFile(url)
2734 + ") is not in the classloader so we'll create a dedicated classloader for this app");
2735 }
2736 break;
2737 }
2738 } catch (final Exception ignored) {
2739 allIsIntheClasspath = false;
2740 if (logger.isDebugEnabled()) {
2741 logger.debug(url.toExternalForm() + " (" + URLs.toFile(url) + ") is not in the classloader", ignored);
2742 }
2743 break;
2744 }
2745 }
2746
2747 if (allIsIntheClasspath) {
2748 logger.info("Not creating another application classloader for " + appInfo.appId);
2749 return parent;
2750 } else if (logger.isDebugEnabled()) {
2751 logger.debug("Logging all urls from the app since we don't skip the app classloader creation:");
2752 for (final URL url : filtered) {
2753 logger.debug(" -> " + url.toExternalForm());
2754 }
2755 logger.debug("Logging all urls from the classloader since we don't skip the app classloader creation:");
2756 for (final File url : urls) {
2757 logger.debug(" -> " + url.getAbsolutePath());
2758 }
2759 }
2760 }
2761
2762 logger.info("Creating dedicated application classloader for " + appInfo.appId);
2763
2764 if (!appInfo.delegateFirst) {
2765 return ClassLoaderUtil.createClassLoader(appInfo.path, filtered, parent);
2766 }
2767 return ClassLoaderUtil.createClassLoaderFirst(appInfo.path, filtered, parent);
2768 }
2769
2770 public void createExternalContext(final JndiContextInfo contextInfo) throws OpenEJBException {
2771 logger.getChildLogger("service").info("createService", contextInfo.service, contextInfo.id, contextInfo.className);
2772
2773 final InitialContext initialContext;
2774 try {
2775 initialContext = new InitialContext(contextInfo.properties);
2776 } catch (final NamingException ne) {
2777 throw new OpenEJBException(String.format("JndiProvider(id=\"%s\") could not be created. Failed to create the InitialContext using the supplied properties",
2778 contextInfo.id), ne);
2779 }
2780
2781 try {
2782 containerSystem.getJNDIContext().bind("openejb/remote_jndi_contexts/" + contextInfo.id, initialContext);
2783 } catch (final NamingException e) {
2784 throw new OpenEJBException("Cannot bind " + contextInfo.service + " with id " + contextInfo.id, e);
2785 }
2786
2787 // Update the config tree
2788 config.facilities.remoteJndiContexts.add(contextInfo);
2789
2790 logger.getChildLogger("service").debug("createService.success", contextInfo.service, contextInfo.id, contextInfo.className);
2791 }
2792
2793 public void createContainer(final ContainerInfo serviceInfo) throws OpenEJBException {
2794
2795 final ObjectRecipe serviceRecipe = createRecipe(Collections.<ServiceInfo>emptyList(), serviceInfo);
2796
2797 serviceRecipe.setProperty("id", serviceInfo.id);
2798 serviceRecipe.setProperty("transactionManager", props.get(TransactionManager.class.getName()));
2799 serviceRecipe.setProperty("securityService", props.get(SecurityService.class.getName