View Javadoc

1   /**
2    *
3    *  Licensed to the Apache Software Foundation (ASF) under one or more
4    *  contributor license agreements.  See the NOTICE file distributed with
5    *  this work for additional information regarding copyright ownership.
6    *  The ASF licenses this file to You under the Apache License, Version 2.0
7    *  (the "License"); you may not use this file except in compliance with
8    *  the License.  You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing, software
13   *  distributed under the License is distributed on an "AS IS" BASIS,
14   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *  See the License for the specific language governing permissions and
16   *  limitations under the License.
17   */
18  package org.apache.geronimo.j2ee.deployment;
19  
20  import java.io.File;
21  import java.io.IOException;
22  import java.net.MalformedURLException;
23  import java.net.URI;
24  import java.net.URL;
25  import java.util.ArrayList;
26  import java.util.Collection;
27  import java.util.Collections;
28  import java.util.Enumeration;
29  import java.util.HashMap;
30  import java.util.HashSet;
31  import java.util.Iterator;
32  import java.util.LinkedHashMap;
33  import java.util.LinkedHashSet;
34  import java.util.LinkedList;
35  import java.util.List;
36  import java.util.Map;
37  import java.util.Set;
38  import java.util.jar.JarFile;
39  import java.util.zip.ZipEntry;
40  
41  import javax.xml.namespace.QName;
42  
43  import org.apache.commons.logging.Log;
44  import org.apache.commons.logging.LogFactory;
45  import org.apache.geronimo.common.DeploymentException;
46  import org.apache.geronimo.deployment.ConfigurationBuilder;
47  import org.apache.geronimo.deployment.DeploymentContext;
48  import org.apache.geronimo.deployment.ModuleIDBuilder;
49  import org.apache.geronimo.deployment.NamespaceDrivenBuilder;
50  import org.apache.geronimo.deployment.NamespaceDrivenBuilderCollection;
51  import org.apache.geronimo.deployment.service.EnvironmentBuilder;
52  import org.apache.geronimo.deployment.util.DeploymentUtil;
53  import org.apache.geronimo.deployment.util.NestedJarFile;
54  import org.apache.geronimo.deployment.xbeans.ArtifactType;
55  import org.apache.geronimo.deployment.xbeans.EnvironmentType;
56  import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil;
57  import org.apache.geronimo.gbean.AbstractName;
58  import org.apache.geronimo.gbean.AbstractNameQuery;
59  import org.apache.geronimo.gbean.GBeanData;
60  import org.apache.geronimo.gbean.GBeanInfo;
61  import org.apache.geronimo.gbean.GBeanInfoBuilder;
62  import org.apache.geronimo.gbean.ReferencePatterns;
63  import org.apache.geronimo.gbean.SingleElementCollection;
64  import org.apache.geronimo.j2ee.ApplicationInfo;
65  import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
66  import org.apache.geronimo.j2ee.management.impl.J2EEApplicationImpl;
67  import org.apache.geronimo.kernel.GBeanAlreadyExistsException;
68  import org.apache.geronimo.kernel.Kernel;
69  import org.apache.geronimo.kernel.Naming;
70  import org.apache.geronimo.kernel.config.ConfigurationAlreadyExistsException;
71  import org.apache.geronimo.kernel.config.ConfigurationData;
72  import org.apache.geronimo.kernel.config.ConfigurationManager;
73  import org.apache.geronimo.kernel.config.ConfigurationModuleType;
74  import org.apache.geronimo.kernel.config.ConfigurationStore;
75  import org.apache.geronimo.kernel.config.ConfigurationUtil;
76  import org.apache.geronimo.kernel.config.SimpleConfigurationManager;
77  import org.apache.geronimo.kernel.repository.Artifact;
78  import org.apache.geronimo.kernel.repository.ArtifactResolver;
79  import org.apache.geronimo.kernel.repository.Environment;
80  import org.apache.geronimo.kernel.repository.Repository;
81  import org.apache.geronimo.management.J2EEResource;
82  import org.apache.geronimo.management.J2EEServer;
83  import org.apache.geronimo.schema.SchemaConversionUtils;
84  import org.apache.geronimo.xbeans.geronimo.j2ee.GerApplicationDocument;
85  import org.apache.geronimo.xbeans.geronimo.j2ee.GerApplicationType;
86  import org.apache.geronimo.xbeans.geronimo.j2ee.GerExtModuleType;
87  import org.apache.geronimo.xbeans.geronimo.j2ee.GerModuleType;
88  import org.apache.geronimo.xbeans.j2ee.ApplicationType;
89  import org.apache.geronimo.xbeans.j2ee.ModuleType;
90  import org.apache.geronimo.xbeans.j2ee.ApplicationDocument;
91  import org.apache.xmlbeans.XmlException;
92  import org.apache.xmlbeans.XmlObject;
93  import org.apache.xmlbeans.XmlCursor;
94  
95  /**
96   * @version $Rev: 470597 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $
97   */
98  public class EARConfigBuilder implements ConfigurationBuilder, CorbaGBeanNameSource {
99  
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 }