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.client.builder; 019 020 import java.io.File; 021 import java.io.IOException; 022 import java.net.URI; 023 import java.net.URISyntaxException; 024 import java.net.URL; 025 import java.util.ArrayList; 026 import java.util.Collection; 027 import java.util.Collections; 028 import java.util.Iterator; 029 import java.util.LinkedList; 030 import java.util.Map; 031 import java.util.StringTokenizer; 032 import java.util.HashMap; 033 import java.util.jar.Attributes; 034 import java.util.jar.JarFile; 035 import java.util.jar.Manifest; 036 import java.util.zip.ZipEntry; 037 038 import org.apache.commons.logging.Log; 039 import org.apache.commons.logging.LogFactory; 040 import org.apache.geronimo.client.AppClientContainer; 041 import org.apache.geronimo.client.StaticJndiContextPlugin; 042 import org.apache.geronimo.common.DeploymentException; 043 import org.apache.geronimo.deployment.DeploymentContext; 044 import org.apache.geronimo.deployment.ModuleIDBuilder; 045 import org.apache.geronimo.deployment.NamespaceDrivenBuilder; 046 import org.apache.geronimo.deployment.NamespaceDrivenBuilderCollection; 047 import org.apache.geronimo.deployment.service.EnvironmentBuilder; 048 import org.apache.geronimo.deployment.util.DeploymentUtil; 049 import org.apache.geronimo.deployment.util.NestedJarFile; 050 import org.apache.geronimo.deployment.xbeans.EnvironmentType; 051 import org.apache.geronimo.deployment.xmlbeans.XmlBeansUtil; 052 import org.apache.geronimo.gbean.AbstractName; 053 import org.apache.geronimo.gbean.AbstractNameQuery; 054 import org.apache.geronimo.gbean.GBeanData; 055 import org.apache.geronimo.gbean.GBeanInfo; 056 import org.apache.geronimo.gbean.GBeanInfoBuilder; 057 import org.apache.geronimo.gbean.SingleElementCollection; 058 import org.apache.geronimo.j2ee.deployment.AppClientModule; 059 import org.apache.geronimo.j2ee.deployment.EARContext; 060 import org.apache.geronimo.j2ee.deployment.Module; 061 import org.apache.geronimo.j2ee.deployment.ModuleBuilder; 062 import org.apache.geronimo.j2ee.deployment.SecurityBuilder; 063 import org.apache.geronimo.j2ee.deployment.CorbaGBeanNameSource; 064 import org.apache.geronimo.j2ee.deployment.NamingBuilder; 065 import org.apache.geronimo.j2ee.deployment.NamingBuilderCollection; 066 import org.apache.geronimo.j2ee.deployment.ConnectorModule; 067 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory; 068 import org.apache.geronimo.j2ee.management.impl.J2EEAppClientModuleImpl; 069 import org.apache.geronimo.kernel.GBeanAlreadyExistsException; 070 import org.apache.geronimo.kernel.Naming; 071 import org.apache.geronimo.kernel.config.ConfigurationAlreadyExistsException; 072 import org.apache.geronimo.kernel.config.ConfigurationModuleType; 073 import org.apache.geronimo.kernel.config.ConfigurationStore; 074 import org.apache.geronimo.kernel.config.Configuration; 075 import org.apache.geronimo.kernel.repository.Artifact; 076 import org.apache.geronimo.kernel.repository.Environment; 077 import org.apache.geronimo.kernel.repository.Repository; 078 import org.apache.geronimo.schema.SchemaConversionUtils; 079 import org.apache.geronimo.security.deploy.DefaultPrincipal; 080 import org.apache.geronimo.xbeans.geronimo.client.GerApplicationClientDocument; 081 import org.apache.geronimo.xbeans.geronimo.client.GerApplicationClientType; 082 import org.apache.geronimo.xbeans.geronimo.client.GerResourceType; 083 import org.apache.geronimo.xbeans.geronimo.naming.GerAbstractNamingEntryDocument; 084 import org.apache.geronimo.xbeans.j2ee.ApplicationClientDocument; 085 import org.apache.geronimo.xbeans.j2ee.ApplicationClientType; 086 import org.apache.xmlbeans.XmlException; 087 import org.apache.xmlbeans.XmlObject; 088 import org.apache.xmlbeans.XmlCursor; 089 090 091 /** 092 * @version $Rev:385232 $ $Date: 2006-11-02 15:30:55 -0800 (Thu, 02 Nov 2006) $ 093 */ 094 public class AppClientModuleBuilder implements ModuleBuilder, CorbaGBeanNameSource { 095 private static final Log log = LogFactory.getLog(AppClientModuleBuilder.class); 096 private static final String LINE_SEP = System.getProperty("line.separator"); 097 098 private final Environment defaultClientEnvironment; 099 private final Environment defaultServerEnvironment; 100 private final AbstractNameQuery corbaGBeanObjectName; 101 102 private final AbstractNameQuery transactionManagerObjectName; 103 private final AbstractNameQuery connectionTrackerObjectName; 104 private final SingleElementCollection connectorModuleBuilder; 105 private final SingleElementCollection securityBuilder; 106 private final NamespaceDrivenBuilderCollection serviceBuilder; 107 private final NamingBuilderCollection namingBuilders; 108 109 private final Collection repositories; 110 111 private static final String GERAPPCLIENT_NAMESPACE = GerApplicationClientDocument.type.getDocumentElementName().getNamespaceURI(); 112 113 public AppClientModuleBuilder(Environment defaultClientEnvironment, 114 Environment defaultServerEnvironment, 115 AbstractNameQuery transactionManagerObjectName, 116 AbstractNameQuery connectionTrackerObjectName, 117 AbstractNameQuery corbaGBeanObjectName, 118 Collection repositories, 119 ModuleBuilder connectorModuleBuilder, 120 NamespaceDrivenBuilder securityBuilder, 121 NamespaceDrivenBuilder serviceBuilder, 122 Collection namingBuilders) { 123 this(defaultClientEnvironment, 124 defaultServerEnvironment, 125 transactionManagerObjectName, 126 connectionTrackerObjectName, 127 corbaGBeanObjectName, 128 repositories, new SingleElementCollection(connectorModuleBuilder), 129 new SingleElementCollection(securityBuilder), 130 serviceBuilder == null ? Collections.EMPTY_SET : Collections.singleton(serviceBuilder), 131 namingBuilders == null ? Collections.EMPTY_SET : namingBuilders); 132 } 133 134 public AppClientModuleBuilder(AbstractNameQuery transactionManagerObjectName, 135 AbstractNameQuery connectionTrackerObjectName, 136 AbstractNameQuery corbaGBeanObjectName, 137 Collection repositories, 138 Collection connectorModuleBuilder, 139 Collection securityBuilder, 140 Collection serviceBuilder, 141 Collection namingBuilders, 142 Environment defaultClientEnvironment, 143 Environment defaultServerEnvironment) { 144 this(defaultClientEnvironment, 145 defaultServerEnvironment, 146 transactionManagerObjectName, 147 connectionTrackerObjectName, 148 corbaGBeanObjectName, 149 repositories, new SingleElementCollection(connectorModuleBuilder), 150 new SingleElementCollection(securityBuilder), 151 serviceBuilder, 152 namingBuilders); 153 } 154 155 private AppClientModuleBuilder(Environment defaultClientEnvironment, 156 Environment defaultServerEnvironment, 157 AbstractNameQuery transactionManagerObjectName, 158 AbstractNameQuery connectionTrackerObjectName, 159 AbstractNameQuery corbaGBeanObjectName, 160 Collection repositories, 161 SingleElementCollection connectorModuleBuilder, 162 SingleElementCollection securityBuilder, 163 Collection serviceBuilder, Collection namingBuilders) { 164 this.defaultClientEnvironment = defaultClientEnvironment; 165 this.defaultServerEnvironment = defaultServerEnvironment; 166 this.corbaGBeanObjectName = corbaGBeanObjectName; 167 this.transactionManagerObjectName = transactionManagerObjectName; 168 this.connectionTrackerObjectName = connectionTrackerObjectName; 169 this.repositories = repositories; 170 this.connectorModuleBuilder = connectorModuleBuilder; 171 this.securityBuilder = securityBuilder; 172 this.serviceBuilder = new NamespaceDrivenBuilderCollection(serviceBuilder); 173 this.namingBuilders = new NamingBuilderCollection(namingBuilders, GerAbstractNamingEntryDocument.type.getDocumentElementName()); 174 } 175 176 177 public AbstractNameQuery getCorbaGBeanName() { 178 return corbaGBeanObjectName; 179 } 180 181 private ModuleBuilder getConnectorModuleBuilder() { 182 return (ModuleBuilder) connectorModuleBuilder.getElement(); 183 } 184 185 private org.apache.geronimo.j2ee.deployment.SecurityBuilder getSecurityBuilder() { 186 return (SecurityBuilder) securityBuilder.getElement(); 187 } 188 189 public Module createModule(File plan, JarFile moduleFile, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException { 190 return createModule(plan, moduleFile, "app-client", null, null, null, naming, idBuilder); 191 } 192 193 public Module createModule(Object plan, JarFile moduleFile, String targetPath, URL specDDUrl, Environment environment, Object moduleContextInfo, AbstractName earName, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException { 194 return createModule(plan, moduleFile, targetPath, specDDUrl, environment, earName, naming, idBuilder); 195 } 196 197 private Module createModule(Object plan, JarFile moduleFile, String targetPath, URL specDDUrl, Environment earEnvironment, AbstractName earName, Naming naming, ModuleIDBuilder idBuilder) throws DeploymentException { 198 assert moduleFile != null: "moduleFile is null"; 199 assert targetPath != null: "targetPath is null"; 200 assert !targetPath.endsWith("/"): "targetPath must not end with a '/'"; 201 assert (earName == null) == (earEnvironment == null): "if earName is not null you must supply earEnvironment as well"; 202 203 String specDD; 204 ApplicationClientType appClient; 205 try { 206 if (specDDUrl == null) { 207 specDDUrl = DeploymentUtil.createJarURL(moduleFile, "META-INF/application-client.xml"); 208 } 209 210 // read in the entire specDD as a string, we need this for getDeploymentDescriptor 211 // on the J2ee management object 212 specDD = DeploymentUtil.readAll(specDDUrl); 213 } catch (Exception e) { 214 //no application-client.xml, not for us. 215 return null; 216 } 217 //we found application-client.xml, if it won't parse it's an error. 218 try { 219 // parse it 220 XmlObject xmlObject = XmlBeansUtil.parse(specDD); 221 ApplicationClientDocument appClientDoc = convertToApplicationClientSchema(xmlObject); 222 appClient = appClientDoc.getApplicationClient(); 223 } catch (XmlException e) { 224 throw new DeploymentException("Unable to parse application-client.xml", e); 225 } 226 227 // parse vendor dd 228 boolean standAlone = earEnvironment == null; 229 GerApplicationClientType gerAppClient = getGeronimoAppClient(plan, moduleFile, standAlone, targetPath, appClient, earEnvironment); 230 231 232 EnvironmentType clientEnvironmentType = gerAppClient.getClientEnvironment(); 233 Environment clientEnvironment = EnvironmentBuilder.buildEnvironment(clientEnvironmentType, defaultClientEnvironment); 234 if (standAlone) { 235 String name = new File(moduleFile.getName()).getName(); 236 idBuilder.resolve(clientEnvironment, name + "_" + name, "jar"); 237 } else { 238 Artifact earConfigId = earEnvironment.getConfigId(); 239 idBuilder.resolve(clientEnvironment, earConfigId.getArtifactId() + "_" + targetPath, "jar"); 240 } 241 EnvironmentType serverEnvironmentType = gerAppClient.getServerEnvironment(); 242 Environment serverEnvironment = EnvironmentBuilder.buildEnvironment(serverEnvironmentType, defaultServerEnvironment); 243 if (!standAlone) { 244 EnvironmentBuilder.mergeEnvironments(earEnvironment, serverEnvironment); 245 serverEnvironment = earEnvironment; 246 if (!serverEnvironment.getConfigId().isResolved()) { 247 throw new IllegalStateException("Server environment module ID should be fully resolved (not " + serverEnvironment.getConfigId() + ")"); 248 } 249 } else { 250 idBuilder.resolve(serverEnvironment, new File(moduleFile.getName()).getName(), "jar"); 251 } 252 253 namingBuilders.buildEnvironment(appClient, gerAppClient, clientEnvironment); 254 255 if (earName == null) { 256 earName = naming.createRootName(earEnvironment.getConfigId(), NameFactory.NULL, NameFactory.J2EE_APPLICATION); 257 } 258 259 //always use the artifactId of the app client as the name component of the module name (on the server). 260 AbstractName moduleName = naming.createChildName(earName, clientEnvironment.getConfigId().toString(), NameFactory.APP_CLIENT_MODULE); 261 AbstractName clientBaseName = naming.createRootName(clientEnvironment.getConfigId(), clientEnvironment.getConfigId().toString(), NameFactory.J2EE_APPLICATION); 262 263 //start installing the resource adapters in the client. 264 Collection resourceModules = new ArrayList(); 265 GerResourceType[] resources = gerAppClient.getResourceArray(); 266 for (int i = 0; i < resources.length; i++) { 267 GerResourceType resource = resources[i]; 268 String path; 269 JarFile connectorFile; 270 if (resource.isSetExternalRar()) { 271 path = resource.getExternalRar().trim(); 272 Artifact artifact = Artifact.create(path); 273 File file = null; 274 for (Iterator iterator = repositories.iterator(); iterator.hasNext();) { 275 Repository repository = (Repository) iterator.next(); 276 if (repository.contains(artifact)) { 277 file = repository.getLocation(artifact); 278 break; 279 } 280 } 281 if (file == null) { 282 throw new DeploymentException("Missing rar in repositories: " + path); 283 } 284 try { 285 connectorFile = new JarFile(file); 286 } catch (IOException e) { 287 throw new DeploymentException("Could not access rar contents", e); 288 } 289 } else { 290 path = resource.getInternalRar(); 291 try { 292 connectorFile = new NestedJarFile(moduleFile, path); 293 } catch (IOException e) { 294 throw new DeploymentException("Could not locate connector inside ear", e); 295 } 296 } 297 XmlObject connectorPlan = resource.getConnector(); 298 Module connectorModule = getConnectorModuleBuilder().createModule(connectorPlan, connectorFile, path, null, clientEnvironment, null, clientBaseName, naming, idBuilder); 299 resourceModules.add(connectorModule); 300 } 301 302 return new AppClientModule(standAlone, moduleName, clientBaseName, serverEnvironment, clientEnvironment, moduleFile, targetPath, appClient, gerAppClient, specDD, resourceModules); 303 } 304 305 GerApplicationClientType getGeronimoAppClient(Object plan, JarFile moduleFile, boolean standAlone, String targetPath, ApplicationClientType appClient, Environment environment) throws DeploymentException { 306 GerApplicationClientType gerAppClient; 307 XmlObject rawPlan = null; 308 try { 309 // load the geronimo-application-client.xml from either the supplied plan or from the earFile 310 try { 311 if (plan instanceof XmlObject) { 312 rawPlan = (XmlObject) plan; 313 } else { 314 if (plan != null) { 315 rawPlan = XmlBeansUtil.parse((File) plan); 316 } else { 317 URL path = DeploymentUtil.createJarURL(moduleFile, "META-INF/geronimo-application-client.xml"); 318 rawPlan = XmlBeansUtil.parse(path, getClass().getClassLoader()); 319 } 320 } 321 } catch (IOException e) { 322 //exception means we create default 323 } 324 325 // if we got one extract the validate it otherwise create a default one 326 if (rawPlan != null) { 327 gerAppClient = (GerApplicationClientType) SchemaConversionUtils.fixGeronimoSchema(rawPlan, GerApplicationClientDocument.type.getDocumentElementName(), GerApplicationClientType.type); 328 } else { 329 String path; 330 if (standAlone) { 331 // default configId is based on the moduleFile name 332 path = new File(moduleFile.getName()).getName(); 333 } else { 334 // default configId is based on the module uri from the application.xml 335 path = targetPath; 336 } 337 gerAppClient = createDefaultPlan(path, appClient, standAlone, environment); 338 } 339 } catch (XmlException e) { 340 throw new DeploymentException(e); 341 } 342 return gerAppClient; 343 } 344 345 private GerApplicationClientType createDefaultPlan(String name, ApplicationClientType appClient, boolean standAlone, Environment environment) { 346 String id = appClient.getId(); 347 if (id == null) { 348 id = name; 349 if (id.endsWith(".jar")) { 350 id = id.substring(0, id.length() - 4); 351 } 352 if (id.endsWith("/")) { 353 id = id.substring(0, id.length() - 1); 354 } 355 } 356 357 GerApplicationClientType geronimoAppClient = GerApplicationClientType.Factory.newInstance(); 358 EnvironmentType clientEnvironmentType = geronimoAppClient.addNewClientEnvironment(); 359 EnvironmentType serverEnvironmentType = geronimoAppClient.addNewServerEnvironment(); 360 //TODO configid fill in environment with configids 361 // set the parentId and configId 362 // if (standAlone) { 363 // geronimoAppClient.setClientConfigId(id); 364 // geronimoAppClient.setConfigId(id + "/server"); 365 // } else { 366 // geronimoAppClient.setClientConfigId(earConfigId.getPath() + "/" + id); 367 // not used but we need to have a value 368 // geronimoAppClient.setConfigId(id); 369 // } 370 return geronimoAppClient; 371 } 372 373 static ApplicationClientDocument convertToApplicationClientSchema(XmlObject xmlObject) throws XmlException { 374 if (ApplicationClientDocument.type.equals(xmlObject.schemaType())) { 375 XmlBeansUtil.validateDD(xmlObject); 376 return (ApplicationClientDocument) xmlObject; 377 } 378 XmlCursor cursor = xmlObject.newCursor(); 379 XmlCursor moveable = xmlObject.newCursor(); 380 String schemaLocationURL = "http://java.sun.com/xml/ns/j2ee/application-client_1_4.xsd"; 381 String version = "1.4"; 382 try { 383 SchemaConversionUtils.convertToSchema(cursor, SchemaConversionUtils.J2EE_NAMESPACE, schemaLocationURL, version); 384 cursor.toStartDoc(); 385 cursor.toChild(SchemaConversionUtils.J2EE_NAMESPACE, "application-client"); 386 cursor.toFirstChild(); 387 SchemaConversionUtils.convertToDescriptionGroup(SchemaConversionUtils.J2EE_NAMESPACE, cursor, moveable); 388 } finally { 389 cursor.dispose(); 390 moveable.dispose(); 391 } 392 XmlObject result = xmlObject.changeType(ApplicationClientDocument.type); 393 if (result != null) { 394 XmlBeansUtil.validateDD(result); 395 return (ApplicationClientDocument) result; 396 } 397 XmlBeansUtil.validateDD(xmlObject); 398 return (ApplicationClientDocument) xmlObject; 399 400 } 401 402 public void installModule(JarFile earFile, EARContext earContext, Module module, Collection configurationStores, ConfigurationStore targetConfigurationStore, Collection repositories) throws DeploymentException { 403 // extract the app client jar file into a standalone packed jar file and add the contents to the output 404 JarFile moduleFile = module.getModuleFile(); 405 try { 406 earContext.addIncludeAsPackedJar(URI.create(module.getTargetPath()), moduleFile); 407 } catch (IOException e) { 408 throw new DeploymentException("Unable to copy app client module jar into configuration: " + moduleFile.getName()); 409 } 410 AppClientModule appClientModule = (AppClientModule) module; 411 appClientModule.setEarFile(earFile); 412 //create the ear context for the app client. 413 Environment clientEnvironment = appClientModule.getClientEnvironment(); 414 // if (!appClientModule.isStandAlone() || clientEnvironment.getConfigId() == null) { 415 // Artifact earConfigId = earContext.getConfigID(); 416 // Artifact configId = new Artifact(earConfigId.getGroupId(), earConfigId.getArtifactId() + "_" + module.getTargetPath(), earConfigId.getVersion(), "car"); 417 // clientEnvironment.setConfigId(configId); 418 // } 419 420 File appClientDir; 421 try { 422 appClientDir = targetConfigurationStore.createNewConfigurationDir(clientEnvironment.getConfigId()); 423 } catch (ConfigurationAlreadyExistsException e) { 424 throw new DeploymentException(e); 425 } 426 427 // construct the app client deployment context... this is the same class used by the ear context 428 EARContext appClientDeploymentContext; 429 try { 430 431 appClientDeploymentContext = new EARContext(appClientDir, 432 null, 433 clientEnvironment, 434 ConfigurationModuleType.CAR, 435 earContext.getNaming(), 436 earContext.getConfigurationManager(), 437 null, //no server name needed on client 438 appClientModule.getAppClientName(), 439 transactionManagerObjectName, 440 connectionTrackerObjectName, 441 null, 442 null, 443 corbaGBeanObjectName 444 ); 445 appClientModule.setEarContext(appClientDeploymentContext); 446 appClientModule.setRootEarContext(earContext); 447 } catch (DeploymentException e) { 448 cleanupAppClientDir(appClientDir); 449 throw e; 450 } 451 for (Iterator resources = appClientModule.getResourceModules().iterator(); resources.hasNext();) { 452 ConnectorModule connectorModule = (ConnectorModule) resources.next(); 453 getConnectorModuleBuilder().installModule(connectorModule.getModuleFile(), appClientDeploymentContext, connectorModule, configurationStores, targetConfigurationStore, repositories); 454 } 455 456 } 457 458 public void initContext(EARContext earContext, Module clientModule, ClassLoader cl) throws DeploymentException { 459 AppClientModule appClientModule = ((AppClientModule) clientModule); 460 for (Iterator resources = appClientModule.getResourceModules().iterator(); resources.hasNext();) { 461 ConnectorModule connectorModule = (ConnectorModule) resources.next(); 462 getConnectorModuleBuilder().initContext(appClientModule.getEarContext(), connectorModule, cl); 463 } 464 } 465 466 public void addGBeans(EARContext earContext, Module module, ClassLoader earClassLoader, Collection repositories) throws DeploymentException { 467 468 AppClientModule appClientModule = (AppClientModule) module; 469 470 ApplicationClientType appClient = (ApplicationClientType) appClientModule.getSpecDD(); 471 GerApplicationClientType geronimoAppClient = (GerApplicationClientType) appClientModule.getVendorDD(); 472 473 // get the app client main class 474 JarFile moduleFile = module.getModuleFile(); 475 String mainClasss; 476 try { 477 Manifest manifest = moduleFile.getManifest(); 478 if (manifest == null) { 479 throw new DeploymentException("App client module jar does not contain a manifest: " + moduleFile.getName()); 480 } 481 mainClasss = manifest.getMainAttributes().getValue(Attributes.Name.MAIN_CLASS); 482 if (mainClasss == null) { 483 throw new DeploymentException("App client module jar does not have Main-Class defined in the manifest: " + moduleFile.getName()); 484 } 485 String classPath = manifest.getMainAttributes().getValue(Attributes.Name.CLASS_PATH); 486 if (module.isStandAlone() && classPath != null) { 487 throw new DeploymentException("Manifest class path entry is not allowed in a standalone jar (J2EE 1.4 Section 8.2)"); 488 } 489 } catch (IOException e) { 490 throw new DeploymentException("Could not get manifest from app client module: " + moduleFile.getName()); 491 } 492 493 // generate the object name for the app client 494 AbstractName appClientModuleName = appClientModule.getModuleName(); 495 496 // create a gbean for the app client module and add it to the ear 497 GBeanData appClientModuleGBeanData = new GBeanData(appClientModuleName, J2EEAppClientModuleImpl.GBEAN_INFO); 498 try { 499 appClientModuleGBeanData.setReferencePattern("J2EEServer", earContext.getServerName()); 500 if (!module.isStandAlone()) { 501 appClientModuleGBeanData.setReferencePattern("J2EEApplication", earContext.getModuleName()); 502 } 503 appClientModuleGBeanData.setAttribute("deploymentDescriptor", appClientModule.getOriginalSpecDD()); 504 505 } catch (Exception e) { 506 throw new DeploymentException("Unable to initialize AppClientModule GBean", e); 507 } 508 try { 509 earContext.addGBean(appClientModuleGBeanData); 510 } catch (GBeanAlreadyExistsException e) { 511 throw new DeploymentException("Could not add application client module gbean to configuration", e); 512 } 513 514 EARContext appClientDeploymentContext = appClientModule.getEarContext(); 515 516 // Create a Module ID Builder defaulting to similar settings to use for any children we create 517 ModuleIDBuilder idBuilder = new ModuleIDBuilder(); 518 idBuilder.setDefaultGroup(appClientModule.getClientEnvironment().getConfigId().getGroupId()); 519 idBuilder.setDefaultVersion(appClientModule.getClientEnvironment().getConfigId().getVersion()); 520 try { 521 try { 522 523 //register the message destinations in the app client ear context. 524 namingBuilders.initContext(appClient, geronimoAppClient, appClientDeploymentContext.getConfiguration(), earContext.getConfiguration(), appClientModule); 525 // extract the client Jar file into a standalone packed jar file and add the contents to the output 526 URI moduleBase = new URI(appClientModule.getTargetPath()); 527 try { 528 appClientDeploymentContext.addIncludeAsPackedJar(moduleBase, moduleFile); 529 } catch (IOException e) { 530 throw new DeploymentException("Unable to copy app client module jar into configuration: " + moduleFile.getName()); 531 } 532 533 // add manifest class path entries to the app client context 534 addManifestClassPath(appClientDeploymentContext, appClientModule.getEarFile(), moduleFile, moduleBase); 535 536 // get the classloader 537 ClassLoader appClientClassLoader = appClientDeploymentContext.getClassLoader(); 538 539 // pop in all the gbeans declared in the geronimo app client file 540 if (geronimoAppClient != null) { 541 serviceBuilder.build(geronimoAppClient, appClientDeploymentContext, appClientDeploymentContext); 542 //deploy the resource adapters specified in the geronimo-application.xml 543 544 for (Iterator resources = appClientModule.getResourceModules().iterator(); resources.hasNext();) { 545 ConnectorModule connectorModule = (ConnectorModule) resources.next(); 546 getConnectorModuleBuilder().addGBeans(appClientDeploymentContext, connectorModule, appClientClassLoader, repositories); 547 } 548 } 549 550 // add the app client static jndi provider 551 //TODO track resource ref shared and app managed security 552 AbstractName jndiContextName = earContext.getNaming().createChildName(appClientDeploymentContext.getModuleName(), "StaticJndiContext", "StaticJndiContext"); 553 GBeanData jndiContextGBeanData = new GBeanData(jndiContextName, StaticJndiContextPlugin.GBEAN_INFO); 554 try { 555 Map buildingContext = new HashMap(); 556 buildingContext.put(NamingBuilder.JNDI_KEY, new HashMap()); 557 buildingContext.put(NamingBuilder.GBEAN_NAME_KEY, jndiContextName); 558 Configuration localConfiguration = appClientDeploymentContext.getConfiguration(); 559 Configuration remoteConfiguration = earContext.getConfiguration(); 560 namingBuilders.buildNaming(appClient, geronimoAppClient, localConfiguration, remoteConfiguration, appClientModule, buildingContext); 561 jndiContextGBeanData.setAttribute("context", buildingContext.get(NamingBuilder.JNDI_KEY)); 562 } catch (DeploymentException e) { 563 throw e; 564 } catch (Exception e) { 565 throw new DeploymentException("Unable to construct jndi context for AppClientModule GBean", e); 566 } 567 appClientDeploymentContext.addGBean(jndiContextGBeanData); 568 569 // finally add the app client container 570 AbstractName appClientContainerName = appClientDeploymentContext.getModuleName(); 571 GBeanData appClientContainerGBeanData = new GBeanData(appClientContainerName, AppClientContainer.GBEAN_INFO); 572 try { 573 appClientContainerGBeanData.setAttribute("mainClassName", mainClasss); 574 appClientContainerGBeanData.setAttribute("appClientModuleName", appClientModuleName); 575 String callbackHandlerClassName = null; 576 if (appClient.isSetCallbackHandler()) { 577 callbackHandlerClassName = appClient.getCallbackHandler().getStringValue().trim(); 578 } 579 if (geronimoAppClient.isSetCallbackHandler()) { 580 callbackHandlerClassName = geronimoAppClient.getCallbackHandler().trim(); 581 } 582 String realmName = null; 583 if (geronimoAppClient.isSetRealmName()) { 584 realmName = geronimoAppClient.getRealmName().trim(); 585 } 586 if (callbackHandlerClassName != null && realmName == null) { 587 throw new DeploymentException("You must specify a realm name with the callback handler"); 588 } 589 if (realmName != null) { 590 appClientContainerGBeanData.setAttribute("realmName", realmName); 591 appClientContainerGBeanData.setAttribute("callbackHandlerClassName", callbackHandlerClassName); 592 } else if (geronimoAppClient.isSetDefaultPrincipal()) { 593 DefaultPrincipal defaultPrincipal = getSecurityBuilder().buildDefaultPrincipal(geronimoAppClient.getDefaultPrincipal()); 594 appClientContainerGBeanData.setAttribute("defaultPrincipal", defaultPrincipal); 595 } 596 appClientContainerGBeanData.setReferencePattern("JNDIContext", jndiContextName); 597 } catch (Exception e) { 598 throw new DeploymentException("Unable to initialize AppClientModule GBean", e); 599 } 600 appClientDeploymentContext.addGBean(appClientContainerGBeanData); 601 602 // get the configuration data 603 earContext.addAdditionalDeployment(appClientDeploymentContext.getConfigurationData()); 604 } finally { 605 if (appClientDeploymentContext != null) { 606 try { 607 appClientDeploymentContext.close(); 608 } catch (IOException e) { 609 //nothing we can do 610 } 611 } 612 } 613 614 } catch (Throwable e) { 615 File appClientDir = appClientDeploymentContext.getBaseDir(); 616 cleanupAppClientDir(appClientDir); 617 if (e instanceof Error) { 618 throw (Error) e; 619 } else if (e instanceof DeploymentException) { 620 throw (DeploymentException) e; 621 } else if (e instanceof Exception) { 622 throw new DeploymentException(e); 623 } 624 throw new Error(e); 625 } 626 } 627 628 public String getSchemaNamespace() { 629 return GERAPPCLIENT_NAMESPACE; 630 } 631 632 public void addManifestClassPath(DeploymentContext deploymentContext, JarFile earFile, JarFile jarFile, URI jarFileLocation) throws DeploymentException { 633 Manifest manifest; 634 try { 635 manifest = jarFile.getManifest(); 636 } catch (IOException e) { 637 throw new DeploymentException("Could not read manifest: " + jarFileLocation); 638 } 639 640 if (manifest == null) { 641 return; 642 } 643 String manifestClassPath = manifest.getMainAttributes().getValue(Attributes.Name.CLASS_PATH); 644 if (manifestClassPath == null) { 645 return; 646 } 647 648 for (StringTokenizer tokenizer = new StringTokenizer(manifestClassPath, " "); tokenizer.hasMoreTokens();) { 649 String path = tokenizer.nextToken(); 650 651 URI pathUri; 652 try { 653 pathUri = new URI(path); 654 } catch (URISyntaxException e) { 655 throw new DeploymentException("Invalid manifest classpath entry: jarFile=" + jarFileLocation + ", path=" + path); 656 } 657 658 if (!pathUri.getPath().endsWith(".jar")) { 659 throw new DeploymentException("Manifest class path entries must end with the .jar extension (J2EE 1.4 Section 8.2): jarFile=" + jarFileLocation + ", path=" + path); 660 } 661 if (pathUri.isAbsolute()) { 662 throw new DeploymentException("Manifest class path entries must be relative (J2EE 1.4 Section 8.2): jarFile=" + jarFileLocation + ", path=" + path); 663 } 664 665 // determine the target file 666 URI classPathJarLocation = jarFileLocation.resolve(pathUri); 667 File classPathFile = deploymentContext.getTargetFile(classPathJarLocation); 668 669 // we only recuse if the path entry is not already in the output context 670 // this will work for all current cases, but may not work in the future 671 if (!classPathFile.exists()) { 672 // check if the path exists in the earFile 673 ZipEntry entry = earFile.getEntry(classPathJarLocation.getPath()); 674 if (entry == null) { 675 throw new DeploymentException("Cound not find manifest class path entry: jarFile=" + jarFileLocation + ", path=" + path); 676 } 677 678 try { 679 // copy the file into the output context 680 deploymentContext.addFile(classPathJarLocation, earFile, entry); 681 } catch (IOException e) { 682 throw new DeploymentException("Cound not copy manifest class path entry into configuration: jarFile=" + jarFileLocation + ", path=" + path, e); 683 } 684 685 JarFile classPathJarFile; 686 try { 687 classPathJarFile = new JarFile(classPathFile); 688 } catch (IOException e) { 689 throw new DeploymentException("Manifest class path entries must be a valid jar file (J2EE 1.4 Section 8.2): jarFile=" + jarFileLocation + ", path=" + path, e); 690 } 691 692 // add the client jars of this class path jar 693 addManifestClassPath(deploymentContext, earFile, classPathJarFile, classPathJarLocation); 694 } 695 } 696 } 697 698 private boolean cleanupAppClientDir(File configurationDir) { 699 LinkedList cannotBeDeletedList = new LinkedList(); 700 701 if (!DeploymentUtil.recursiveDelete(configurationDir, cannotBeDeletedList)) { 702 // Output a message to help user track down file problem 703 log.warn("Unable to delete " + cannotBeDeletedList.size() + 704 " files while recursively deleting directory " 705 + configurationDir + LINE_SEP + 706 "The first file that could not be deleted was:" + LINE_SEP + " " + 707 (!cannotBeDeletedList.isEmpty() ? cannotBeDeletedList.getFirst() : "")); 708 return false; 709 } 710 return true; 711 } 712 713 public static final GBeanInfo GBEAN_INFO; 714 715 static { 716 GBeanInfoBuilder infoBuilder = GBeanInfoBuilder.createStatic(AppClientModuleBuilder.class, NameFactory.MODULE_BUILDER); 717 infoBuilder.addAttribute("defaultClientEnvironment", Environment.class, true, true); 718 infoBuilder.addAttribute("defaultServerEnvironment", Environment.class, true, true); 719 infoBuilder.addAttribute("transactionManagerObjectName", AbstractNameQuery.class, true); 720 infoBuilder.addAttribute("connectionTrackerObjectName", AbstractNameQuery.class, true); 721 infoBuilder.addAttribute("corbaGBeanObjectName", AbstractNameQuery.class, true); 722 infoBuilder.addReference("Repositories", Repository.class, "Repository"); 723 infoBuilder.addReference("ConnectorModuleBuilder", ModuleBuilder.class, NameFactory.MODULE_BUILDER); 724 infoBuilder.addReference("SecurityBuilder", SecurityBuilder.class, NameFactory.MODULE_BUILDER); 725 infoBuilder.addReference("ServiceBuilders", NamespaceDrivenBuilder.class, NameFactory.MODULE_BUILDER); 726 infoBuilder.addReference("NamingBuilders", NamingBuilder.class, NameFactory.MODULE_BUILDER); 727 728 infoBuilder.addInterface(ModuleBuilder.class); 729 730 infoBuilder.setConstructor(new String[]{"transactionManagerObjectName", 731 "connectionTrackerObjectName", 732 "corbaGBeanObjectName", 733 "Repositories", 734 "ConnectorModuleBuilder", 735 "SecurityBuilder", 736 "ServiceBuilders", 737 "NamingBuilders", 738 "defaultClientEnvironment", 739 "defaultServerEnvironment", 740 }); 741 742 GBEAN_INFO = infoBuilder.getBeanInfo(); 743 } 744 745 public static GBeanInfo getGBeanInfo() { 746 return GBEAN_INFO; 747 } 748 749 }