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    }