001    /**
002     *
003     *  Licensed to the Apache Software Foundation (ASF) under one or more
004     *  contributor license agreements.  See the NOTICE file distributed with
005     *  this work for additional information regarding copyright ownership.
006     *  The ASF licenses this file to You under the Apache License, Version 2.0
007     *  (the "License"); you may not use this file except in compliance with
008     *  the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    package org.apache.geronimo.j2ee.deployment;
019    
020    import java.io.File;
021    import java.io.IOException;
022    import java.net.MalformedURLException;
023    import java.net.URI;
024    import java.net.URL;
025    import java.util.ArrayList;
026    import java.util.Collection;
027    import java.util.Collections;
028    import java.util.Enumeration;
029    import java.util.HashMap;
030    import java.util.HashSet;
031    import java.util.Iterator;
032    import java.util.LinkedHashMap;
033    import java.util.LinkedHashSet;
034    import java.util.LinkedList;
035    import java.util.List;
036    import java.util.Map;
037    import java.util.Set;
038    import java.util.jar.JarFile;
039    import java.util.zip.ZipEntry;
040    
041    import javax.xml.namespace.QName;
042    
043    import org.apache.commons.logging.Log;
044    import org.apache.commons.logging.LogFactory;
045    import org.apache.geronimo.common.DeploymentException;
046    import org.apache.geronimo.deployment.ConfigurationBuilder;
047    import org.apache.geronimo.deployment.DeploymentContext;
048    import org.apache.geronimo.deployment.ModuleIDBuilder;
049    import org.apache.geronimo.deployment.NamespaceDrivenBuilder;
050    import org.apache.geronimo.deployment.NamespaceDrivenBuilderCollection;
051    import org.apache.geronimo.deployment.service.EnvironmentBuilder;
052    import org.apache.geronimo.deployment.util.DeploymentUtil;
053    import org.apache.geronimo.deployment.util.NestedJarFile;
054    import org.apache.geronimo.deployment.xbeans.ArtifactType;
055    import org.apache.geronimo.deployment.xbeans.EnvironmentType;
056    import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
057    import org.apache.geronimo.gbean.AbstractName;
058    import org.apache.geronimo.gbean.AbstractNameQuery;
059    import org.apache.geronimo.gbean.GBeanData;
060    import org.apache.geronimo.gbean.GBeanInfo;
061    import org.apache.geronimo.gbean.GBeanInfoBuilder;
062    import org.apache.geronimo.gbean.ReferencePatterns;
063    import org.apache.geronimo.gbean.SingleElementCollection;
064    import org.apache.geronimo.j2ee.ApplicationInfo;
065    import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
066    import org.apache.geronimo.j2ee.management.impl.J2EEApplicationImpl;
067    import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
068    import org.apache.geronimo.kernel.Kernel;
069    import org.apache.geronimo.kernel.Naming;
070    import org.apache.geronimo.kernel.config.ConfigurationAlreadyExistsException;
071    import org.apache.geronimo.kernel.config.ConfigurationData;
072    import org.apache.geronimo.kernel.config.ConfigurationManager;
073    import org.apache.geronimo.kernel.config.ConfigurationModuleType;
074    import org.apache.geronimo.kernel.config.ConfigurationStore;
075    import org.apache.geronimo.kernel.config.ConfigurationUtil;
076    import org.apache.geronimo.kernel.config.SimpleConfigurationManager;
077    import org.apache.geronimo.kernel.repository.Artifact;
078    import org.apache.geronimo.kernel.repository.ArtifactResolver;
079    import org.apache.geronimo.kernel.repository.Environment;
080    import org.apache.geronimo.kernel.repository.Repository;
081    import org.apache.geronimo.management.J2EEResource;
082    import org.apache.geronimo.management.J2EEServer;
083    import org.apache.geronimo.schema.SchemaConversionUtils;
084    import org.apache.geronimo.xbeans.geronimo.j2ee.GerApplicationDocument;
085    import org.apache.geronimo.xbeans.geronimo.j2ee.GerApplicationType;
086    import org.apache.geronimo.xbeans.geronimo.j2ee.GerExtModuleType;
087    import org.apache.geronimo.xbeans.geronimo.j2ee.GerModuleType;
088    import org.apache.geronimo.xbeans.j2ee.ApplicationType;
089    import org.apache.geronimo.xbeans.j2ee.ModuleType;
090    import org.apache.geronimo.xbeans.j2ee.ApplicationDocument;
091    import org.apache.xmlbeans.XmlException;
092    import org.apache.xmlbeans.XmlObject;
093    import org.apache.xmlbeans.XmlCursor;
094    
095    /**
096     * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
097     */
098    public class EARConfigBuilder implements ConfigurationBuilder, CorbaGBeanNameSource {
099    
100        private static final Log log = LogFactory.getLog(EARConfigBuilder.class);
101        private static final String LINE_SEP = System.getProperty("line.separator");
102    
103        private final static QName APPLICATION_QNAME = GerApplicationDocument.type.getDocumentElementName();
104    
105        private final ConfigurationManager configurationManager;
106        private final Collection repositories;
107        private final SingleElementCollection ejbConfigBuilder;
108        private final SingleElementCollection webConfigBuilder;
109        private final SingleElementCollection connectorConfigBuilder;
110        private final SingleElementCollection appClientConfigBuilder;
111        private final SingleElementCollection resourceReferenceBuilder;
112        private final NamespaceDrivenBuilderCollection securityBuilders;
113        private final NamespaceDrivenBuilderCollection serviceBuilders;
114    
115        private final Environment defaultEnvironment;
116        private final AbstractNameQuery serverName;
117        private final AbstractNameQuery transactionManagerObjectName;
118        private final AbstractNameQuery connectionTrackerObjectName;
119        private final AbstractNameQuery transactionalTimerObjectName;
120        private final AbstractNameQuery nonTransactionalTimerObjectName;
121        private final AbstractNameQuery corbaGBeanObjectName;
122        private final Naming naming;
123    
124        public EARConfigBuilder(Environment defaultEnvironment,
125                AbstractNameQuery transactionManagerAbstractName,
126                AbstractNameQuery connectionTrackerAbstractName,
127                AbstractNameQuery transactionalTimerAbstractName,
128                AbstractNameQuery nonTransactionalTimerAbstractName,
129                AbstractNameQuery corbaGBeanAbstractName,
130                AbstractNameQuery serverName,
131                Collection repositories,
132                Collection ejbConfigBuilder,
133                Collection webConfigBuilder,
134                Collection connectorConfigBuilder,
135                Collection resourceReferenceBuilder,
136                Collection appClientConfigBuilder,
137                Collection securityBuilders,
138                Collection serviceBuilders,
139                Kernel kernel) {
140            this(defaultEnvironment,
141                    transactionManagerAbstractName,
142                    connectionTrackerAbstractName,
143                    transactionalTimerAbstractName,
144                    nonTransactionalTimerAbstractName,
145                    corbaGBeanAbstractName,
146                    serverName,
147                    ConfigurationUtil.getConfigurationManager(kernel),
148                    repositories,
149                    new SingleElementCollection(ejbConfigBuilder),
150                    new SingleElementCollection(webConfigBuilder),
151                    new SingleElementCollection(connectorConfigBuilder),
152                    new SingleElementCollection(resourceReferenceBuilder),
153                    new SingleElementCollection(appClientConfigBuilder),
154                    securityBuilders,
155                    serviceBuilders,
156                    kernel.getNaming());
157        }
158        public EARConfigBuilder(Environment defaultEnvironment,
159                AbstractNameQuery transactionManagerAbstractName,
160                AbstractNameQuery connectionTrackerAbstractName,
161                AbstractNameQuery transactionalTimerAbstractName,
162                AbstractNameQuery nonTransactionalTimerAbstractName,
163                AbstractNameQuery corbaGBeanAbstractName,
164                AbstractNameQuery serverName,
165                Collection repositories,
166                ModuleBuilder ejbConfigBuilder,
167                ModuleBuilder webConfigBuilder,
168                ModuleBuilder connectorConfigBuilder,
169                ActivationSpecInfoLocator activationSpecInfoLocator,
170                ModuleBuilder appClientConfigBuilder,
171                NamespaceDrivenBuilder securityBuilder,
172                NamespaceDrivenBuilder serviceBuilder,
173                Naming naming) {
174            this(defaultEnvironment,
175                    transactionManagerAbstractName,
176                    connectionTrackerAbstractName,
177                    transactionalTimerAbstractName,
178                    nonTransactionalTimerAbstractName,
179                    corbaGBeanAbstractName,
180                    serverName,
181                    null,
182                    repositories,
183                    new SingleElementCollection(ejbConfigBuilder),
184                    new SingleElementCollection(webConfigBuilder),
185                    new SingleElementCollection(connectorConfigBuilder),
186                    new SingleElementCollection(activationSpecInfoLocator),
187                    new SingleElementCollection(appClientConfigBuilder),
188                    securityBuilder == null? Collections.EMPTY_SET: Collections.singleton(securityBuilder),
189                    serviceBuilder == null? Collections.EMPTY_SET: Collections.singleton(serviceBuilder),
190                    naming);
191        }
192    
193        private EARConfigBuilder(Environment defaultEnvironment,
194                AbstractNameQuery transactionManagerAbstractName,
195                AbstractNameQuery connectionTrackerAbstractName,
196                AbstractNameQuery transactionalTimerAbstractName,
197                AbstractNameQuery nonTransactionalTimerAbstractName,
198                AbstractNameQuery corbaGBeanAbstractName,
199                AbstractNameQuery serverName,
200                ConfigurationManager configurationManager,
201                Collection repositories,
202                SingleElementCollection ejbConfigBuilder,
203                SingleElementCollection webConfigBuilder,
204                SingleElementCollection connectorConfigBuilder,
205                SingleElementCollection resourceReferenceBuilder,
206                SingleElementCollection appClientConfigBuilder,
207                Collection securityBuilders,
208                Collection serviceBuilders,
209                Naming naming) {
210            this.configurationManager = configurationManager;
211            this.repositories = repositories;
212            this.defaultEnvironment = defaultEnvironment;
213    
214            this.ejbConfigBuilder = ejbConfigBuilder;
215            this.resourceReferenceBuilder = resourceReferenceBuilder;
216            this.webConfigBuilder = webConfigBuilder;
217            this.connectorConfigBuilder = connectorConfigBuilder;
218            this.appClientConfigBuilder = appClientConfigBuilder;
219            this.securityBuilders = new NamespaceDrivenBuilderCollection(securityBuilders);
220            this.serviceBuilders = new NamespaceDrivenBuilderCollection(serviceBuilders);
221    
222            this.transactionManagerObjectName = transactionManagerAbstractName;
223            this.connectionTrackerObjectName = connectionTrackerAbstractName;
224            this.transactionalTimerObjectName = transactionalTimerAbstractName;
225            this.nonTransactionalTimerObjectName = nonTransactionalTimerAbstractName;
226            this.corbaGBeanObjectName = corbaGBeanAbstractName;
227            this.serverName = serverName;
228            this.naming = naming;
229        }
230    
231    
232        public AbstractNameQuery getCorbaGBeanName() {
233            return corbaGBeanObjectName;
234        }
235    
236        private ModuleBuilder getEjbConfigBuilder() {
237            return (ModuleBuilder) ejbConfigBuilder.getElement();
238        }
239    
240        private ModuleBuilder getWebConfigBuilder() {
241            return (ModuleBuilder) webConfigBuilder.getElement();
242        }
243    
244        private ModuleBuilder getConnectorConfigBuilder() {
245            return (ModuleBuilder) connectorConfigBuilder.getElement();
246        }
247    
248        private ModuleBuilder getAppClientConfigBuilder() {
249            return (ModuleBuilder) appClientConfigBuilder.getElement();
250        }
251    
252        private ActivationSpecInfoLocator getResourceReferenceBuilder() {
253            return (ActivationSpecInfoLocator) resourceReferenceBuilder.getElement();
254        }
255    
256        public Object getDeploymentPlan(File planFile, JarFile jarFile, ModuleIDBuilder idBuilder) throws DeploymentException {
257            if (planFile == null && jarFile == null) {
258                return null;
259            }
260            ApplicationInfo plan = getEarPlan(planFile, jarFile, idBuilder);
261            if (plan != null) {
262                return plan;
263            }
264            //Only "synthetic" ears with only external modules can have no jar file.
265            if (jarFile == null) {
266                return null;
267            }
268    
269            // get the modules either the application plan or for a stand alone module from the specific deployer
270            Module module = null;
271            if (getWebConfigBuilder() != null) {
272                module = getWebConfigBuilder().createModule(planFile, jarFile, naming, idBuilder);
273            }
274            if (module == null && getEjbConfigBuilder() != null) {
275                module = getEjbConfigBuilder().createModule(planFile, jarFile, naming, idBuilder);
276            }
277            if (module == null && getConnectorConfigBuilder() != null) {
278                module = getConnectorConfigBuilder().createModule(planFile, jarFile, naming, idBuilder);
279            }
280            if (module == null && getAppClientConfigBuilder() != null) {
281                module = getAppClientConfigBuilder().createModule(planFile, jarFile, naming, idBuilder);
282            }
283            if (module == null) {
284                return null;
285            }
286    
287            return new ApplicationInfo(module.getType(),
288                    module.getEnvironment(),
289                    module.getModuleName(),
290                    null,
291                    null,
292                    new LinkedHashSet(Collections.singleton(module)),
293                    Collections.EMPTY_SET,
294                    null);
295        }
296    
297        private ApplicationInfo getEarPlan(File planFile, JarFile earFile, ModuleIDBuilder idBuilder) throws DeploymentException {
298            String specDD;
299            ApplicationType application = null;
300            if (earFile != null) {
301                try {
302                    URL applicationXmlUrl = DeploymentUtil.createJarURL(earFile, "META-INF/application.xml");
303                    specDD = DeploymentUtil.readAll(applicationXmlUrl);
304                } catch (Exception e) {
305                    //no application.xml, not for us
306                    return null;
307                }
308                //we found something called application.xml in the right place, if we can't parse it it's an error
309                try {
310                    XmlObject xmlObject = XmlBeansUtil.parse(specDD);
311                    application = convertToApplicationSchema(xmlObject).getApplication();
312                } catch (XmlException e) {
313                    throw new DeploymentException("Could not parse application.xml", e);
314                }
315            }
316    
317            GerApplicationType gerApplication = null;
318            try {
319                // load the geronimo-application.xml from either the supplied plan or from the earFile
320                XmlObject rawPlan;
321                try {
322                    if (planFile != null) {
323                        rawPlan = XmlBeansUtil.parse(planFile.toURL(), getClass().getClassLoader());
324                        gerApplication = (GerApplicationType) SchemaConversionUtils.fixGeronimoSchema(rawPlan, APPLICATION_QNAME, GerApplicationType.type);
325                        if (gerApplication == null) {
326                            return null;
327                        }
328                    } else {
329                        URL path = DeploymentUtil.createJarURL(earFile, "META-INF/geronimo-application.xml");
330                        rawPlan = XmlBeansUtil.parse(path, getClass().getClassLoader());
331                        gerApplication = (GerApplicationType) SchemaConversionUtils.fixGeronimoSchema(rawPlan, APPLICATION_QNAME, GerApplicationType.type);
332                    }
333                } catch (IOException e) {
334                    //TODO isn't this an error?
335                }
336    
337                // if we got one extract the validate it otherwise create a default one
338                if (gerApplication == null) {
339                    gerApplication = createDefaultPlan(application, earFile);
340                }
341            } catch (XmlException e) {
342                throw new DeploymentException(e);
343            }
344    
345            EnvironmentType environmentType = gerApplication.getEnvironment();
346            Environment environment = EnvironmentBuilder.buildEnvironment(environmentType, defaultEnvironment);
347            idBuilder.resolve(environment, earFile == null ? planFile.getName() : new File(earFile.getName()).getName(), "ear");
348            // Make this EAR's settings the default for child modules
349            idBuilder.setDefaultGroup(environment.getConfigId().getGroupId());
350            idBuilder.setDefaultVersion(environment.getConfigId().getVersion());
351    
352            Artifact artifact = environment.getConfigId();
353            AbstractName earName = naming.createRootName(artifact, artifact.toString(), NameFactory.J2EE_APPLICATION);
354    
355            // get the modules either the application plan or for a stand alone module from the specific deployer
356            // todo change module so you can extract the real module path back out.. then we can eliminate
357            // the moduleLocations and have addModules return the modules
358            Set moduleLocations = new HashSet();
359            LinkedHashSet modules = new LinkedHashSet();
360            try {
361                addModules(earFile, application, gerApplication, moduleLocations, modules, environment, earName, idBuilder);
362            } catch (Throwable e) {
363                // close all the modules
364                for (Iterator iterator = modules.iterator(); iterator.hasNext();) {
365                    Module module = (Module) iterator.next();
366                    module.close();
367                }
368    
369                if (e instanceof DeploymentException) {
370                    throw (DeploymentException) e;
371                } else if (e instanceof RuntimeException) {
372                    throw (RuntimeException) e;
373                } else if (e instanceof Error) {
374                    throw (Error) e;
375                }
376                throw new DeploymentException(e);
377            }
378    
379            return new ApplicationInfo(ConfigurationModuleType.EAR,
380                    environment,
381                    earName,
382                    application,
383                    gerApplication,
384                    modules,
385                    moduleLocations,
386                    application == null ? null : application.toString());
387        }
388    
389    
390        private GerApplicationType createDefaultPlan(ApplicationType application, JarFile module) {
391            // construct the empty geronimo-application.xml
392            GerApplicationType gerApplication = GerApplicationType.Factory.newInstance();
393            EnvironmentType environmentType = gerApplication.addNewEnvironment();
394            ArtifactType artifactType = environmentType.addNewModuleId();
395    
396            artifactType.setGroupId(Artifact.DEFAULT_GROUP_ID);
397    
398            // set the configId
399            String id = application.getId();
400            if (id == null) {
401                File fileName = new File(module.getName());
402                id = fileName.getName();
403                if (id.endsWith(".ear")) {
404                    id = id.substring(0, id.length() - 4);
405                }
406                if (id.endsWith("/")) {
407                    id = id.substring(0, id.length() - 1);
408                }
409            }
410    
411            artifactType.setArtifactId(id);
412            artifactType.setVersion("" + System.currentTimeMillis());
413            artifactType.setType("car");
414            return gerApplication;
415        }
416    
417        static ApplicationDocument convertToApplicationSchema(XmlObject xmlObject) throws XmlException {
418            if (ApplicationDocument.type.equals(xmlObject.schemaType())) {
419                XmlBeansUtil.validateDD(xmlObject);
420                return (ApplicationDocument) xmlObject;
421            }
422            XmlCursor cursor = xmlObject.newCursor();
423            XmlCursor moveable = xmlObject.newCursor();
424            String schemaLocationURL = "http://java.sun.com/xml/ns/j2ee/application_1_4.xsd";
425            String version = "1.4";
426            try {
427                SchemaConversionUtils.convertToSchema(cursor, SchemaConversionUtils.J2EE_NAMESPACE, schemaLocationURL, version);
428                cursor.toStartDoc();
429                cursor.toChild(SchemaConversionUtils.J2EE_NAMESPACE, "application");
430                cursor.toFirstChild();
431                SchemaConversionUtils.convertToDescriptionGroup(SchemaConversionUtils.J2EE_NAMESPACE, cursor, moveable);
432            } finally {
433                cursor.dispose();
434                moveable.dispose();
435            }
436            XmlObject result = xmlObject.changeType(ApplicationDocument.type);
437            if (result != null) {
438                XmlBeansUtil.validateDD(result);
439                return (ApplicationDocument) result;
440            }
441            XmlBeansUtil.validateDD(xmlObject);
442            return (ApplicationDocument) xmlObject;
443        }
444    
445        public Artifact getConfigurationID(Object plan, JarFile module, ModuleIDBuilder idBuilder) throws IOException, DeploymentException {
446            ApplicationInfo applicationInfo = (ApplicationInfo) plan;
447            Artifact test = applicationInfo.getEnvironment().getConfigId();
448            if(!test.isResolved()) {
449                throw new IllegalStateException("Module ID should be fully resolved by now (not "+test+")");
450            }
451            return test;
452        }
453    
454        public DeploymentContext buildConfiguration(boolean inPlaceDeployment, Artifact configId, Object plan, JarFile earFile, Collection configurationStores, ArtifactResolver artifactResolver, ConfigurationStore targetConfigurationStore) throws IOException, DeploymentException {
455            assert plan != null;
456            ApplicationInfo applicationInfo = (ApplicationInfo) plan;
457    
458            EARContext earContext = null;
459            ConfigurationModuleType applicationType = applicationInfo.getType();
460            applicationInfo.getEnvironment().setConfigId(configId);
461            File configurationDir;
462            try {
463                configurationDir = targetConfigurationStore.createNewConfigurationDir(configId);
464            } catch (ConfigurationAlreadyExistsException e) {
465                throw new DeploymentException(e);
466            }
467    
468            ConfigurationManager configurationManager = this.configurationManager;
469            if (configurationManager == null) {
470                configurationManager = new SimpleConfigurationManager(configurationStores, artifactResolver, repositories);
471            }
472            try {
473                // Create the output ear context
474                earContext = new EARContext(configurationDir,
475                        inPlaceDeployment ? DeploymentUtil.toFile(earFile) : null,
476                        applicationInfo.getEnvironment(),
477                        applicationType,
478                        naming,
479                        configurationManager,
480                        repositories,
481                        serverName,
482                        applicationInfo.getBaseName(),
483                        transactionManagerObjectName,
484                        connectionTrackerObjectName,
485                        transactionalTimerObjectName,
486                        nonTransactionalTimerObjectName,
487                        corbaGBeanObjectName
488                );
489    
490                // Copy over all files that are _NOT_ modules (e.g. META-INF and APP-INF files)
491                Set moduleLocations = applicationInfo.getModuleLocations();
492                if (ConfigurationModuleType.EAR == applicationType && earFile != null) {
493                    for (Enumeration e = earFile.entries(); e.hasMoreElements();) {
494                        ZipEntry entry = (ZipEntry) e.nextElement();
495                        String entryName = entry.getName();
496                        boolean addEntry = true;
497                        for (Iterator iter = moduleLocations.iterator(); iter.hasNext();) {
498                            String location = (String) iter.next();
499                            if (entryName.startsWith(location)) {
500                                addEntry = false;
501                                break;
502                            }
503                        }
504                        if (addEntry) {
505                            earContext.addFile(URI.create(entry.getName()), earFile, entry);
506                        }
507                    }
508                }
509    
510                GerApplicationType geronimoApplication = (GerApplicationType) applicationInfo.getVendorDD();
511    
512                // each module installs it's files into the output context.. this is different for each module type
513                LinkedHashSet modules = applicationInfo.getModules();
514                for (Iterator iterator = modules.iterator(); iterator.hasNext();) {
515                    Module module = (Module) iterator.next();
516                    getBuilder(module).installModule(earFile, earContext, module, configurationStores, targetConfigurationStore, repositories);
517                }
518    
519                earContext.flush();
520    
521                // give each module a chance to populate the earContext now that a classloader is available
522                ClassLoader cl = earContext.getClassLoader();
523                for (Iterator iterator = modules.iterator(); iterator.hasNext();) {
524                    Module module = (Module) iterator.next();
525                    getBuilder(module).initContext(earContext, module, cl);
526                }
527    
528                // add gbeans declared in the geronimo-application.xml
529                if (geronimoApplication != null) {
530                    securityBuilders.build(geronimoApplication, earContext, earContext);
531                    serviceBuilders.build(geronimoApplication, earContext, earContext);
532                }
533    
534                // Create the J2EEApplication managed object
535                if (ConfigurationModuleType.EAR == applicationType) {
536                    GBeanData gbeanData = new GBeanData(earContext.getModuleName(), J2EEApplicationImpl.GBEAN_INFO);
537                    try {
538                        String originalSpecDD = applicationInfo.getOriginalSpecDD();
539                        if (originalSpecDD == null) {
540                            originalSpecDD = "Synthetic EAR";
541                        }
542                        gbeanData.setAttribute("deploymentDescriptor", originalSpecDD);
543                    } catch (Exception e) {
544                        throw new DeploymentException("Error initializing J2EEApplication managed object");
545                    }
546                    gbeanData.setReferencePatterns("Server", new ReferencePatterns(new AbstractNameQuery(J2EEServer.class.getName())));
547    
548                    Map thisApp = Collections.singletonMap(NameFactory.J2EE_APPLICATION, earContext.getModuleName().getNameProperty(NameFactory.J2EE_NAME));
549                    LinkedHashSet resourcePatterns = new LinkedHashSet();
550                    resourcePatterns.add(new AbstractNameQuery(null, filter(thisApp, NameFactory.J2EE_TYPE, NameFactory.JAVA_MAIL_RESOURCE), J2EEResource.class.getName()));
551                    resourcePatterns.add(new AbstractNameQuery(null, filter(thisApp, NameFactory.J2EE_TYPE, NameFactory.JCA_CONNECTION_FACTORY), J2EEResource.class.getName()));
552                    resourcePatterns.add(new AbstractNameQuery(null, filter(thisApp, NameFactory.J2EE_TYPE, NameFactory.JDBC_RESOURCE), J2EEResource.class.getName()));
553                    resourcePatterns.add(new AbstractNameQuery(null, filter(thisApp, NameFactory.J2EE_TYPE, NameFactory.JDBC_DRIVER), J2EEResource.class.getName()));
554                    resourcePatterns.add(new AbstractNameQuery(null, filter(thisApp, NameFactory.J2EE_TYPE, NameFactory.JMS_RESOURCE), J2EEResource.class.getName()));
555                    resourcePatterns.add(new AbstractNameQuery(null, filter(thisApp, NameFactory.J2EE_TYPE, NameFactory.JNDI_RESOURCE), J2EEResource.class.getName()));
556                    resourcePatterns.add(new AbstractNameQuery(null, filter(thisApp, NameFactory.J2EE_TYPE, NameFactory.JTA_RESOURCE), J2EEResource.class.getName()));
557                    resourcePatterns.add(new AbstractNameQuery(null, filter(thisApp, NameFactory.J2EE_TYPE, NameFactory.RMI_IIOP_RESOURCE), J2EEResource.class.getName()));
558                    resourcePatterns.add(new AbstractNameQuery(null, filter(thisApp, NameFactory.J2EE_TYPE, NameFactory.URL_RESOURCE), J2EEResource.class.getName()));
559                    gbeanData.setReferencePatterns("Resources", resourcePatterns);
560    
561                    gbeanData.setReferencePatterns("AppClientModules", new ReferencePatterns(new AbstractNameQuery(null, thisApp, org.apache.geronimo.management.AppClientModule.class.getName())));
562                    gbeanData.setReferencePatterns("EJBModules", new ReferencePatterns(new AbstractNameQuery(null, thisApp, org.apache.geronimo.management.EJBModule.class.getName())));
563                    gbeanData.setReferencePatterns("ResourceAdapterModules", new ReferencePatterns(new AbstractNameQuery(null, thisApp, org.apache.geronimo.management.geronimo.ResourceAdapterModule.class.getName())));
564                    gbeanData.setReferencePatterns("WebModules", new ReferencePatterns(new AbstractNameQuery(null, thisApp, org.apache.geronimo.management.geronimo.WebModule.class.getName())));
565                    earContext.addGBean(gbeanData);
566                }
567    
568                // each module can now add it's GBeans
569                for (Iterator iterator = modules.iterator(); iterator.hasNext();) {
570                    Module module = (Module) iterator.next();
571                    getBuilder(module).addGBeans(earContext, module, cl, repositories);
572                }
573    
574                // it's the caller's responsibility to close the context...
575                return earContext;
576            } catch (GBeanAlreadyExistsException e) {
577                cleanupContext(earContext, configurationDir);
578                throw new DeploymentException(e);
579            } catch (IOException e) {
580                cleanupContext(earContext, configurationDir);
581                throw e;
582            } catch (DeploymentException e) {
583                cleanupContext(earContext, configurationDir);
584                throw e;
585            } catch(RuntimeException e) {
586                cleanupContext(earContext, configurationDir);
587                throw e;
588            } catch(Error e) {
589                cleanupContext(earContext, configurationDir);
590                throw e;
591            } finally {
592                Set modules = applicationInfo.getModules();
593                for (Iterator iterator = modules.iterator(); iterator.hasNext();) {
594                    Module module = (Module) iterator.next();
595                    module.close();
596                }
597            }
598        }
599    
600        private void cleanupContext(EARContext earContext, File configurationDir) {
601            List configurations = new ArrayList();
602            if (earContext != null) {
603                configurations.addAll(earContext.getAdditionalDeployment());
604                try {
605                    earContext.close();
606                } catch (IOException ioe) {
607                    // ignore any cleanup problems
608                } catch (DeploymentException de) {
609                    // ignore any cleanup problems
610                }
611            }
612            // configurationDir is created before we create an EARContext
613            if (configurationDir != null) {
614                cleanupConfigurationDir(configurationDir);
615            }
616            // cleanup any other configurations generated (e.g. AppClient config dirs)
617            for (Iterator iterator = configurations.iterator(); iterator.hasNext();) {
618                ConfigurationData configurationData = (ConfigurationData) iterator.next();
619                cleanupConfigurationDir(configurationData.getConfigurationDir());
620            }
621        }
622    
623        private boolean cleanupConfigurationDir(File configurationDir)
624        {
625            LinkedList cannotBeDeletedList = new LinkedList();
626    
627            if (!DeploymentUtil.recursiveDelete(configurationDir,cannotBeDeletedList)) {
628                // Output a message to help user track down file problem
629                log.warn("Unable to delete " + cannotBeDeletedList.size() +
630                        " files while recursively deleting directory "
631                        + configurationDir + LINE_SEP +
632                        "The first file that could not be deleted was:" + LINE_SEP + "  "+
633                        ( !cannotBeDeletedList.isEmpty() ? cannotBeDeletedList.getFirst() : "") );
634                return false;
635            }
636            return true;
637        }
638    
639        private static Map filter(Map original, String key, String value) {
640            LinkedHashMap filter = new LinkedHashMap(original);
641            filter.put(key, value);
642            return filter;
643        }
644    
645        private void addModules(JarFile earFile, ApplicationType application, GerApplicationType gerApplication, Set moduleLocations, LinkedHashSet modules, Environment environment, AbstractName earName, ModuleIDBuilder idBuilder) throws DeploymentException {
646            Map altVendorDDs = new HashMap();
647            try {
648                if (earFile != null) {
649                    ModuleType[] moduleTypes = application.getModuleArray();
650                    //paths is used to check that all modules in the geronimo plan are in the application.xml.
651                    Set paths = new HashSet();
652                    for (int i = 0; i < moduleTypes.length; i++) {
653                        ModuleType type = moduleTypes[i];
654                        if (type.isSetEjb()) {
655                            paths.add(type.getEjb().getStringValue());
656                        } else if (type.isSetWeb()) {
657                            paths.add(type.getWeb().getWebUri().getStringValue());
658                        } else if (type.isSetConnector()) {
659                            paths.add(type.getConnector().getStringValue());
660                        } else if (type.isSetJava()) {
661                            paths.add(type.getJava().getStringValue());
662                        }
663                    }
664    
665                    // build map from module path to alt vendor dd
666                    GerModuleType gerModuleTypes[] = gerApplication.getModuleArray();
667                    for (int i = 0; i < gerModuleTypes.length; i++) {
668                        GerModuleType gerModule = gerModuleTypes[i];
669                        String path = null;
670                        if (gerModule.isSetEjb()) {
671                            path = gerModule.getEjb().getStringValue();
672                        } else if (gerModule.isSetWeb()) {
673                            path = gerModule.getWeb().getStringValue();
674                        } else if (gerModule.isSetConnector()) {
675                            path = gerModule.getConnector().getStringValue();
676                        } else if (gerModule.isSetJava()) {
677                            path = gerModule.getJava().getStringValue();
678                        }
679                        if (!paths.contains(path)) {
680                            throw new DeploymentException("Geronimo deployment plan refers to module '" + path + "' but that was not defined in the META-INF/application.xml");
681                        }
682    
683                        if (gerModule.isSetAltDd()) {
684                            // the the url of the alt dd
685                            try {
686                                altVendorDDs.put(path, DeploymentUtil.toTempFile(earFile, gerModule.getAltDd().getStringValue()));
687                            } catch (IOException e) {
688                                throw new DeploymentException("Invalid alt vendor dd url: " + gerModule.getAltDd().getStringValue(), e);
689                            }
690                        } else {
691                            //dd is included explicitly
692                            XmlObject[] anys = gerModule.selectChildren(GerModuleType.type.qnameSetForWildcardElements());
693                            if (anys.length != 1) {
694                                throw new DeploymentException("Unexpected count of xs:any elements in embedded vendor plan " + anys.length + " qnameset: " + GerModuleType.type.qnameSetForWildcardElements());
695                            }
696                            altVendorDDs.put(path, anys[0]);
697                        }
698                    }
699    
700                    // get a set containing all of the files in the ear that are actually modules
701                    for (int i = 0; i < moduleTypes.length; i++) {
702                        ModuleType moduleXml = moduleTypes[i];
703    
704                        String modulePath;
705                        ModuleBuilder builder;
706    
707                        Object moduleContextInfo = null;
708                        String moduleTypeName;
709                        if (moduleXml.isSetEjb()) {
710                            modulePath = moduleXml.getEjb().getStringValue();
711                            builder = getEjbConfigBuilder();
712                            if (builder == null) {
713                                throw new DeploymentException("Cannot deploy ejb application; No ejb deployer defined: " + modulePath);
714                            }
715                            moduleTypeName = "an EJB";
716                        } else if (moduleXml.isSetWeb()) {
717                            modulePath = moduleXml.getWeb().getWebUri().getStringValue();
718                            if (getWebConfigBuilder() == null) {
719                                throw new DeploymentException("Cannot deploy web application; No war deployer defined: " + modulePath);
720                            }
721                            builder = getWebConfigBuilder();
722                            moduleTypeName = "a war";
723                            moduleContextInfo = moduleXml.getWeb().getContextRoot().getStringValue().trim();
724                        } else if (moduleXml.isSetConnector()) {
725                            modulePath = moduleXml.getConnector().getStringValue();
726                            if (getConnectorConfigBuilder() == null) {
727                                throw new DeploymentException("Cannot deploy resource adapter; No rar deployer defined: " + modulePath);
728                            }
729                            builder = getConnectorConfigBuilder();
730                            moduleTypeName = "a connector";
731                        } else if (moduleXml.isSetJava()) {
732                            modulePath = moduleXml.getJava().getStringValue();
733                            if (getAppClientConfigBuilder() == null) {
734                                throw new DeploymentException("Cannot deploy app client; No app client deployer defined: " + modulePath);
735                            }
736                            builder = getAppClientConfigBuilder();
737                            moduleTypeName = "an application client";
738                        } else {
739                            throw new DeploymentException("Could not find a module builder for module: " + moduleXml);
740                        }
741    
742                        moduleLocations.add(modulePath);
743    
744                        URL altSpecDD = null;
745                        if (moduleXml.isSetAltDd()) {
746                            try {
747                                altSpecDD = DeploymentUtil.createJarURL(earFile, moduleXml.getAltDd().getStringValue());
748                            } catch (MalformedURLException e) {
749                                throw new DeploymentException("Invalid alt sped dd url: " + moduleXml.getAltDd().getStringValue(), e);
750                            }
751                        }
752    
753                        NestedJarFile moduleFile;
754                        try {
755                            moduleFile = new NestedJarFile(earFile, modulePath);
756                        } catch (IOException e) {
757                            throw new DeploymentException("Invalid moduleFile: " + modulePath, e);
758                        }
759    
760                        Module module = builder.createModule(altVendorDDs.get(modulePath),
761                                moduleFile,
762                                modulePath,
763                                altSpecDD,
764                                environment,
765                                moduleContextInfo,
766                                earName,
767                                naming, idBuilder);
768    
769                        if (module == null) {
770                            throw new DeploymentException("Module was not " + moduleTypeName + ": " + modulePath);
771                        }
772    
773                        modules.add(module);
774                    }
775                }
776    
777                //deploy the extension modules
778                GerExtModuleType gerExtModuleTypes[] = gerApplication.getExtModuleArray();
779                for (int i = 0; i < gerExtModuleTypes.length; i++) {
780                    GerExtModuleType gerExtModule = gerExtModuleTypes[i];
781                    String moduleName;
782                    ModuleBuilder builder;
783                    Object moduleContextInfo = null;
784                    String moduleTypeName;
785    
786                    if (gerExtModule.isSetEjb()) {
787                        moduleName = gerExtModule.getEjb().getStringValue();
788                        builder = getEjbConfigBuilder();
789                        if (builder == null) {
790                            throw new DeploymentException("Cannot deploy ejb application; No ejb deployer defined: " + moduleName);
791                        }
792                        moduleTypeName = "an EJB";
793                    } else if (gerExtModule.isSetWeb()) {
794                        moduleName = gerExtModule.getWeb().getStringValue();
795                        if (getWebConfigBuilder() == null) {
796                            throw new DeploymentException("Cannot deploy web application; No war deployer defined: " + moduleName);
797                        }
798                        builder = getWebConfigBuilder();
799                        moduleTypeName = "a war";
800                        //ext modules must use vendor plan to set context-root
801    //                    moduleContextInfo = gerExtModule.getWeb().getContextRoot().getStringValue().trim();
802                    } else if (gerExtModule.isSetConnector()) {
803                        moduleName = gerExtModule.getConnector().getStringValue();
804                        if (getConnectorConfigBuilder() == null) {
805                            throw new DeploymentException("Cannot deploy resource adapter; No rar deployer defined: " + moduleName);
806                        }
807                        builder = getConnectorConfigBuilder();
808                        moduleTypeName = "a connector";
809                    } else if (gerExtModule.isSetJava()) {
810                        moduleName = gerExtModule.getJava().getStringValue();
811                        if (getAppClientConfigBuilder() == null) {
812                            throw new DeploymentException("Cannot deploy app client; No app client deployer defined: " + moduleName);
813                        }
814                        builder = getAppClientConfigBuilder();
815                        moduleTypeName = "an application client";
816                    } else {
817                        throw new DeploymentException("Could not find a module builder for module: " + gerExtModule);
818                    }
819                    //dd is included explicitly
820                    XmlObject[] anys = gerExtModule.selectChildren(GerExtModuleType.type.qnameSetForWildcardElements());
821                    if (anys.length != 1) {
822                        throw new DeploymentException("Unexpected count of xs:any elements in embedded vendor plan " + anys.length + " qnameset: " + GerExtModuleType.type.qnameSetForWildcardElements());
823                    }
824                    Object vendorDD = anys[0];
825    
826                    JarFile moduleFile;
827                    if (gerExtModule.isSetInternalPath()) {
828                        String modulePath = gerExtModule.getInternalPath().trim();
829                        moduleLocations.add(modulePath);
830                        try {
831                            moduleFile = new NestedJarFile(earFile, modulePath);
832                        } catch (IOException e) {
833                            throw new DeploymentException("Invalid moduleFile: " + modulePath, e);
834                        }
835                    } else {
836                        String path = gerExtModule.getExternalPath().trim();
837                        Artifact artifact = Artifact.create(path);
838                        File location = null;
839                        for (Iterator iterator = repositories.iterator(); iterator.hasNext();) {
840                            Repository repository = (Repository) iterator.next();
841                            if (repository.contains(artifact)) {
842                                 location = repository.getLocation(artifact);
843                                break;
844                            }
845                        }
846                        if (location == null) {
847                            throw new DeploymentException(moduleTypeName + " is missing in repositories: " + path);
848                        }
849                        try {
850                            moduleFile = new JarFile(location);
851                        } catch (IOException e) {
852                            throw new DeploymentException("Could not access contents of " + moduleTypeName, e);
853                        }
854    
855                    }
856    
857    
858                    URL altSpecDD = null;
859                    //todo implement an alt-spec-dd element.
860    //                if (moduleXml.isSetAltDd()) {
861    //                    try {
862    //                        altSpecDD = DeploymentUtil.createJarURL(earFile, moduleXml.getAltDd().getStringValue());
863    //                    } catch (MalformedURLException e) {
864    //                        throw new DeploymentException("Invalid alt spec dd url: " + moduleXml.getAltDd().getStringValue(), e);
865    //                    }
866    //                }
867    
868    
869                    Module module = builder.createModule(vendorDD,
870                            moduleFile,
871                            moduleName,
872                            altSpecDD,
873                            environment,
874                            moduleContextInfo,
875                            earName,
876                            naming, idBuilder);
877    
878                    if (module == null) {
879                        throw new DeploymentException("Module was not " + moduleTypeName + ": " + moduleName);
880                    }
881    
882                    modules.add(module);
883                }
884    
885    
886            } finally {
887                // delete all the temp files created for alt vendor dds
888                for (Iterator iterator = altVendorDDs.values().iterator(); iterator.hasNext();) {
889                    Object altVendorDD = iterator.next();
890                    if (altVendorDD instanceof File) {
891                        ((File) altVendorDD).delete();
892                    }
893                }
894            }
895        }
896    
897        private ModuleBuilder getBuilder(Module module) throws DeploymentException {
898            if (module instanceof EJBModule) {
899                if (getEjbConfigBuilder() == null) {
900                    throw new DeploymentException("Cannot deploy ejb application; No ejb deployer defined: " + module.getModuleURI());
901                }
902                return getEjbConfigBuilder();
903            } else if (module instanceof WebModule) {
904                if (getWebConfigBuilder() == null) {
905                    throw new DeploymentException("Cannot deploy web application; No war deployer defined: " + module.getModuleURI());
906                }
907                return getWebConfigBuilder();
908            } else if (module instanceof ConnectorModule) {
909                if (getConnectorConfigBuilder() == null) {
910                    throw new DeploymentException("Cannot deploy resource adapter; No rar deployer defined: " + module.getModuleURI());
911                }
912                return getConnectorConfigBuilder();
913            } else if (module instanceof AppClientModule) {
914                if (getAppClientConfigBuilder() == null) {
915                    throw new DeploymentException("Cannot deploy app client; No app client deployer defined: " + module.getModuleURI());
916                }
917                return getAppClientConfigBuilder();
918            }
919            throw new IllegalArgumentException("Unknown module type: " + module.getClass().getName());
920        }
921    
922        public static final GBeanInfo GBEAN_INFO;
923    
924        static {
925            GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(EARConfigBuilder.class, NameFactory.CONFIG_BUILDER);
926            infoBuilder.addAttribute("defaultEnvironment", Environment.class, true, true);
927            infoBuilder.addAttribute("transactionManagerAbstractName", AbstractNameQuery.class, true);
928            infoBuilder.addAttribute("connectionTrackerAbstractName", AbstractNameQuery.class, true);
929            infoBuilder.addAttribute("transactionalTimerAbstractName", AbstractNameQuery.class, true);
930            infoBuilder.addAttribute("nonTransactionalTimerAbstractName", AbstractNameQuery.class, true);
931            infoBuilder.addAttribute("corbaGBeanAbstractName", AbstractNameQuery.class, true);
932            infoBuilder.addAttribute("serverName", AbstractNameQuery.class, true);
933    
934            infoBuilder.addReference("Repositories", Repository.class, "Repository");
935            infoBuilder.addReference("EJBConfigBuilder", ModuleBuilder.class, NameFactory.MODULE_BUILDER);
936            infoBuilder.addReference("WebConfigBuilder", ModuleBuilder.class, NameFactory.MODULE_BUILDER);
937            infoBuilder.addReference("ConnectorConfigBuilder", ModuleBuilder.class, NameFactory.MODULE_BUILDER);
938            infoBuilder.addReference("ActivationSpecInfoLocator", ActivationSpecInfoLocator.class, NameFactory.MODULE_BUILDER);
939            infoBuilder.addReference("AppClientConfigBuilder", ModuleBuilder.class, NameFactory.MODULE_BUILDER);
940            infoBuilder.addReference("SecurityBuilders", NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER);
941            infoBuilder.addReference("ServiceBuilders", NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER);
942    
943            infoBuilder.addAttribute("kernel", Kernel.class, false);
944    
945            infoBuilder.addInterface(ConfigurationBuilder.class);
946    
947            infoBuilder.setConstructor(new String[]{
948                    "defaultEnvironment",
949                    "transactionManagerAbstractName",
950                    "connectionTrackerAbstractName",
951                    "transactionalTimerAbstractName",
952                    "nonTransactionalTimerAbstractName",
953                    "corbaGBeanAbstractName",
954                    "serverName",
955                    "Repositories",
956                    "EJBConfigBuilder",
957                    "WebConfigBuilder",
958                    "ConnectorConfigBuilder",
959                    "ActivationSpecInfoLocator",
960                    "AppClientConfigBuilder",
961                    "SecurityBuilders",
962                    "ServiceBuilders",
963                    "kernel"
964            });
965    
966            GBEAN_INFO = infoBuilder.getBeanInfo();
967        }
968    
969        public static GBeanInfo getGBeanInfo() {
970            return GBEAN_INFO;
971        }
972    
973    }