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