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