001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.geronimo.openejb.deployment;
018
019 import java.io.File;
020 import java.io.IOException;
021 import java.net.URI;
022 import java.net.URL;
023 import java.util.Collection;
024 import java.util.Collections;
025 import java.util.HashMap;
026 import java.util.Iterator;
027 import java.util.LinkedHashSet;
028 import java.util.LinkedList;
029 import java.util.Map;
030 import java.util.Properties;
031 import java.util.Set;
032 import java.util.TreeMap;
033 import java.util.TreeSet;
034 import java.util.jar.JarFile;
035
036 import javax.ejb.EntityContext;
037 import javax.ejb.MessageDrivenContext;
038 import javax.ejb.SessionContext;
039 import javax.ejb.TimerService;
040 import javax.xml.namespace.QName;
041 import javax.xml.ws.WebServiceContext;
042
043 import org.apache.commons.logging.Log;
044 import org.apache.commons.logging.LogFactory;
045 import org.apache.geronimo.common.DeploymentException;
046 import org.apache.geronimo.connector.ResourceAdapterWrapperGBean;
047 import org.apache.geronimo.deployment.ClassPathList;
048 import org.apache.geronimo.deployment.ModuleIDBuilder;
049 import org.apache.geronimo.deployment.ModuleList;
050 import org.apache.geronimo.deployment.NamespaceDrivenBuilder;
051 import org.apache.geronimo.deployment.NamespaceDrivenBuilderCollection;
052 import org.apache.geronimo.deployment.service.EnvironmentBuilder;
053 import org.apache.geronimo.deployment.service.GBeanBuilder;
054 import org.apache.geronimo.deployment.util.DeploymentUtil;
055 import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
056 import org.apache.geronimo.gbean.AbstractName;
057 import org.apache.geronimo.gbean.AbstractNameQuery;
058 import org.apache.geronimo.gbean.GBeanData;
059 import org.apache.geronimo.gbean.GBeanInfo;
060 import org.apache.geronimo.gbean.GBeanInfoBuilder;
061 import org.apache.geronimo.gbean.ReferencePatterns;
062 import org.apache.geronimo.gbean.GBeanLifecycle;
063 import org.apache.geronimo.j2ee.deployment.EARContext;
064 import org.apache.geronimo.j2ee.deployment.Module;
065 import org.apache.geronimo.j2ee.deployment.ModuleBuilder;
066 import org.apache.geronimo.j2ee.deployment.ModuleBuilderExtension;
067 import org.apache.geronimo.j2ee.deployment.NamingBuilder;
068 import org.apache.geronimo.j2ee.deployment.annotation.AnnotatedEjbJar;
069 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
070 import org.apache.geronimo.kernel.GBeanNotFoundException;
071 import org.apache.geronimo.kernel.Naming;
072 import org.apache.geronimo.kernel.classloader.TemporaryClassLoader;
073 import org.apache.geronimo.kernel.config.Configuration;
074 import org.apache.geronimo.kernel.config.ConfigurationModuleType;
075 import org.apache.geronimo.kernel.config.ConfigurationStore;
076 import org.apache.geronimo.kernel.repository.Artifact;
077 import org.apache.geronimo.kernel.repository.Environment;
078 import org.apache.geronimo.naming.deployment.ResourceEnvironmentSetter;
079 import org.apache.geronimo.openejb.EjbContainer;
080 import org.apache.geronimo.openejb.EjbDeployment;
081 import org.apache.geronimo.openejb.EjbModuleImplGBean;
082 import org.apache.geronimo.openejb.OpenEjbSystem;
083 import org.apache.geronimo.openejb.xbeans.ejbjar.OpenejbGeronimoEjbJarType;
084 import org.apache.geronimo.security.jacc.ComponentPermissions;
085 import org.apache.geronimo.xbeans.geronimo.j2ee.GerSecurityDocument;
086 import org.apache.geronimo.xbeans.javaee.EjbJarType;
087 import org.apache.geronimo.persistence.PersistenceUnitGBean;
088 import org.apache.openejb.OpenEJBException;
089 import org.apache.openejb.util.LinkResolver;
090 import org.apache.openejb.assembler.classic.AppInfo;
091 import org.apache.openejb.assembler.classic.CmpJarBuilder;
092 import org.apache.openejb.assembler.classic.ContainerInfo;
093 import org.apache.openejb.assembler.classic.ContainerSystemInfo;
094 import org.apache.openejb.assembler.classic.EjbJarInfo;
095 import org.apache.openejb.assembler.classic.EnterpriseBeanInfo;
096 import org.apache.openejb.assembler.classic.FacilitiesInfo;
097 import org.apache.openejb.assembler.classic.MdbContainerInfo;
098 import org.apache.openejb.assembler.classic.MessageDrivenBeanInfo;
099 import org.apache.openejb.assembler.classic.OpenEjbConfiguration;
100 import org.apache.openejb.assembler.classic.StatefulBeanInfo;
101 import org.apache.openejb.assembler.classic.PersistenceContextReferenceInfo;
102 import org.apache.openejb.util.UniqueDefaultLinkResolver;
103 import org.apache.openejb.config.AppModule;
104 import org.apache.openejb.config.ConfigurationFactory;
105 import org.apache.openejb.config.DeploymentLoader;
106 import org.apache.openejb.config.ReadDescriptors;
107 import org.apache.openejb.config.UnknownModuleTypeException;
108 import org.apache.openejb.config.UnsupportedModuleTypeException;
109 import org.apache.openejb.config.ValidationError;
110 import org.apache.openejb.config.ValidationFailedException;
111 import org.apache.openejb.config.ValidationFailure;
112 import org.apache.openejb.jee.EjbJar;
113 import org.apache.openejb.jee.EjbRef;
114 import org.apache.openejb.jee.EnterpriseBean;
115 import org.apache.openejb.jee.MessageDestinationRef;
116 import org.apache.openejb.jee.PersistenceContextRef;
117 import org.apache.openejb.jee.PersistenceUnitRef;
118 import org.apache.openejb.jee.ResourceEnvRef;
119 import org.apache.openejb.jee.ResourceRef;
120 import org.apache.openejb.jee.ServiceRef;
121 import org.apache.openejb.jee.jpa.unit.Persistence;
122 import org.apache.openejb.jee.jpa.unit.PersistenceUnit;
123 import org.apache.openejb.jee.jpa.unit.TransactionType;
124 import org.apache.openejb.jee.oejb2.EjbRefType;
125 import org.apache.openejb.jee.oejb2.GeronimoEjbJarType;
126 import org.apache.openejb.jee.oejb2.MessageDrivenBeanType;
127 import org.apache.openejb.jee.oejb2.OpenejbJarType;
128 import org.apache.openejb.jee.oejb2.PatternType;
129 import org.apache.openejb.jee.oejb2.ResourceLocatorType;
130 import org.apache.openejb.loader.SystemInstance;
131 import org.apache.xmlbeans.XmlCursor;
132 import org.apache.xmlbeans.XmlObject;
133
134 /**
135 * Master builder for processing EJB JAR deployments and creating the
136 * correspinding runtime objects (GBeans, etc.).
137 *
138 * @version $Revision: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
139 */
140 public class EjbModuleBuilder implements ModuleBuilder, GBeanLifecycle {
141 private static final Log log = LogFactory.getLog(EjbModuleBuilder.class);
142
143 private static final String OPENEJBJAR_NAMESPACE = XmlUtil.OPENEJBJAR_QNAME.getNamespaceURI();
144 private static final Map<String, String> NAMESPACE_UPDATES = new HashMap<String, String>();
145 static {
146 NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/openejb-jar", "http://openejb.apache.org/xml/ns/openejb-jar-2.3");
147 NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/openejb-jar-2.1", "http://openejb.apache.org/xml/ns/openejb-jar-2.3");
148 NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/openejb-jar-2.2", "http://openejb.apache.org/xml/ns/openejb-jar-2.3");
149 NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/openejb-jar-2.3", "http://openejb.apache.org/xml/ns/openejb-jar-2.3");
150 NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/pkgen", "http://openejb.apache.org/xml/ns/pkgen-2.1");
151 NAMESPACE_UPDATES.put("http://www.openejb.org/xml/ns/pkgen-2.0", "http://openejb.apache.org/xml/ns/pkgen-2.1");
152 }
153
154 private final Environment defaultEnvironment;
155 private final String defaultCmpJTADataSource;
156 private final String defaultCmpNonJTADataSource;
157 private final NamespaceDrivenBuilderCollection securityBuilders;
158 private final NamespaceDrivenBuilderCollection serviceBuilders;
159 private final NamingBuilder namingBuilder;
160 private final ResourceEnvironmentSetter resourceEnvironmentSetter;
161 private final Collection<ModuleBuilderExtension> moduleBuilderExtensions;
162
163 public EjbModuleBuilder(Environment defaultEnvironment,
164
165 String defaultCmpJTADataSource, String defaultCmpNonJTADataSource,
166 Collection<ModuleBuilderExtension> moduleBuilderExtensions,
167 Collection securityBuilders,
168 Collection serviceBuilders,
169 NamingBuilder namingBuilders,
170 ResourceEnvironmentSetter resourceEnvironmentSetter) {
171
172 this.defaultEnvironment = defaultEnvironment;
173 this.defaultCmpJTADataSource = defaultCmpJTADataSource;
174 this.defaultCmpNonJTADataSource = defaultCmpNonJTADataSource;
175 this.securityBuilders = new NamespaceDrivenBuilderCollection(securityBuilders, GerSecurityDocument.type.getDocumentElementName());
176 this.serviceBuilders = new NamespaceDrivenBuilderCollection(serviceBuilders, GBeanBuilder.SERVICE_QNAME);
177 this.namingBuilder = namingBuilders;
178 this.resourceEnvironmentSetter = resourceEnvironmentSetter;
179
180 if (moduleBuilderExtensions == null) {
181 moduleBuilderExtensions = Collections.emptyList();
182 }
183 this.moduleBuilderExtensions = moduleBuilderExtensions;
184
185 //duplicate of stuff in OpenEjbSystemGBean, may not be essential
186 System.setProperty("duct tape", "");
187 System.setProperty("admin.disabled", "true");
188 System.setProperty("openejb.logger.external", "true");
189
190 setDefaultProperty("openejb.deploymentId.format", "{moduleId}/{ejbName}");
191 setDefaultProperty("openejb.jndiname.strategy.class", "org.apache.openejb.assembler.classic.JndiBuilder$TemplatedStrategy");
192 setDefaultProperty("openejb.jndiname.format", "{ejbName}{interfaceType.annotationName}");
193 setDefaultProperty("openejb.jndiname.failoncollision", "false");
194
195 System.setProperty("openejb.naming", "xbean");
196
197 }
198
199 public void doStart() throws Exception {
200 XmlBeansUtil.registerNamespaceUpdates(NAMESPACE_UPDATES);
201 }
202
203 public void doStop() {
204 XmlBeansUtil.unregisterNamespaceUpdates(NAMESPACE_UPDATES);
205 }
206
207 public void doFail() {
208 doStop();
209 }
210
211 private void setDefaultProperty(String key, String value) {
212 SystemInstance systemInstance = SystemInstance.get();
213 String format = systemInstance.getProperty(key);
214 if (format == null) {
215 systemInstance.setProperty(key, value);
216 }
217 }
218
219
220 public String getSchemaNamespace() {
221 return EjbModuleBuilder.OPENEJBJAR_NAMESPACE;
222 }
223
224 public Module createModule(File plan, JarFile moduleFile, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException {
225 return createModule(plan, moduleFile, "ejb.jar", null, null, null, naming, idBuilder);
226 }
227
228 public Module createModule(Object plan, JarFile moduleFile, String targetPath, URL specDDUrl, Environment environment, Object moduleContextInfo, AbstractName earName, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException {
229 return createModule(plan, moduleFile, targetPath, specDDUrl, environment, earName, naming, idBuilder);
230 }
231
232 private Module createModule(Object plan, JarFile moduleFile, String targetPath, URL specDDUrl, Environment earEnvironment, AbstractName earName, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException {
233 if (moduleFile == null) throw new NullPointerException("moduleFile is null");
234 if (targetPath == null) throw new NullPointerException("targetPath is null");
235 if (targetPath.endsWith("/")) throw new IllegalArgumentException("targetPath must not end with a '/'");
236
237 // Load the module file
238 DeploymentLoader loader = new DeploymentLoader();
239 AppModule appModule;
240 try {
241 appModule = loader.load(new File(moduleFile.getName()));
242 } catch (UnknownModuleTypeException e) {
243 return null;
244 } catch (UnsupportedModuleTypeException e) {
245 return null;
246 } catch (OpenEJBException e) {
247 Throwable t = e.getCause();
248 if (t instanceof UnknownModuleTypeException || t instanceof UnsupportedModuleTypeException) {
249 return null;
250 }
251 throw new DeploymentException(e);
252 }
253
254 // did we find a ejb jar?
255 if (appModule.getEjbModules().size() == 0) {
256 return null;
257 }
258
259 // get the module
260 org.apache.openejb.config.EjbModule ejbModule = appModule.getEjbModules().get(0);
261
262 // add the ejb-jar.xml altDD plan
263 if (specDDUrl != null) {
264 ejbModule.setEjbJar(null);
265 ejbModule.getAltDDs().put("ejb-jar.xml", specDDUrl);
266 }
267
268 // convert the vendor plan object to the ejbModule altDD map
269 XmlObject unknownXmlObject = null;
270 if (plan instanceof XmlObject) {
271 unknownXmlObject = (XmlObject) plan;
272 } else if (plan != null) {
273 try {
274 unknownXmlObject = XmlBeansUtil.parse(((File) plan).toURL(), XmlUtil.class.getClassLoader());
275 } catch (Exception e) {
276 throw new DeploymentException(e);
277 }
278 }
279
280 if (unknownXmlObject != null) {
281 XmlCursor xmlCursor = unknownXmlObject.newCursor();
282 //
283 QName qname = xmlCursor.getName();
284 if (qname == null) {
285 xmlCursor.toFirstChild();
286 qname = xmlCursor.getName();
287 }
288 if (qname.getLocalPart().equals("openejb-jar")) {
289 ejbModule.getAltDDs().put("openejb-jar.xml", xmlCursor.xmlText());
290 } else if (qname.getLocalPart().equals("ejb-jar") && qname.getNamespaceURI().equals("http://geronimo.apache.org/xml/ns/j2ee/ejb/openejb-2.0")) {
291 ejbModule.getAltDDs().put("geronimo-openejb.xml", xmlCursor.xmlText());
292 }
293 }
294
295 // Read in the deploument desiptor files
296 ReadDescriptors readDescriptors = new ReadDescriptors();
297 try {
298 readDescriptors.deploy(appModule);
299 } catch (OpenEJBException e) {
300 throw new DeploymentException("Failed parsing descriptors for module: " + moduleFile.getName(), e);
301 }
302
303 // Get the geronimo-openejb.xml tree
304 boolean standAlone = earEnvironment == null;
305 GeronimoEjbJarType geronimoEjbJarType = (GeronimoEjbJarType) ejbModule.getAltDDs().get("geronimo-openejb.xml");
306 if (geronimoEjbJarType == null) {
307 // create default plan
308 String path = (standAlone) ? new File(moduleFile.getName()).getName() : targetPath;
309 geronimoEjbJarType = XmlUtil.createDefaultPlan(path, ejbModule.getEjbJar());
310 ejbModule.getAltDDs().put("geronimo-openejb.xml", geronimoEjbJarType);
311 }
312
313 // create the geronimo environment object
314 Environment environment = XmlUtil.buildEnvironment(geronimoEjbJarType.getEnvironment(), defaultEnvironment);
315 if (earEnvironment != null) {
316 EnvironmentBuilder.mergeEnvironments(earEnvironment, environment);
317 environment = earEnvironment;
318 if (!environment.getConfigId().isResolved()) {
319 throw new IllegalStateException("EJB module ID should be fully resolved (not " + environment.getConfigId() + ")");
320 }
321 } else {
322 idBuilder.resolve(environment, new File(moduleFile.getName()).getName(), "jar");
323 }
324
325
326 AbstractName moduleName;
327 if (earName == null) {
328 earName = naming.createRootName(environment.getConfigId(), NameFactory.NULL, NameFactory.J2EE_APPLICATION);
329 moduleName = naming.createChildName(earName, environment.getConfigId().toString(), NameFactory.EJB_MODULE);
330 ejbModule.setModuleId(environment.getConfigId().getArtifactId());
331 } else {
332 moduleName = naming.createChildName(earName, targetPath, NameFactory.EJB_MODULE);
333 ejbModule.setModuleId(targetPath);
334 }
335
336 // Create XMLBeans version of EjbJarType for the AnnotatedApp interface
337 EjbJar ejbJar = ejbModule.getEjbJar();
338 EjbJarType ejbJarType = XmlUtil.convertToXmlbeans(ejbJar);
339 AnnotatedEjbJar annotatedEjbJar = new AnnotatedEjbJar(ejbJarType);
340
341 EjbModule module = new EjbModule(ejbModule, standAlone, moduleName, environment, moduleFile, targetPath, "", annotatedEjbJar);
342
343 for (ModuleBuilderExtension builder : moduleBuilderExtensions) {
344 try {
345 builder.createModule(module, plan, moduleFile, targetPath, specDDUrl, environment, null, earName, naming, idBuilder);
346 } catch (Throwable t) {
347 String builderName = builder.getClass().getSimpleName();
348 log.error(builderName + ".createModule() failed: " + t.getMessage(), t);
349
350 }
351 }
352 return module;
353 }
354
355 protected static void unmapReferences(EjbJar ejbJar, GeronimoEjbJarType geronimoEjbJarType) {
356 Set<String> corbaEjbRefs = new TreeSet<String>();
357 for (EjbRefType ejbRef : geronimoEjbJarType.getEjbRef()) {
358 if (ejbRef.getNsCorbaloc() != null) {
359 corbaEjbRefs.add(ejbRef.getRefName());
360 }
361 }
362
363 for (EnterpriseBean enterpriseBean : ejbJar.getEnterpriseBeans()) {
364 enterpriseBean.getEnvEntry().clear();
365 enterpriseBean.getEjbLocalRef().clear();
366
367 for (Iterator<EjbRef> iterator = enterpriseBean.getEjbRef().iterator(); iterator.hasNext();) {
368 EjbRef ref = iterator.next();
369 if (!corbaEjbRefs.contains(ref.getEjbRefName())) {
370 // remove all non corba refs to avoid overwriting normal ejb refs
371 iterator.remove();
372 } else {
373 // clear mapped named data from corba refs
374 ref.setMappedName(null);
375 ref.getInjectionTarget().clear();
376 }
377 }
378
379 for (MessageDestinationRef ref : enterpriseBean.getMessageDestinationRef()) {
380 ref.setMappedName(null);
381 ref.getInjectionTarget().clear();
382 }
383 for (PersistenceContextRef ref : enterpriseBean.getPersistenceContextRef()) {
384 ref.setMappedName(null);
385 ref.getInjectionTarget().clear();
386 }
387 for (PersistenceUnitRef ref : enterpriseBean.getPersistenceUnitRef()) {
388 ref.setMappedName(null);
389 ref.getInjectionTarget().clear();
390 }
391 for (ResourceRef ref : enterpriseBean.getResourceRef()) {
392 ref.setMappedName(null);
393 ref.getInjectionTarget().clear();
394 }
395 for (Iterator<ResourceEnvRef> iterator = enterpriseBean.getResourceEnvRef().iterator(); iterator.hasNext();) {
396 ResourceEnvRef ref = iterator.next();
397 if (ref.getType().equals(SessionContext.class.getName())) {
398 iterator.remove();
399 } else if (ref.getType().equals(EntityContext.class.getName())) {
400 iterator.remove();
401 } else if (ref.getType().equals(MessageDrivenContext.class.getName())) {
402 iterator.remove();
403 } else if (ref.getType().equals(TimerService.class.getName())) {
404 iterator.remove();
405 } else if (ref.getType().equals(WebServiceContext.class.getName())) {
406 iterator.remove();
407 } else {
408 ref.setMappedName(null);
409 }
410 ref.getInjectionTarget().clear();
411
412 }
413 for (ServiceRef ref : enterpriseBean.getServiceRef()) {
414 ref.setMappedName(null);
415 ref.getInjectionTarget().clear();
416 }
417 }
418 }
419
420
421 public void installModule(JarFile earFile, EARContext earContext, Module module, Collection configurationStores, ConfigurationStore targetConfigurationStore, Collection repository) throws DeploymentException {
422 installModule(module, earContext);
423 EARContext moduleContext;
424 if (module.isStandAlone()) {
425 moduleContext = earContext;
426 } else {
427 Environment environment = earContext.getConfiguration().getEnvironment();
428 File configurationDir = new File(earContext.getBaseDir(), module.getTargetPath());
429 // configurationDir.mkdirs();
430
431 // construct the ejb app deployment context... this is the same class used by the ear context
432 try {
433 File inPlaceConfigurationDir = null;
434 if (null != earContext.getInPlaceConfigurationDir()) {
435 inPlaceConfigurationDir = new File(earContext.getInPlaceConfigurationDir(), module.getTargetPath());
436 }
437 moduleContext = new EARContext(configurationDir,
438 inPlaceConfigurationDir,
439 environment,
440 ConfigurationModuleType.EJB,
441 module.getModuleName(),
442 earContext);
443 } catch (DeploymentException e) {
444 cleanupConfigurationDir(configurationDir);
445 throw e;
446 }
447 }
448 module.setEarContext(moduleContext);
449 module.setRootEarContext(earContext);
450 if (((EjbModule) module).getEjbJar().getAssemblyDescriptor() != null) {
451 namingBuilder.buildEnvironment(null, null, module.getEnvironment());
452 }
453 for (ModuleBuilderExtension builder : moduleBuilderExtensions) {
454 try {
455 builder.installModule(earFile, earContext, module, configurationStores, targetConfigurationStore, repository);
456 } catch (Throwable t) {
457 String builderName = builder.getClass().getSimpleName();
458 log.error(builderName + ".installModule() failed: " + t.getMessage(), t);
459 }
460 }
461 }
462
463 private void installModule(Module module, EARContext earContext) throws DeploymentException {
464 EarData earData = (EarData) earContext.getGeneralData().get(EarData.class);
465 if (earData == null) {
466 earData = new EarData();
467 earContext.getGeneralData().put(EarData.class, earData);
468 }
469 earData.addEjbModule((EjbModule) module);
470
471 JarFile moduleFile = module.getModuleFile();
472 try {
473 // extract the ejbJar file into a standalone packed jar file and add the contents to the output
474 earContext.addIncludeAsPackedJar(URI.create(module.getTargetPath()), moduleFile);
475 } catch (IOException e) {
476 throw new DeploymentException("Unable to copy ejb module jar into configuration: " + moduleFile.getName(), e);
477 }
478 }
479
480 private static final String LINE_SEP = System.getProperty("line.separator");
481
482 private boolean cleanupConfigurationDir(File configurationDir) {
483 LinkedList<String> cannotBeDeletedList = new LinkedList<String>();
484
485 if (!DeploymentUtil.recursiveDelete(configurationDir, cannotBeDeletedList)) {
486 // Output a message to help user track down file problem
487 log.warn("Unable to delete " + cannotBeDeletedList.size() +
488 " files while recursively deleting directory "
489 + configurationDir.getAbsolutePath() + LINE_SEP +
490 "The first file that could not be deleted was:" + LINE_SEP + " " +
491 (!cannotBeDeletedList.isEmpty() ? cannotBeDeletedList.getFirst() : ""));
492 return false;
493 }
494 return true;
495 }
496
497 public void initContext(EARContext earContext, Module module, ClassLoader classLoader) throws DeploymentException {
498 EjbModule ejbModule = (EjbModule) module;
499
500 EjbJarInfo ejbJarInfo = getEjbJarInfo(earContext, ejbModule, classLoader);
501
502 ejbModule.setEjbJarInfo(ejbJarInfo);
503
504 // update the original spec dd with the metadata complete dd
505 EjbJar ejbJar = ejbModule.getEjbJar();
506 ejbModule.setOriginalSpecDD(XmlUtil.marshal(ejbModule.getEjbJar()));
507
508 // Get the geronimo-openejb plan
509 GeronimoEjbJarType geronimoEjbJarType = (GeronimoEjbJarType) ejbModule.getEjbModule().getAltDDs().get("geronimo-openejb.xml");
510
511 // We must set all mapped name references back to null or Geronimo will blow up
512 unmapReferences(ejbJar, geronimoEjbJarType);
513
514 // create a xmlbeans version of the ejb-jar.xml file, because the jndi code is coupled based on xmlbeans objects
515 EjbJarType ejbJarType = XmlUtil.convertToXmlbeans(ejbJar);
516 ejbModule.setSpecDD(ejbJarType);
517
518 // convert the plan to xmlbeans since geronimo naming is coupled on xmlbeans objects
519 OpenejbGeronimoEjbJarType geronimoOpenejb = XmlUtil.convertToXmlbeans(geronimoEjbJarType);
520 ejbModule.setVendorDD(geronimoOpenejb);
521
522 // todo move namingBuilders.buildEnvironment() here when geronimo naming supports it
523
524 // initialize the naming builders
525 if (ejbJarType.getAssemblyDescriptor() != null) {
526 namingBuilder.initContext(ejbJarType.getAssemblyDescriptor(),
527 geronimoOpenejb,
528 ejbModule);
529 }
530
531 EjbDeploymentBuilder ejbDeploymentBuilder = new EjbDeploymentBuilder(earContext, ejbModule, namingBuilder, resourceEnvironmentSetter);
532 ejbModule.setEjbBuilder(ejbDeploymentBuilder);
533 ejbDeploymentBuilder.initContext();
534
535 // Build the security configuration.
536 securityBuilders.build(geronimoOpenejb, earContext, ejbModule.isStandAlone() ? ejbModule.getEarContext() : null);
537
538 // Add extra gbean declared in the geronimo-openejb.xml file
539 serviceBuilders.build(geronimoOpenejb, earContext, ejbModule.getEarContext());
540
541 ClassPathList manifestcp = new ClassPathList();
542 manifestcp.add(module.getTargetPath());
543 EARContext moduleContext = module.getEarContext();
544 ModuleList moduleLocations = (ModuleList) module.getRootEarContext().getGeneralData().get(ModuleList.class);
545 URI baseUri = URI.create(module.getTargetPath());
546 moduleContext.getCompleteManifestClassPath(module.getModuleFile(), baseUri, URI.create("."), manifestcp, moduleLocations);
547 moduleContext.getGeneralData().put(ClassPathList.class, manifestcp);
548
549 for (ModuleBuilderExtension builder : moduleBuilderExtensions) {
550 try {
551 builder.initContext(earContext, module, classLoader);
552 } catch (Throwable t) {
553 String builderName = builder.getClass().getSimpleName();
554 log.error(builderName + ".initContext() failed: " + t.getMessage(), t);
555 }
556 }
557 }
558
559 private EjbJarInfo getEjbJarInfo(EARContext earContext, EjbModule ejbModule, ClassLoader classLoader) throws DeploymentException {
560 EarData earData = (EarData) earContext.getGeneralData().get(EarData.class);
561 if (earData.getEjbJars().isEmpty()) {
562
563 // temporary classloader is used for processing ejb annotations and byte code manipulation during ejb load
564 TemporaryClassLoader temporaryClassLoader = new TemporaryClassLoader(new URL[0], classLoader);
565
566 // create an openejb app module for the ear containing all ejb modules
567 AppModule appModule = new AppModule(classLoader, earContext.getConfigID().toString());
568 for (EjbModule module : earData.getEjbModuels()) {
569 module.setClassLoader(temporaryClassLoader);
570 appModule.getEjbModules().add(module.getEjbModule());
571 }
572
573 // build the config info tree
574 // this method fills in the ejbJar jaxb tree based on the annotations
575 // (metadata complete) and it run the openejb verifier
576 AppInfo appInfo;
577 try {
578 appInfo = configureApplication(appModule, earContext.getConfiguration());
579 } catch (ValidationFailedException set) {
580 StringBuilder sb = new StringBuilder();
581 sb.append("Jar failed validation: ").append(appModule.getModuleId());
582
583 for (ValidationError e : set.getErrors()) {
584 sb.append(e.getPrefix()).append(" ... ").append(e.getComponentName()).append(":\t").append(e.getMessage(2));
585 }
586
587 for (ValidationFailure e : set.getFailures()) {
588 sb.append(e.getPrefix()).append(" ... ").append(e.getComponentName()).append(":\t").append(e.getMessage(2));
589 }
590
591 throw new DeploymentException(sb.toString());
592 } catch (OpenEJBException e) {
593 throw new DeploymentException(e);
594 }
595
596 // add all of the modules to the ear data
597 for (EjbJarInfo ejbJar : appInfo.ejbJars) {
598 earData.addEjbJar(ejbJar);
599 }
600
601 // add the cmp jar
602 CmpJarBuilder cmp2Builder = new CmpJarBuilder(appInfo, classLoader);
603 try {
604 File generatedJar = cmp2Builder.getJarFile();
605 if (generatedJar != null) {
606 String generatedPath = ejbModule.getTargetPath();
607 if (generatedPath.endsWith(".jar")) {
608 generatedPath = generatedPath.substring(0, generatedPath.length() - 4);
609 }
610 generatedPath += "-cmp2.jar";
611 earContext.addInclude(URI.create(generatedPath), generatedJar);
612 }
613 } catch (IOException e) {
614 throw new DeploymentException(e);
615 }
616
617 // add the cmp persistence unit if needed
618 if (appInfo.cmpMappingsXml != null) {
619 addGeronimmoOpenEJBPersistenceUnit(ejbModule);
620 }
621 }
622
623 // find our module
624 EjbJarInfo ejbJarInfo = earData.getEjbJar(ejbModule.getEjbModule().getModuleId());
625 return ejbJarInfo;
626 }
627
628 private AppInfo configureApplication(AppModule appModule, Configuration configuration) throws OpenEJBException {
629 OpenEjbConfiguration openEjbConfiguration = new OpenEjbConfiguration();
630 openEjbConfiguration.containerSystem = new ContainerSystemInfo();
631 openEjbConfiguration.facilities = new FacilitiesInfo();
632 boolean offline = true;
633 ConfigurationFactory configurationFactory = new ConfigurationFactory(offline, openEjbConfiguration);
634 ClassLoader oldClassLoader = Thread.currentThread().getContextClassLoader();
635 Thread.currentThread().setContextClassLoader(appModule.getClassLoader());
636 try {
637 addContainerInfos(configuration, openEjbConfiguration.containerSystem, configurationFactory);
638 addResourceAdapterMDBInfos(configuration, openEjbConfiguration.containerSystem, configurationFactory);
639 //process resource adapters
640
641 return configurationFactory.configureApplication(appModule);
642 } finally {
643 Thread.currentThread().setContextClassLoader(oldClassLoader);
644 }
645 }
646
647 private void addContainerInfos(Configuration configuration, ContainerSystemInfo containerSystem, ConfigurationFactory configurationFactory) throws OpenEJBException {
648 LinkedHashSet<GBeanData> containerDatas = configuration.findGBeanDatas(Collections.singleton(new AbstractNameQuery(EjbContainer.class.getName())));
649 for (GBeanData containerData : containerDatas) {
650 Class<? extends ContainerInfo> infoClass = (Class<? extends ContainerInfo>) containerData.getAttribute("infoType");
651 if (infoClass == null) {
652 String type = (String) containerData.getAttribute("type");
653 infoClass = EjbContainer.getInfoType(type);
654 }
655 String serviceId = (String) containerData.getAttribute("id");
656 Properties declaredProperties = (Properties) containerData.getAttribute("properties");
657 String providerId = (String) containerData.getAttribute("provider");
658 ContainerInfo containerInfo = configurationFactory.configureService(infoClass, serviceId, declaredProperties, providerId, "Container");
659 containerSystem.containers.add(containerInfo);
660 }
661 }
662
663 private void addResourceAdapterMDBInfos(Configuration configuration, ContainerSystemInfo containerSystem, ConfigurationFactory configurationFactory) throws OpenEJBException {
664 LinkedHashSet<GBeanData> resourceAdapterWrappers = configuration.findGBeanDatas(Collections.singleton(new AbstractNameQuery(ResourceAdapterWrapperGBean.class.getName())));
665 for (GBeanData resourceAdapterWrapperData : resourceAdapterWrappers) {
666 String resourceAdapterId = getResourceAdapterId(resourceAdapterWrapperData.getAbstractName());
667 Map<String, String> messageListenerToActivationSpecMap = (Map<String, String>) resourceAdapterWrapperData.getAttribute("messageListenerToActivationSpecMap");
668 if (messageListenerToActivationSpecMap == null) {
669 continue;
670 }
671 for (Map.Entry<String, String> entry : messageListenerToActivationSpecMap.entrySet()) {
672 String messageListenerInterface = entry.getKey();
673 String activationSpecClass = entry.getValue();
674
675 // only process RA if not previously processed
676 String containerName = resourceAdapterId + "-" + messageListenerInterface;
677 // get default mdb config
678 ContainerInfo containerInfo = configurationFactory.configureService(MdbContainerInfo.class);
679 containerInfo.id = containerName;
680 containerInfo.displayName = containerName;
681
682 // set ra specific properties
683
684 try {
685 containerInfo.properties.put("MessageListenerInterface",
686 configuration.getConfigurationClassLoader().loadClass(messageListenerInterface));
687 } catch (ClassNotFoundException e) {
688 throw new OpenEJBException("Could not load MessageListenerInterface " + messageListenerInterface + " in classloader: " + configuration.getConfigurationClassLoader(), e);
689 }
690 try {
691 containerInfo.properties.put("ActivationSpecClass",
692 configuration.getConfigurationClassLoader().loadClass(activationSpecClass));
693 } catch (ClassNotFoundException e) {
694 throw new OpenEJBException("Could not load ActivationSpecClass " + activationSpecClass + " in classloader: " + configuration.getConfigurationClassLoader(), e);
695 }
696 containerInfo.properties.put("TxRecovery", true);
697 //TODO is this necessary????
698 // containerInfo.properties.put("ResourceAdapter", resourceAdapter);
699
700 containerSystem.containers.add(containerInfo);
701 }
702 }
703 }
704
705
706 private void addGeronimmoOpenEJBPersistenceUnit(EjbModule ejbModule) {
707 GeronimoEjbJarType geronimoEjbJarType = (GeronimoEjbJarType) ejbModule.getEjbModule().getAltDDs().get("geronimo-openejb.xml");
708
709 // search for the cmp persistence unit
710 PersistenceUnit persistenceUnit = null;
711 for (Persistence persistence : geronimoEjbJarType.getPersistence()) {
712 for (PersistenceUnit unit : persistence.getPersistenceUnit()) {
713 if ("cmp".equals(unit.getName())) {
714 persistenceUnit = unit;
715 break;
716 }
717 }
718 }
719
720 // if not found create one
721 if (persistenceUnit == null) {
722 String jtaDataSource = null;
723 // todo Persistence Unit Data Sources need to be global JNDI names
724 Object altDD = ejbModule.getEjbModule().getAltDDs().get("openejb-jar.xml");
725 if (altDD instanceof OpenejbJarType) {
726 ResourceLocatorType cmpConnectionFactory = ((OpenejbJarType) altDD).getCmpConnectionFactory();
727 if (cmpConnectionFactory != null) {
728 String datasourceName = cmpConnectionFactory.getResourceLink();
729 if (datasourceName != null) {
730 jtaDataSource = datasourceName.trim();
731 }
732 }
733 }
734
735 persistenceUnit = new PersistenceUnit();
736 persistenceUnit.setName("cmp");
737 persistenceUnit.setTransactionType(TransactionType.JTA);
738 if (jtaDataSource != null) {
739 persistenceUnit.setJtaDataSource(jtaDataSource);
740 } else {
741 persistenceUnit.setJtaDataSource(defaultCmpJTADataSource);
742 }
743 persistenceUnit.setNonJtaDataSource(defaultCmpNonJTADataSource);
744 persistenceUnit.setExcludeUnlistedClasses(true);
745
746 Persistence persistence = new Persistence();
747 persistence.setVersion("1.0");
748 persistence.getPersistenceUnit().add(persistenceUnit);
749
750 geronimoEjbJarType.getPersistence().add(persistence);
751 }
752 persistenceUnit.getMappingFile().add("META-INF/openejb-cmp-generated-orm.xml");
753 }
754
755 /**
756 * Does the meaty work of processing the deployment information and
757 * creating GBeans for all the EJBs in the JAR, etc.
758 */
759 public void addGBeans(EARContext earContext, Module module, ClassLoader cl, Collection repositories) throws DeploymentException {
760 EjbModule ejbModule = (EjbModule) module;
761 EjbDeploymentBuilder ejbDeploymentBuilder = ejbModule.getEjbBuilder();
762
763 // add enc
764 ejbDeploymentBuilder.buildEnc();
765
766 Set<GBeanData> gBeanDatas = earContext.getConfiguration().findGBeanDatas(Collections.singleton(new AbstractNameQuery(PersistenceUnitGBean.class.getName())));
767 LinkResolver<String> linkResolver = new UniqueDefaultLinkResolver<String>();
768 for (GBeanData gBeanData : gBeanDatas) {
769 String name = (String) gBeanData.getAttribute("persistenceUnitName");
770 String rootUrl = (String) gBeanData.getAttribute("persistenceUnitRoot");
771 if (name.equals("cmp")) continue;
772 String id = name + " " + rootUrl.hashCode();
773 linkResolver.add(rootUrl, name, id);
774 }
775
776 EjbJarInfo ejbJarInfo = ejbModule.getEjbJarInfo();
777 for (EnterpriseBeanInfo beanInfo : ejbJarInfo.enterpriseBeans) {
778 if (beanInfo instanceof StatefulBeanInfo) {
779 StatefulBeanInfo statefulBeanInfo = (StatefulBeanInfo) beanInfo;
780 for (PersistenceContextReferenceInfo refInfo : statefulBeanInfo.jndiEnc.persistenceContextRefs) {
781 if (refInfo.extended) {
782 String id = linkResolver.resolveLink(refInfo.persistenceUnitName, ejbJarInfo.moduleId);
783 refInfo.unitId = id;
784 }
785 }
786 }
787 }
788 // Add JSR77 EJBModule GBean
789 GBeanData ejbModuleGBeanData = new GBeanData(ejbModule.getModuleName(), EjbModuleImplGBean.GBEAN_INFO);
790 try {
791 ejbModuleGBeanData.setReferencePattern("J2EEServer", earContext.getServerName());
792 if (!ejbModule.isStandAlone()) {
793 ejbModuleGBeanData.setReferencePattern("J2EEApplication", earContext.getModuleName());
794 }
795
796 ejbModuleGBeanData.setAttribute("deploymentDescriptor", ejbModule.getOriginalSpecDD());
797
798 ejbModuleGBeanData.setReferencePatterns("EJBCollection",
799 new ReferencePatterns(new AbstractNameQuery(null,
800 Collections.singletonMap(NameFactory.EJB_MODULE, ejbModule.getModuleName().getNameProperty(NameFactory.J2EE_NAME)),
801 EjbDeployment.class.getName())));
802
803 ejbModuleGBeanData.setReferencePattern("OpenEjbSystem", new AbstractNameQuery(null, Collections.EMPTY_MAP, OpenEjbSystem.class.getName()));
804 ejbModuleGBeanData.setAttribute("ejbJarInfo", ejbModule.getEjbJarInfo());
805
806 earContext.addGBean(ejbModuleGBeanData);
807 } catch (Exception e) {
808 throw new DeploymentException("Unable to initialize EJBModule GBean " + ejbModuleGBeanData.getAbstractName(), e);
809 }
810
811 // add a depdendency on the ejb module object
812 ejbDeploymentBuilder.addEjbModuleDependency(ejbModuleGBeanData.getAbstractName());
813
814 // add the Jacc permissions to the ear
815 ComponentPermissions componentPermissions = ejbDeploymentBuilder.buildComponentPermissions();
816 earContext.addSecurityContext(ejbModule.getEjbJarInfo().moduleId, componentPermissions);
817
818 setMdbContainerIds(earContext, ejbModule, ejbModuleGBeanData);
819
820 for (ModuleBuilderExtension builder : moduleBuilderExtensions) {
821 try {
822 builder.addGBeans(earContext, module, cl, repositories);
823 } catch (Throwable t) {
824 String builderName = builder.getClass().getSimpleName();
825 log.error(builderName + ".addGBeans() failed: " + t.getMessage(), t);
826 }
827 }
828 }
829
830 private void setMdbContainerIds(EARContext earContext, EjbModule ejbModule, GBeanData ejbModuleGBeanData) throws DeploymentException {
831 Object altDD = ejbModule.getEjbModule().getAltDDs().get("openejb-jar.xml");
832 if (!(altDD instanceof OpenejbJarType)) {
833 return;
834 }
835 OpenejbJarType openejbJarType = (OpenejbJarType) altDD;
836 EjbJarInfo ejbJarInfo = ejbModule.getEjbJarInfo();
837
838 Map<String, MessageDrivenBeanInfo> mdbs = new TreeMap<String, MessageDrivenBeanInfo>();
839 for (EnterpriseBeanInfo enterpriseBean : ejbJarInfo.enterpriseBeans) {
840 if (enterpriseBean instanceof MessageDrivenBeanInfo) {
841 mdbs.put(enterpriseBean.ejbName, (MessageDrivenBeanInfo) enterpriseBean);
842 }
843 }
844 for (org.apache.openejb.jee.oejb2.EnterpriseBean enterpriseBean : openejbJarType.getEnterpriseBeans()) {
845 if (!(enterpriseBean instanceof MessageDrivenBeanType)) {
846 continue;
847 }
848 MessageDrivenBeanType bean = (MessageDrivenBeanType) enterpriseBean;
849 MessageDrivenBeanInfo messageDrivenBeanInfo = mdbs.get(bean.getEjbName());
850 if (messageDrivenBeanInfo == null) {
851 continue;
852 }
853 if (messageDrivenBeanInfo.containerId != null) {
854 // containerId already set
855 continue;
856 }
857
858 if (bean.getResourceAdapter() == null) {
859 throw new DeploymentException("No Resource Adapter defined for MDB '" + bean.getEjbName() + "'");
860 }
861
862 AbstractNameQuery resourceAdapterNameQuery = getResourceAdapterNameQuery(bean.getResourceAdapter());
863 AbstractName resourceAdapterAbstractName;
864 try {
865 resourceAdapterAbstractName = earContext.findGBean(resourceAdapterNameQuery);
866 } catch (GBeanNotFoundException e) {
867 throw new DeploymentException("Resource Adapter for MDB '" + bean.getEjbName() + "'not found: " + resourceAdapterNameQuery, e);
868 }
869
870 String resourceAdapterId = getResourceAdapterId(resourceAdapterAbstractName);
871 messageDrivenBeanInfo.containerId = resourceAdapterId + "-" + messageDrivenBeanInfo.mdbInterface;
872
873 // add a dependency from the module to the ra so we can be assured the mdb
874 // container exists when this app is started
875 ejbModuleGBeanData.addDependency(resourceAdapterAbstractName);
876 }
877 }
878
879 private String getResourceAdapterId(AbstractName resourceAdapterAbstractName) {
880 Map properties = resourceAdapterAbstractName.getName();
881 String shortName = (String) properties.get("name");
882 String moduleName = (String) properties.get("ResourceAdapterModule");
883 if (shortName != null && moduleName != null) {
884 return moduleName + "." + shortName;
885 } else {
886 return resourceAdapterAbstractName.getObjectName().toString();
887 }
888 }
889
890 private static AbstractNameQuery getResourceAdapterNameQuery(ResourceLocatorType resourceLocator) {
891 if (resourceLocator.getResourceLink() != null) {
892 Map<String, String> nameMap = new HashMap<String, String>();
893 nameMap.put("name", resourceLocator.getResourceLink());
894 nameMap.put("j2eeType", NameFactory.JCA_RESOURCE_ADAPTER);
895 return new AbstractNameQuery(null, nameMap);
896 }
897
898 //construct name from components
899 PatternType pattern = resourceLocator.getPattern();
900 Artifact artifact = null;
901 if (pattern.getArtifactId() != null) {
902 artifact = new Artifact(pattern.getGroupId(), pattern.getArtifactId(), pattern.getVersion(), "car");
903 }
904
905 Map<String, String> nameMap = new HashMap<String, String>();
906 nameMap.put("name", pattern.getName());
907 nameMap.put("j2eeType", NameFactory.JCA_RESOURCE_ADAPTER);
908 if (pattern.getModule() != null) {
909 nameMap.put(NameFactory.RESOURCE_ADAPTER_MODULE, pattern.getModule());
910 }
911 return new AbstractNameQuery(artifact, nameMap, (Set) null);
912 }
913
914 public static class EarData {
915 private final Map<String, EjbModule> ejbModules = new TreeMap<String, EjbModule>();
916 private final Map<String, EjbJarInfo> ejbJars = new TreeMap<String, EjbJarInfo>();
917
918 public void addEjbModule(EjbModule ejbModule) {
919 ejbModules.put(ejbModule.getEjbModule().getModuleId(), ejbModule);
920 }
921
922 public EjbModule getEjbModule(String moduleId) throws DeploymentException {
923 EjbModule ejbModule = ejbModules.get(moduleId);
924 if (ejbModule == null) {
925 throw new DeploymentException("Ejb module " + moduleId + " was not found in configured module list " + ejbModules.keySet());
926 }
927 return ejbModule;
928 }
929
930 public Collection<EjbModule> getEjbModuels() {
931 return ejbModules.values();
932 }
933
934 public void addEjbJar(EjbJarInfo ejbJarInfo) {
935 ejbJars.put(ejbJarInfo.moduleId, ejbJarInfo);
936 }
937
938 public EjbJarInfo getEjbJar(String moduleId) throws DeploymentException {
939 EjbJarInfo ejbJarInfo = ejbJars.get(moduleId);
940 if (ejbJarInfo == null) {
941 throw new DeploymentException("Ejb jar configuration passed but expected module " +
942 moduleId + " was not found in configured module list " + ejbJars.keySet());
943 }
944 return ejbJarInfo;
945 }
946
947 public Collection<EjbJarInfo> getEjbJars() {
948 return ejbJars.values();
949 }
950 }
951
952
953 public static final GBeanInfo GBEAN_INFO;
954
955 static {
956 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(EjbModuleBuilder.class, NameFactory.MODULE_BUILDER);
957 infoBuilder.addAttribute("defaultEnvironment", Environment.class, true);
958 infoBuilder.addAttribute("defaultCmpJTADataSource", String.class, true);
959 infoBuilder.addAttribute("defaultCmpNonJTADataSource", String.class, true);
960 infoBuilder.addReference("ModuleBuilderExtensions", ModuleBuilderExtension.class, NameFactory.MODULE_BUILDER);
961 infoBuilder.addReference("SecurityBuilders", NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER);
962 infoBuilder.addReference("ServiceBuilders", NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER);
963 infoBuilder.addReference("NamingBuilders", NamingBuilder.class, NameFactory.MODULE_BUILDER);
964 infoBuilder.addReference("ResourceEnvironmentSetter", ResourceEnvironmentSetter.class, NameFactory.MODULE_BUILDER);
965
966 infoBuilder.setConstructor(new String[]{
967 "defaultEnvironment",
968 "defaultCmpJTADataSource",
969 "defaultCmpNonJTADataSource",
970 "ModuleBuilderExtensions",
971 "SecurityBuilders",
972 "ServiceBuilders",
973 "NamingBuilders",
974 "ResourceEnvironmentSetter"});
975 GBEAN_INFO = infoBuilder.getBeanInfo();
976 }
977
978 public static GBeanInfo getGBeanInfo() {
979 return GBEAN_INFO;
980 }
981
982 }