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.LinkedList;
028 import java.util.Map;
029 import java.util.Set;
030 import java.util.TreeMap;
031 import java.util.TreeSet;
032 import java.util.jar.JarFile;
033
034 import javax.ejb.EntityContext;
035 import javax.ejb.SessionContext;
036 import javax.ejb.MessageDrivenContext;
037 import javax.xml.namespace.QName;
038
039 import org.apache.commons.logging.Log;
040 import org.apache.commons.logging.LogFactory;
041 import org.apache.geronimo.common.DeploymentException;
042 import org.apache.geronimo.deployment.ModuleIDBuilder;
043 import org.apache.geronimo.deployment.NamespaceDrivenBuilder;
044 import org.apache.geronimo.deployment.NamespaceDrivenBuilderCollection;
045 import org.apache.geronimo.deployment.service.EnvironmentBuilder;
046 import org.apache.geronimo.deployment.service.GBeanBuilder;
047 import org.apache.geronimo.deployment.util.DeploymentUtil;
048 import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
049 import org.apache.geronimo.gbean.AbstractName;
050 import org.apache.geronimo.gbean.AbstractNameQuery;
051 import org.apache.geronimo.gbean.GBeanData;
052 import org.apache.geronimo.gbean.GBeanInfo;
053 import org.apache.geronimo.gbean.GBeanInfoBuilder;
054 import org.apache.geronimo.gbean.ReferencePatterns;
055 import org.apache.geronimo.j2ee.deployment.EARContext;
056 import org.apache.geronimo.j2ee.deployment.Module;
057 import org.apache.geronimo.j2ee.deployment.ModuleBuilder;
058 import org.apache.geronimo.j2ee.deployment.ModuleBuilderExtension;
059 import org.apache.geronimo.j2ee.deployment.NamingBuilder;
060 import org.apache.geronimo.deployment.ModuleList;
061 import org.apache.geronimo.deployment.ClassPathList;
062 import org.apache.geronimo.j2ee.deployment.annotation.AnnotatedEjbJar;
063 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
064 import org.apache.geronimo.kernel.classloader.TemporaryClassLoader;
065 import org.apache.geronimo.kernel.Naming;
066 import org.apache.geronimo.kernel.GBeanNotFoundException;
067 import org.apache.geronimo.kernel.config.ConfigurationModuleType;
068 import org.apache.geronimo.kernel.config.ConfigurationStore;
069 import org.apache.geronimo.kernel.repository.Environment;
070 import org.apache.geronimo.kernel.repository.Artifact;
071 import org.apache.geronimo.naming.deployment.ResourceEnvironmentSetter;
072 import org.apache.geronimo.openejb.EjbDeployment;
073 import org.apache.geronimo.openejb.EjbModuleImplGBean;
074 import org.apache.geronimo.openejb.OpenEjbSystem;
075 import org.apache.geronimo.openejb.xbeans.ejbjar.OpenejbGeronimoEjbJarType;
076 import org.apache.geronimo.security.jacc.ComponentPermissions;
077 import org.apache.geronimo.xbeans.geronimo.j2ee.GerSecurityDocument;
078 import org.apache.geronimo.xbeans.javaee.EjbJarType;
079 import org.apache.openejb.OpenEJBException;
080 import org.apache.openejb.assembler.classic.AppInfo;
081 import org.apache.openejb.assembler.classic.CmpJarBuilder;
082 import org.apache.openejb.assembler.classic.EjbJarInfo;
083 import org.apache.openejb.assembler.classic.EnterpriseBeanInfo;
084 import org.apache.openejb.assembler.classic.MessageDrivenBeanInfo;
085 import org.apache.openejb.config.AppModule;
086 import org.apache.openejb.config.DeploymentLoader;
087 import org.apache.openejb.config.ReadDescriptors;
088 import org.apache.openejb.config.UnknownModuleTypeException;
089 import org.apache.openejb.config.UnsupportedModuleTypeException;
090 import org.apache.openejb.config.ValidationFailedException;
091 import org.apache.openejb.config.ValidationError;
092 import org.apache.openejb.config.ValidationFailure;
093 import org.apache.openejb.jee.EjbJar;
094 import org.apache.openejb.jee.EnterpriseBean;
095 import org.apache.openejb.jee.MessageDestinationRef;
096 import org.apache.openejb.jee.PersistenceContextRef;
097 import org.apache.openejb.jee.PersistenceUnitRef;
098 import org.apache.openejb.jee.ResourceEnvRef;
099 import org.apache.openejb.jee.ResourceRef;
100 import org.apache.openejb.jee.ServiceRef;
101 import org.apache.openejb.jee.EjbRef;
102 import org.apache.openejb.jee.jpa.unit.Persistence;
103 import org.apache.openejb.jee.jpa.unit.PersistenceUnit;
104 import org.apache.openejb.jee.jpa.unit.TransactionType;
105 import org.apache.openejb.jee.oejb2.GeronimoEjbJarType;
106 import org.apache.openejb.jee.oejb2.ResourceLocatorType;
107 import org.apache.openejb.jee.oejb2.PatternType;
108 import org.apache.openejb.jee.oejb2.OpenejbJarType;
109 import org.apache.openejb.jee.oejb2.MessageDrivenBeanType;
110 import org.apache.openejb.jee.oejb2.EjbRefType;
111 import org.apache.xmlbeans.XmlCursor;
112 import org.apache.xmlbeans.XmlObject;
113
114 /**
115 * Master builder for processing EJB JAR deployments and creating the
116 * correspinding runtime objects (GBeans, etc.).
117 *
118 * @version $Revision: 479481 $ $Date: 2006-11-26 16:52:20 -0800 (Sun, 26 Nov 2006) $
119 */
120 public class EjbModuleBuilder implements ModuleBuilder {
121 private static final Log log = LogFactory.getLog(EjbModuleBuilder.class);
122
123 private static final String OPENEJBJAR_NAMESPACE = XmlUtil.OPENEJBJAR_QNAME.getNamespaceURI();
124
125 private final Environment defaultEnvironment;
126 private final String defaultCmpJTADataSource;
127 private final String defaultCmpNonJTADataSource;
128 private final NamespaceDrivenBuilderCollection securityBuilders;
129 private final NamespaceDrivenBuilderCollection serviceBuilders;
130 private final NamingBuilder namingBuilder;
131 private final ResourceEnvironmentSetter resourceEnvironmentSetter;
132 private final OpenEjbSystem openEjbSystem;
133 private final Collection<ModuleBuilderExtension> moduleBuilderExtensions;
134
135 public EjbModuleBuilder(Environment defaultEnvironment,
136
137 String defaultCmpJTADataSource, String defaultCmpNonJTADataSource, OpenEjbSystem openEjbSystem,
138 Collection<ModuleBuilderExtension> moduleBuilderExtensions,
139 Collection securityBuilders,
140 Collection serviceBuilders,
141 NamingBuilder namingBuilders,
142 ResourceEnvironmentSetter resourceEnvironmentSetter) {
143
144 this.openEjbSystem = openEjbSystem;
145 this.defaultEnvironment = defaultEnvironment;
146 this.defaultCmpJTADataSource = defaultCmpJTADataSource;
147 this.defaultCmpNonJTADataSource = defaultCmpNonJTADataSource;
148 this.securityBuilders = new NamespaceDrivenBuilderCollection(securityBuilders, GerSecurityDocument.type.getDocumentElementName());
149 this.serviceBuilders = new NamespaceDrivenBuilderCollection(serviceBuilders, GBeanBuilder.SERVICE_QNAME);
150 this.namingBuilder = namingBuilders;
151 this.resourceEnvironmentSetter = resourceEnvironmentSetter;
152
153 if (moduleBuilderExtensions == null) {
154 moduleBuilderExtensions = Collections.emptyList();
155 }
156 this.moduleBuilderExtensions = moduleBuilderExtensions;
157 }
158
159 public String getSchemaNamespace() {
160 return EjbModuleBuilder.OPENEJBJAR_NAMESPACE;
161 }
162
163 public Module createModule(File plan, JarFile moduleFile, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException {
164 return createModule(plan, moduleFile, "ejb.jar", null, null, null, naming, idBuilder);
165 }
166
167 public Module createModule(Object plan, JarFile moduleFile, String targetPath, URL specDDUrl, Environment environment, Object moduleContextInfo, AbstractName earName, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException {
168 return createModule(plan, moduleFile, targetPath, specDDUrl, environment, earName, naming, idBuilder);
169 }
170
171 private Module createModule(Object plan, JarFile moduleFile, String targetPath, URL specDDUrl, Environment earEnvironment, AbstractName earName, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException {
172 if (moduleFile == null) throw new NullPointerException("moduleFile is null");
173 if (targetPath == null) throw new NullPointerException("targetPath is null");
174 if (targetPath.endsWith("/")) throw new IllegalArgumentException("targetPath must not end with a '/'");
175
176 // Load the module file
177 DeploymentLoader loader = new DeploymentLoader();
178 AppModule appModule = null;
179 try {
180 appModule = loader.load(new File(moduleFile.getName()));
181 } catch (UnknownModuleTypeException e){
182 return null;
183 } catch (UnsupportedModuleTypeException e){
184 return null;
185 } catch (OpenEJBException e) {
186 Throwable t = e.getCause();
187 if (t instanceof UnknownModuleTypeException || t instanceof UnsupportedModuleTypeException) {
188 return null;
189 }
190 throw new DeploymentException(e);
191 }
192
193 // did we find a ejb jar?
194 if (appModule.getEjbModules().size() == 0) {
195 return null;
196 }
197
198 // get the module
199 org.apache.openejb.config.EjbModule ejbModule = appModule.getEjbModules().get(0);
200
201 // add the ejb-jar.xml altDD plan
202 if (specDDUrl != null) {
203 ejbModule.getAltDDs().put("ejb-jar.xml", specDDUrl);
204 }
205
206 // convert the vendor plan object to the ejbModule altDD map
207 XmlObject unknownXmlObject = null;
208 if (plan instanceof XmlObject) {
209 unknownXmlObject = (XmlObject) plan;
210 } else if (plan != null) {
211 try {
212 unknownXmlObject = XmlBeansUtil.parse(((File) plan).toURL(), XmlUtil.class.getClassLoader());
213 } catch (Exception e) {
214 throw new DeploymentException(e);
215 }
216 }
217
218 if (unknownXmlObject != null) {
219 XmlCursor xmlCursor = unknownXmlObject.newCursor();
220 //
221 QName qname = xmlCursor.getName();
222 if (qname == null) {
223 xmlCursor.toFirstChild();
224 qname = xmlCursor.getName();
225 }
226 if (qname.getLocalPart().equals("openejb-jar")) {
227 ejbModule.getAltDDs().put("openejb-jar.xml", xmlCursor.xmlText());
228 } else
229 if (qname.getLocalPart().equals("ejb-jar") && qname.getNamespaceURI().equals("http://geronimo.apache.org/xml/ns/j2ee/ejb/openejb-2.0")) {
230 ejbModule.getAltDDs().put("geronimo-openejb.xml", xmlCursor.xmlText());
231 }
232 }
233
234 // Read in the deploument desiptor files
235 ReadDescriptors readDescriptors = new ReadDescriptors();
236 try {
237 readDescriptors.deploy(appModule);
238 } catch (OpenEJBException e) {
239 throw new DeploymentException("Failed parsing descriptors for module: " + moduleFile.getName(), e);
240 }
241
242 // Get the geronimo-openejb.xml tree
243 boolean standAlone = earEnvironment == null;
244 GeronimoEjbJarType geronimoEjbJarType = (GeronimoEjbJarType) ejbModule.getAltDDs().get("geronimo-openejb.xml");
245 if (geronimoEjbJarType == null) {
246 // create default plan
247 String path = (standAlone) ? new File(moduleFile.getName()).getName() : targetPath;
248 geronimoEjbJarType = XmlUtil.createDefaultPlan(path, ejbModule.getEjbJar());
249 ejbModule.getAltDDs().put("geronimo-openejb.xml", geronimoEjbJarType);
250 }
251
252 // create the geronimo environment object
253 Environment environment = XmlUtil.buildEnvironment(geronimoEjbJarType.getEnvironment(), defaultEnvironment);
254 if (earEnvironment != null) {
255 EnvironmentBuilder.mergeEnvironments(earEnvironment, environment);
256 environment = earEnvironment;
257 if (!environment.getConfigId().isResolved()) {
258 throw new IllegalStateException("EJB module ID should be fully resolved (not " + environment.getConfigId() + ")");
259 }
260 } else {
261 idBuilder.resolve(environment, new File(moduleFile.getName()).getName(), "jar");
262 }
263
264
265 AbstractName moduleName;
266 if (earName == null) {
267 earName = naming.createRootName(environment.getConfigId(), NameFactory.NULL, NameFactory.J2EE_APPLICATION);
268 moduleName = naming.createChildName(earName, environment.getConfigId().toString(), NameFactory.EJB_MODULE);
269 ejbModule.setModuleId(environment.getConfigId().getArtifactId());
270 } else {
271 moduleName = naming.createChildName(earName, targetPath, NameFactory.EJB_MODULE);
272 ejbModule.setModuleId(targetPath);
273 }
274
275 // Create XMLBeans version of EjbJarType for the AnnotatedApp interface
276 EjbJar ejbJar = ejbModule.getEjbJar();
277 EjbJarType ejbJarType = XmlUtil.convertToXmlbeans(ejbJar);
278 AnnotatedEjbJar annotatedEjbJar = new AnnotatedEjbJar(ejbJarType);
279
280 EjbModule module = new EjbModule(ejbModule, standAlone, moduleName, environment, moduleFile, targetPath, "", annotatedEjbJar);
281
282 for (ModuleBuilderExtension builder : moduleBuilderExtensions) {
283 try {
284 builder.createModule(module, plan, moduleFile, targetPath, specDDUrl, environment, null, earName, naming, idBuilder);
285 } catch (Throwable t) {
286 String builderName = builder.getClass().getSimpleName();
287 log.error(builderName + ".createModule() failed: " + t.getMessage(), t);
288
289 }
290 }
291 return module;
292 }
293
294 protected static void unmapReferences(EjbJar ejbJar, GeronimoEjbJarType geronimoEjbJarType) {
295 Set<String> corbaEjbRefs = new TreeSet<String>();
296 for (EjbRefType ejbRef : geronimoEjbJarType.getEjbRef()) {
297 if (ejbRef.getNsCorbaloc() != null) {
298 corbaEjbRefs.add(ejbRef.getRefName());
299 }
300 }
301
302 for (EnterpriseBean enterpriseBean : ejbJar.getEnterpriseBeans()) {
303 enterpriseBean.getEnvEntry().clear();
304 enterpriseBean.getEjbLocalRef().clear();
305
306 for (Iterator<EjbRef> iterator = enterpriseBean.getEjbRef().iterator(); iterator.hasNext();) {
307 EjbRef ref = iterator.next();
308 if (!corbaEjbRefs.contains(ref.getEjbRefName())) {
309 // remove all non corba refs to avoid overwriting normal ejb refs
310 iterator.remove();
311 } else {
312 // clear mapped named data from corba refs
313 ref.setMappedName(null);
314 ref.getInjectionTarget().clear();
315 }
316 }
317
318 for (MessageDestinationRef ref : enterpriseBean.getMessageDestinationRef()) {
319 ref.setMappedName(null);
320 ref.getInjectionTarget().clear();
321 }
322 for (PersistenceContextRef ref : enterpriseBean.getPersistenceContextRef()) {
323 ref.setMappedName(null);
324 ref.getInjectionTarget().clear();
325 }
326 for (PersistenceUnitRef ref : enterpriseBean.getPersistenceUnitRef()) {
327 ref.setMappedName(null);
328 ref.getInjectionTarget().clear();
329 }
330 for (ResourceRef ref : enterpriseBean.getResourceRef()) {
331 ref.setMappedName(null);
332 ref.getInjectionTarget().clear();
333 }
334 for (Iterator<ResourceEnvRef> iterator = enterpriseBean.getResourceEnvRef().iterator(); iterator.hasNext();)
335 {
336 ResourceEnvRef ref = iterator.next();
337 if (ref.getType().equals(SessionContext.class.getName())) {
338 iterator.remove();
339 } else if (ref.getType().equals(EntityContext.class.getName())) {
340 iterator.remove();
341 } else if (ref.getType().equals(MessageDrivenContext.class.getName())) {
342 iterator.remove();
343 } else {
344 ref.setMappedName(null);
345 }
346 ref.getInjectionTarget().clear();
347
348 }
349 for (ServiceRef ref : enterpriseBean.getServiceRef()) {
350 ref.setMappedName(null);
351 ref.getInjectionTarget().clear();
352 }
353 }
354 }
355
356
357 public void installModule(JarFile earFile, EARContext earContext, Module module, Collection configurationStores, ConfigurationStore targetConfigurationStore, Collection repository) throws DeploymentException {
358 installModule(module, earContext);
359 EARContext moduleContext;
360 if (module.isStandAlone()) {
361 moduleContext = earContext;
362 } else {
363 Environment environment = earContext.getConfiguration().getEnvironment();
364 File configurationDir = new File(earContext.getBaseDir(), module.getTargetPath());
365 // configurationDir.mkdirs();
366
367 // construct the ejb app deployment context... this is the same class used by the ear context
368 try {
369 File inPlaceConfigurationDir = null;
370 if (null != earContext.getInPlaceConfigurationDir()) {
371 inPlaceConfigurationDir = new File(earContext.getInPlaceConfigurationDir(), module.getTargetPath());
372 }
373 moduleContext = new EARContext(configurationDir,
374 inPlaceConfigurationDir,
375 environment,
376 ConfigurationModuleType.EJB,
377 module.getModuleName(),
378 earContext);
379 } catch (DeploymentException e) {
380 cleanupConfigurationDir(configurationDir);
381 throw e;
382 }
383 }
384 module.setEarContext(moduleContext);
385 module.setRootEarContext(earContext);
386 if (((EjbModule)module).getEjbJar().getAssemblyDescriptor() != null) {
387 namingBuilder.buildEnvironment(null, null, module.getEnvironment());
388 }
389 for (ModuleBuilderExtension builder : moduleBuilderExtensions) {
390 try {
391 builder.installModule(earFile, earContext, module, configurationStores, targetConfigurationStore, repository);
392 } catch (Throwable t) {
393 String builderName = builder.getClass().getSimpleName();
394 log.error(builderName + ".installModule() failed: " + t.getMessage(), t);
395 }
396 }
397 }
398
399 private void installModule(Module module, EARContext earContext) throws DeploymentException {
400 EarData earData = (EarData) earContext.getGeneralData().get(EarData.class);
401 if (earData == null) {
402 earData = new EarData();
403 earContext.getGeneralData().put(EarData.class, earData);
404 }
405 earData.addEjbModule((EjbModule) module);
406
407 JarFile moduleFile = module.getModuleFile();
408 try {
409 // extract the ejbJar file into a standalone packed jar file and add the contents to the output
410 earContext.addIncludeAsPackedJar(URI.create(module.getTargetPath()), moduleFile);
411 } catch (IOException e) {
412 throw new DeploymentException("Unable to copy ejb module jar into configuration: " + moduleFile.getName(), e);
413 }
414 }
415
416 private static final String LINE_SEP = System.getProperty("line.separator");
417
418 private boolean cleanupConfigurationDir(File configurationDir) {
419 LinkedList<String> cannotBeDeletedList = new LinkedList<String>();
420
421 if (!DeploymentUtil.recursiveDelete(configurationDir, cannotBeDeletedList)) {
422 // Output a message to help user track down file problem
423 log.warn("Unable to delete " + cannotBeDeletedList.size() +
424 " files while recursively deleting directory "
425 + configurationDir.getAbsolutePath() + LINE_SEP +
426 "The first file that could not be deleted was:" + LINE_SEP + " " +
427 (!cannotBeDeletedList.isEmpty() ? cannotBeDeletedList.getFirst() : ""));
428 return false;
429 }
430 return true;
431 }
432
433 public void initContext(EARContext earContext, Module module, ClassLoader classLoader) throws DeploymentException {
434 EjbModule ejbModule = (EjbModule) module;
435 EarData earData = (EarData) earContext.getGeneralData().get(EarData.class);
436
437 EjbJarInfo ejbJarInfo = getEjbJarInfo(earContext, ejbModule, classLoader);
438
439 ejbModule.setEjbJarInfo(ejbJarInfo);
440
441 // update the original spec dd with the metadata complete dd
442 EjbJar ejbJar = ejbModule.getEjbJar();
443 ejbModule.setOriginalSpecDD(XmlUtil.marshal(ejbModule.getEjbJar()));
444
445 // Get the geronimo-openejb plan
446 GeronimoEjbJarType geronimoEjbJarType = (GeronimoEjbJarType) ejbModule.getEjbModule().getAltDDs().get("geronimo-openejb.xml");
447
448 // We must set all mapped name references back to null or Geronimo will blow up
449 unmapReferences(ejbJar, geronimoEjbJarType);
450
451 // create a xmlbeans version of the ejb-jar.xml file, because the jndi code is coupled based on xmlbeans objects
452 EjbJarType ejbJarType = XmlUtil.convertToXmlbeans(ejbJar);
453 ejbModule.setSpecDD(ejbJarType);
454
455 // convert the plan to xmlbeans since geronimo naming is coupled on xmlbeans objects
456 OpenejbGeronimoEjbJarType geronimoOpenejb = XmlUtil.convertToXmlbeans(geronimoEjbJarType);
457 ejbModule.setVendorDD(geronimoOpenejb);
458
459 // todo move namingBuilders.buildEnvironment() here when geronimo naming supports it
460
461 // initialize the naming builders
462 if (ejbJarType.getAssemblyDescriptor() != null) {
463 namingBuilder.initContext(ejbJarType.getAssemblyDescriptor(),
464 geronimoOpenejb,
465 ejbModule);
466 }
467
468 EjbDeploymentBuilder ejbDeploymentBuilder = new EjbDeploymentBuilder(earContext, ejbModule, namingBuilder, resourceEnvironmentSetter);
469 ejbModule.setEjbBuilder(ejbDeploymentBuilder);
470 ejbDeploymentBuilder.initContext();
471
472 // Build the security configuration.
473 securityBuilders.build(geronimoOpenejb, earContext, ejbModule.isStandAlone() ? ejbModule.getEarContext() : null);
474
475 // Add extra gbean declared in the geronimo-openejb.xml file
476 serviceBuilders.build(geronimoOpenejb, earContext, ejbModule.getEarContext());
477
478 ClassPathList manifestcp = new ClassPathList();
479 manifestcp.add(module.getTargetPath());
480 EARContext moduleContext = module.getEarContext();
481 ModuleList moduleLocations = (ModuleList) module.getRootEarContext().getGeneralData().get(ModuleList.class);
482 URI baseUri = URI.create(module.getTargetPath());
483 moduleContext.getCompleteManifestClassPath(module.getModuleFile(), baseUri, URI.create("."), manifestcp, moduleLocations);
484 moduleContext.getGeneralData().put(ClassPathList.class, manifestcp);
485
486 for (ModuleBuilderExtension builder : moduleBuilderExtensions) {
487 try {
488 builder.initContext(earContext, module, classLoader);
489 } catch (Throwable t) {
490 String builderName = builder.getClass().getSimpleName();
491 log.error(builderName + ".initContext() failed: " + t.getMessage(), t);
492 }
493 }
494 }
495
496 private EjbJarInfo getEjbJarInfo(EARContext earContext, EjbModule ejbModule, ClassLoader classLoader) throws DeploymentException {
497 EarData earData = (EarData) earContext.getGeneralData().get(EarData.class);
498 if (earData.getEjbJars().isEmpty()) {
499
500 // temporary classloader is used for processing ejb annotations and byte code manipulation during ejb load
501 TemporaryClassLoader temporaryClassLoader = new TemporaryClassLoader(new URL[0], classLoader);
502
503 // create an openejb app module for the ear containing all ejb modules
504 AppModule appModule = new AppModule(classLoader, ejbModule.getEjbModule().getModuleId());
505 for (EjbModule module : earData.getEjbModuels()) {
506 module.setClassLoader(temporaryClassLoader);
507 appModule.getEjbModules().add(module.getEjbModule());
508 }
509
510 // build the config info tree
511 // this method fills in the ejbJar jaxb tree based on the annotations
512 // (metadata complete) and it run the openejb verifier
513 AppInfo appInfo;
514 try {
515 appInfo = openEjbSystem.configureApplication(appModule);
516 } catch (ValidationFailedException set) {
517 StringBuilder sb = new StringBuilder();
518 sb.append("Jar failed validation: "+appModule.getModuleId());
519
520 for (ValidationError e : set.getErrors()) {
521 sb.append(e.getPrefix() + " ... " + e.getComponentName() + ":\t" + e.getMessage(2));
522 }
523
524 for (ValidationFailure e : set.getFailures()) {
525 sb.append(e.getPrefix() + " ... " + e.getComponentName() + ":\t" + e.getMessage(2));
526 }
527
528 throw new DeploymentException(sb.toString());
529 } catch (OpenEJBException e) {
530 throw new DeploymentException(e);
531 }
532
533 // add all of the modules to the ear data
534 for (EjbJarInfo ejbJar : appInfo.ejbJars) {
535 earData.addEjbJar(ejbJar);
536 }
537
538 // add the cmp jar
539 CmpJarBuilder cmp2Builder = new CmpJarBuilder(appInfo, classLoader);
540 try {
541 File generatedJar = cmp2Builder.getJarFile();
542 if (generatedJar != null) {
543 String generatedPath = ejbModule.getTargetPath();
544 if (generatedPath.endsWith(".jar")) {
545 generatedPath = generatedPath.substring(0, generatedPath.length() - 4);
546 }
547 generatedPath += "-cmp2.jar";
548 earContext.addInclude(URI.create(generatedPath), generatedJar);
549 }
550 } catch (IOException e) {
551 throw new DeploymentException(e);
552 }
553
554 // add the cmp persistence unit if needed
555 if (appInfo.cmpMappingsXml != null) {
556 addGeronimmoOpenEJBPersistenceUnit(ejbModule);
557 }
558 }
559
560 // find our module
561 EjbJarInfo ejbJarInfo = earData.getEjbJar(ejbModule.getEjbModule().getModuleId());
562 return ejbJarInfo;
563 }
564
565 private void addGeronimmoOpenEJBPersistenceUnit(EjbModule ejbModule) {
566 GeronimoEjbJarType geronimoEjbJarType = (GeronimoEjbJarType) ejbModule.getEjbModule().getAltDDs().get("geronimo-openejb.xml");
567
568 // search for the cmp persistence unit
569 PersistenceUnit persistenceUnit = null;
570 for (Persistence persistence : geronimoEjbJarType.getPersistence()) {
571 for (PersistenceUnit unit : persistence.getPersistenceUnit()) {
572 if ("cmp".equals(unit.getName())) {
573 persistenceUnit = unit;
574 break;
575 }
576 }
577 }
578
579 // if not found create one
580 if (persistenceUnit == null) {
581 String jtaDataSource = null;
582 // todo Persistence Unit Data Sources need to be global JNDI names
583 Object altDD = ejbModule.getEjbModule().getAltDDs().get("openejb-jar.xml");
584 if (altDD instanceof OpenejbJarType) {
585 ResourceLocatorType cmpConnectionFactory = ((OpenejbJarType) altDD).getCmpConnectionFactory();
586 if (cmpConnectionFactory != null) {
587 String datasourceName = cmpConnectionFactory.getResourceLink();
588 if (datasourceName != null) {
589 jtaDataSource = datasourceName.trim();
590 }
591 }
592 }
593
594 persistenceUnit = new PersistenceUnit();
595 persistenceUnit.setName("cmp");
596 persistenceUnit.setTransactionType(TransactionType.JTA);
597 if (jtaDataSource != null) {
598 persistenceUnit.setJtaDataSource(jtaDataSource);
599 } else {
600 persistenceUnit.setJtaDataSource(defaultCmpJTADataSource);
601 }
602 persistenceUnit.setNonJtaDataSource(defaultCmpNonJTADataSource);
603 persistenceUnit.setExcludeUnlistedClasses(true);
604
605 Persistence persistence = new Persistence();
606 persistence.setVersion("1.0");
607 persistence.getPersistenceUnit().add(persistenceUnit);
608
609 geronimoEjbJarType.getPersistence().add(persistence);
610 }
611 persistenceUnit.getMappingFile().add("META-INF/openejb-cmp-generated-orm.xml");
612 }
613
614 /**
615 * Does the meaty work of processing the deployment information and
616 * creating GBeans for all the EJBs in the JAR, etc.
617 */
618 public void addGBeans(EARContext earContext, Module module, ClassLoader cl, Collection repositories) throws DeploymentException {
619 EjbModule ejbModule = (EjbModule) module;
620 EjbDeploymentBuilder ejbDeploymentBuilder = ejbModule.getEjbBuilder();
621
622 // add enc
623 ejbDeploymentBuilder.buildEnc();
624
625 // Add JSR77 EJBModule GBean
626 GBeanData ejbModuleGBeanData = new GBeanData(ejbModule.getModuleName(), EjbModuleImplGBean.GBEAN_INFO);
627 try {
628 ejbModuleGBeanData.setReferencePattern("J2EEServer", earContext.getServerName());
629 if (!ejbModule.isStandAlone()) {
630 ejbModuleGBeanData.setReferencePattern("J2EEApplication", earContext.getModuleName());
631 }
632
633 ejbModuleGBeanData.setAttribute("deploymentDescriptor", ejbModule.getOriginalSpecDD());
634
635 ejbModuleGBeanData.setReferencePatterns("EJBCollection",
636 new ReferencePatterns(new AbstractNameQuery(null,
637 Collections.singletonMap(NameFactory.EJB_MODULE, ejbModule.getModuleName().getNameProperty(NameFactory.J2EE_NAME)),
638 EjbDeployment.class.getName())));
639
640 ejbModuleGBeanData.setReferencePattern("OpenEjbSystem", new AbstractNameQuery(null, Collections.EMPTY_MAP, OpenEjbSystem.class.getName()));
641 ejbModuleGBeanData.setAttribute("ejbJarInfo", ejbModule.getEjbJarInfo());
642
643 earContext.addGBean(ejbModuleGBeanData);
644 } catch (Exception e) {
645 throw new DeploymentException("Unable to initialize EJBModule GBean " + ejbModuleGBeanData.getAbstractName(), e);
646 }
647
648 // add a depdendency on the ejb module object
649 ejbDeploymentBuilder.addEjbModuleDependency(ejbModuleGBeanData.getAbstractName());
650
651 // add the Jacc permissions to the ear
652 ComponentPermissions componentPermissions = ejbDeploymentBuilder.buildComponentPermissions();
653 earContext.addSecurityContext(ejbModule.getEjbJarInfo().moduleId, componentPermissions);
654
655 setMdbContainerIds(earContext, ejbModule, ejbModuleGBeanData);
656
657 for (ModuleBuilderExtension builder : moduleBuilderExtensions) {
658 try {
659 builder.addGBeans(earContext, module, cl, repositories);
660 } catch (Throwable t) {
661 String builderName = builder.getClass().getSimpleName();
662 log.error(builderName + ".addGBeans() failed: " + t.getMessage(), t);
663 }
664 }
665 }
666
667 private void setMdbContainerIds(EARContext earContext, EjbModule ejbModule, GBeanData ejbModuleGBeanData) throws DeploymentException {
668 Object altDD = ejbModule.getEjbModule().getAltDDs().get("openejb-jar.xml");
669 if (!(altDD instanceof OpenejbJarType)) {
670 return;
671 }
672 OpenejbJarType openejbJarType = (OpenejbJarType) altDD;
673 EjbJarInfo ejbJarInfo = ejbModule.getEjbJarInfo();
674
675 Map<String, MessageDrivenBeanInfo> mdbs = new TreeMap<String, MessageDrivenBeanInfo>();
676 for (EnterpriseBeanInfo enterpriseBean : ejbJarInfo.enterpriseBeans) {
677 if (enterpriseBean instanceof MessageDrivenBeanInfo) {
678 mdbs.put(enterpriseBean.ejbName, (MessageDrivenBeanInfo) enterpriseBean);
679 }
680 }
681 for (org.apache.openejb.jee.oejb2.EnterpriseBean enterpriseBean : openejbJarType.getEnterpriseBeans()) {
682 if (!(enterpriseBean instanceof MessageDrivenBeanType)) {
683 continue;
684 }
685 MessageDrivenBeanType bean = (MessageDrivenBeanType) enterpriseBean;
686 MessageDrivenBeanInfo messageDrivenBeanInfo = mdbs.get(bean.getEjbName());
687 if (messageDrivenBeanInfo == null) {
688 continue;
689 }
690 if (messageDrivenBeanInfo.containerId != null) {
691 // containerId already set
692 continue;
693 }
694
695 if (bean.getResourceAdapter() == null) {
696 throw new DeploymentException("Resource Adapter defined for MDB '" + bean.getEjbName() + "'");
697 }
698
699 AbstractNameQuery resourceAdapterNameQuery = getResourceAdapterNameQuery(bean.getResourceAdapter());
700 AbstractName resourceAdapterAbstractName = null;
701 try {
702 resourceAdapterAbstractName = earContext.findGBean(resourceAdapterNameQuery);
703 } catch (GBeanNotFoundException e) {
704 throw new DeploymentException("Resource Adapter for MDB '" + bean.getEjbName() + "'not found: " + resourceAdapterNameQuery, e);
705 }
706
707 Map properties = resourceAdapterAbstractName.getName();
708 String shortName = (String) properties.get("name");
709 String moduleName = (String) properties.get("ResourceAdapterModule");
710 if (shortName != null && moduleName != null) {
711 messageDrivenBeanInfo.containerId = moduleName + "." + shortName + "-" + messageDrivenBeanInfo.mdbInterface;
712 } else {
713 messageDrivenBeanInfo.containerId = resourceAdapterAbstractName.getObjectName().toString() + "-" + messageDrivenBeanInfo.mdbInterface;
714 }
715
716 // add a dependency from the module to the ra so we can be assured the mdb
717 // container exists when this app is started
718 ejbModuleGBeanData.addDependency(resourceAdapterAbstractName);
719 }
720 }
721
722 private static AbstractNameQuery getResourceAdapterNameQuery(ResourceLocatorType resourceLocator) {
723 if (resourceLocator.getResourceLink() != null) {
724 Map<String, String> nameMap = new HashMap<String, String>();
725 nameMap.put("name", resourceLocator.getResourceLink());
726 nameMap.put("j2eeType", NameFactory.JCA_RESOURCE_ADAPTER);
727 return new AbstractNameQuery(null, nameMap);
728 }
729
730 //construct name from components
731 PatternType pattern = resourceLocator.getPattern();
732 Artifact artifact = null;
733 if (pattern.getArtifactId() != null) {
734 artifact = new Artifact(pattern.getGroupId(), pattern.getArtifactId(), pattern.getVersion(), "car");
735 }
736
737 Map<String, String> nameMap = new HashMap<String, String>();
738 nameMap.put("name", pattern.getName());
739 nameMap.put("j2eeType", NameFactory.JCA_RESOURCE_ADAPTER);
740 if (pattern.getModule() != null) {
741 nameMap.put(NameFactory.RESOURCE_ADAPTER_MODULE, pattern.getModule());
742 }
743 return new AbstractNameQuery(artifact, nameMap, (Set)null);
744 }
745
746 public static class EarData {
747 private final Map<String, EjbModule> ejbModules = new TreeMap<String, EjbModule>();
748 private final Map<String, EjbJarInfo> ejbJars = new TreeMap<String, EjbJarInfo>();
749
750 public void addEjbModule(EjbModule ejbModule) {
751 ejbModules.put(ejbModule.getEjbModule().getModuleId(), ejbModule);
752 }
753
754 public EjbModule getEjbModule(String moduleId) throws DeploymentException {
755 EjbModule ejbModule = ejbModules.get(moduleId);
756 if (ejbModule == null) {
757 throw new DeploymentException("Ejb module " + moduleId + " was not found in configured module list " + ejbModules.keySet());
758 }
759 return ejbModule;
760 }
761
762 public Collection<EjbModule> getEjbModuels() {
763 return ejbModules.values();
764 }
765
766 public void addEjbJar(EjbJarInfo ejbJarInfo) {
767 ejbJars.put(ejbJarInfo.moduleId, ejbJarInfo);
768 }
769
770 public EjbJarInfo getEjbJar(String moduleId) throws DeploymentException {
771 EjbJarInfo ejbJarInfo = ejbJars.get(moduleId);
772 if (ejbJarInfo == null) {
773 throw new DeploymentException("Ejb jar configuration passed but expected module " +
774 moduleId + " was not found in configured module list " + ejbJars.keySet());
775 }
776 return ejbJarInfo;
777 }
778
779 public Collection<EjbJarInfo> getEjbJars() {
780 return ejbJars.values();
781 }
782 }
783
784
785 public static final GBeanInfo GBEAN_INFO;
786
787 static {
788 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(EjbModuleBuilder.class, NameFactory.MODULE_BUILDER);
789 infoBuilder.addAttribute("defaultEnvironment", Environment.class, true);
790 infoBuilder.addAttribute("defaultCmpJTADataSource", String.class, true);
791 infoBuilder.addAttribute("defaultCmpNonJTADataSource", String.class, true);
792 infoBuilder.addReference("OpenEjbSystem", OpenEjbSystem.class);
793 infoBuilder.addReference("ModuleBuilderExtensions", ModuleBuilderExtension.class, NameFactory.MODULE_BUILDER);
794 infoBuilder.addReference("SecurityBuilders", NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER);
795 infoBuilder.addReference("ServiceBuilders", NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER);
796 infoBuilder.addReference("NamingBuilders", NamingBuilder.class, NameFactory.MODULE_BUILDER);
797 infoBuilder.addReference("ResourceEnvironmentSetter", ResourceEnvironmentSetter.class, NameFactory.MODULE_BUILDER);
798
799 infoBuilder.setConstructor(new String[]{
800 "defaultEnvironment",
801 "defaultCmpJTADataSource",
802 "defaultCmpNonJTADataSource",
803 "OpenEjbSystem",
804 "ModuleBuilderExtensions",
805 "SecurityBuilders",
806 "ServiceBuilders",
807 "NamingBuilders",
808 "ResourceEnvironmentSetter"});
809 GBEAN_INFO = infoBuilder.getBeanInfo();
810 }
811
812 public static GBeanInfo getGBeanInfo() {
813 return GBEAN_INFO;
814 }
815
816 }