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.openejb.deployment; 019 020 import java.security.PermissionCollection; 021 import java.security.Permissions; 022 import java.util.ArrayList; 023 import java.util.Collections; 024 import java.util.HashMap; 025 import java.util.List; 026 import java.util.Map; 027 import java.util.TreeMap; 028 029 import org.apache.geronimo.common.DeploymentException; 030 import org.apache.geronimo.connector.outbound.connectiontracking.TrackedConnectionAssociator; 031 import org.apache.geronimo.gbean.AbstractName; 032 import org.apache.geronimo.gbean.AbstractNameQuery; 033 import org.apache.geronimo.gbean.GBeanData; 034 import org.apache.geronimo.j2ee.deployment.EARContext; 035 import org.apache.geronimo.j2ee.deployment.NamingBuilder; 036 import org.apache.geronimo.j2ee.deployment.annotation.AnnotatedEjbJar; 037 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory; 038 import org.apache.geronimo.kernel.GBeanAlreadyExistsException; 039 import org.apache.geronimo.naming.deployment.AbstractNamingBuilder; 040 import org.apache.geronimo.naming.deployment.GBeanResourceEnvironmentBuilder; 041 import org.apache.geronimo.naming.deployment.ResourceEnvironmentSetter; 042 import org.apache.geronimo.openejb.EntityDeploymentGBean; 043 import org.apache.geronimo.openejb.MessageDrivenDeploymentGBean; 044 import org.apache.geronimo.openejb.OpenEjbSystem; 045 import org.apache.geronimo.openejb.StatefulDeploymentGBean; 046 import org.apache.geronimo.openejb.StatelessDeploymentGBean; 047 import org.apache.geronimo.openejb.xbeans.ejbjar.OpenejbGeronimoEjbJarType; 048 import org.apache.geronimo.security.deployment.SecurityConfiguration; 049 import org.apache.geronimo.security.jacc.ComponentPermissions; 050 import org.apache.geronimo.xbeans.geronimo.naming.GerResourceRefType; 051 import org.apache.geronimo.xbeans.javaee.EjbJarType; 052 import org.apache.geronimo.xbeans.javaee.EnterpriseBeansType; 053 import org.apache.geronimo.xbeans.javaee.EntityBeanType; 054 import org.apache.geronimo.xbeans.javaee.MessageDrivenBeanType; 055 import org.apache.geronimo.xbeans.javaee.ResourceRefType; 056 import org.apache.geronimo.xbeans.javaee.SessionBeanType; 057 import org.apache.openejb.DeploymentInfo; 058 import org.apache.openejb.jee.EnterpriseBean; 059 import org.apache.openejb.jee.EntityBean; 060 import org.apache.openejb.jee.MessageDrivenBean; 061 import org.apache.openejb.jee.RemoteBean; 062 import org.apache.openejb.jee.SecurityIdentity; 063 import org.apache.openejb.jee.SessionBean; 064 import org.apache.openejb.jee.SessionType; 065 import org.apache.openejb.jee.oejb3.EjbDeployment; 066 import org.apache.xbean.finder.ClassFinder; 067 import org.apache.xmlbeans.XmlObject; 068 069 /** 070 * Handles building ejb deployment gbeans. 071 */ 072 public class EjbDeploymentBuilder { 073 private final EARContext earContext; 074 private final EjbModule ejbModule; 075 private final NamingBuilder namingBuilder; 076 private final ResourceEnvironmentSetter resourceEnvironmentSetter; 077 private final Map<String, GBeanData> gbeans = new TreeMap<String, GBeanData>(); 078 079 public EjbDeploymentBuilder(EARContext earContext, EjbModule ejbModule, NamingBuilder namingBuilder, ResourceEnvironmentSetter resourceEnvironmentSetter) { 080 this.earContext = earContext; 081 this.ejbModule = ejbModule; 082 this.namingBuilder = namingBuilder; 083 this.resourceEnvironmentSetter = resourceEnvironmentSetter; 084 } 085 086 public void initContext() throws DeploymentException { 087 for (EnterpriseBean enterpriseBean : ejbModule.getEjbJar().getEnterpriseBeans()) { 088 AbstractName abstractName = createEjbName(enterpriseBean); 089 GBeanData gbean = null; 090 if (enterpriseBean instanceof SessionBean) { 091 SessionBean sessionBean = (SessionBean) enterpriseBean; 092 switch (sessionBean.getSessionType()) { 093 case STATELESS: 094 gbean = new GBeanData(abstractName, StatelessDeploymentGBean.GBEAN_INFO); 095 break; 096 case STATEFUL: 097 gbean = new GBeanData(abstractName, StatefulDeploymentGBean.GBEAN_INFO); 098 break; 099 } 100 } else if (enterpriseBean instanceof EntityBean) { 101 gbean = new GBeanData(abstractName, EntityDeploymentGBean.GBEAN_INFO); 102 } else if (enterpriseBean instanceof MessageDrivenBean) { 103 gbean = new GBeanData(abstractName, MessageDrivenDeploymentGBean.GBEAN_INFO); 104 } 105 if (gbean == null) { 106 throw new DeploymentException("Unknown enterprise bean type " + enterpriseBean.getClass().getName()); 107 } 108 109 String ejbName = enterpriseBean.getEjbName(); 110 111 EjbDeployment ejbDeployment = ejbModule.getOpenejbJar().getDeploymentsByEjbName().get(ejbName); 112 if (ejbDeployment == null) { 113 throw new DeploymentException("OpenEJB configuration not found for ejb " + ejbName); 114 } 115 gbean.setAttribute("deploymentId", ejbDeployment.getDeploymentId()); 116 gbean.setAttribute("ejbName", ejbName); 117 118 // set interface class names 119 if (enterpriseBean instanceof RemoteBean) { 120 RemoteBean remoteBean = (RemoteBean) enterpriseBean; 121 122 // Remote 123 if (remoteBean.getRemote() != null) { 124 String remoteInterfaceName = remoteBean.getRemote(); 125 assureEJBObjectInterface(remoteInterfaceName, ejbModule.getClassLoader()); 126 gbean.setAttribute(EjbInterface.REMOTE.getAttributeName(), remoteInterfaceName); 127 128 String homeInterfaceName = remoteBean.getHome(); 129 assureEJBHomeInterface(homeInterfaceName, ejbModule.getClassLoader()); 130 gbean.setAttribute(EjbInterface.HOME.getAttributeName(), homeInterfaceName); 131 } 132 133 // Local 134 if (remoteBean.getLocal() != null) { 135 String localInterfaceName = remoteBean.getLocal(); 136 assureEJBLocalObjectInterface(localInterfaceName, ejbModule.getClassLoader()); 137 gbean.setAttribute(EjbInterface.LOCAL.getAttributeName(), localInterfaceName); 138 139 String localHomeInterfaceName = remoteBean.getLocalHome(); 140 assureEJBLocalHomeInterface(localHomeInterfaceName, ejbModule.getClassLoader()); 141 gbean.setAttribute(EjbInterface.LOCAL_HOME.getAttributeName(), localHomeInterfaceName); 142 } 143 144 if (enterpriseBean instanceof SessionBean && ((SessionBean) enterpriseBean).getSessionType() == SessionType.STATELESS) { 145 SessionBean statelessBean = (SessionBean) enterpriseBean; 146 gbean.setAttribute(EjbInterface.SERVICE_ENDPOINT.getAttributeName(), statelessBean.getServiceEndpoint()); 147 } 148 } 149 150 // set reference patterns 151 gbean.setReferencePattern("TrackedConnectionAssociator", new AbstractNameQuery(null, Collections.EMPTY_MAP, TrackedConnectionAssociator.class.getName())); 152 gbean.setReferencePattern("OpenEjbSystem", new AbstractNameQuery(null, Collections.EMPTY_MAP, OpenEjbSystem.class.getName())); 153 154 try { 155 earContext.addGBean(gbean); 156 } catch (GBeanAlreadyExistsException e) { 157 throw new DeploymentException("Could not add entity bean to context", e); 158 } 159 gbeans.put(ejbName, gbean); 160 } 161 } 162 163 164 public void addEjbModuleDependency(AbstractName ejbModuleName) { 165 for (GBeanData gbean : gbeans.values()) { 166 gbean.addDependency(ejbModuleName); 167 } 168 } 169 170 public ComponentPermissions buildComponentPermissions() throws DeploymentException { 171 ComponentPermissions componentPermissions = new ComponentPermissions(new Permissions(), new Permissions(), new HashMap<String, PermissionCollection>()); 172 for (EnterpriseBean enterpriseBean : ejbModule.getEjbJar().getEnterpriseBeans()) { 173 addSecurityData(enterpriseBean, componentPermissions); 174 } 175 return componentPermissions; 176 } 177 178 private void addSecurityData(EnterpriseBean enterpriseBean, ComponentPermissions componentPermissions) throws DeploymentException { 179 SecurityConfiguration securityConfiguration = (SecurityConfiguration) earContext.getSecurityConfiguration(); 180 if (securityConfiguration != null) { 181 GBeanData gbean = getEjbGBean(enterpriseBean.getEjbName()); 182 if (enterpriseBean instanceof RemoteBean) { 183 RemoteBean remoteBean = (RemoteBean) enterpriseBean; 184 185 SecurityBuilder securityBuilder = new SecurityBuilder(); 186 PermissionCollection permissions = new Permissions(); 187 188 securityBuilder.addToPermissions(permissions, 189 remoteBean.getEjbName(), 190 EjbInterface.HOME.getJaccInterfaceName(), 191 remoteBean.getHome(), 192 ejbModule.getClassLoader()); 193 securityBuilder.addToPermissions(permissions, 194 remoteBean.getEjbName(), 195 EjbInterface.REMOTE.getJaccInterfaceName(), 196 remoteBean.getRemote(), 197 ejbModule.getClassLoader()); 198 securityBuilder.addToPermissions(permissions, 199 remoteBean.getEjbName(), 200 EjbInterface.LOCAL.getJaccInterfaceName(), 201 remoteBean.getLocal(), 202 ejbModule.getClassLoader()); 203 securityBuilder.addToPermissions(permissions, 204 remoteBean.getEjbName(), 205 EjbInterface.LOCAL_HOME.getJaccInterfaceName(), 206 remoteBean.getLocalHome(), 207 ejbModule.getClassLoader()); 208 if (remoteBean instanceof SessionBean) { 209 securityBuilder.addToPermissions(permissions, 210 remoteBean.getEjbName(), 211 EjbInterface.SERVICE_ENDPOINT.getJaccInterfaceName(), 212 ((SessionBean) remoteBean).getServiceEndpoint(), 213 ejbModule.getClassLoader()); 214 } 215 if (remoteBean.getBusinessRemote() != null && !remoteBean.getBusinessRemote().isEmpty()) { 216 for (String businessRemote : remoteBean.getBusinessRemote()) { 217 securityBuilder.addToPermissions(permissions, 218 remoteBean.getEjbName(), 219 EjbInterface.REMOTE.getJaccInterfaceName(), 220 businessRemote, 221 ejbModule.getClassLoader()); 222 } 223 securityBuilder.addToPermissions(componentPermissions.getUncheckedPermissions(), 224 remoteBean.getEjbName(), 225 EjbInterface.HOME.getJaccInterfaceName(), 226 DeploymentInfo.BusinessRemoteHome.class.getName(), 227 ejbModule.getClassLoader()); 228 } 229 if (remoteBean.getBusinessLocal() != null && !remoteBean.getBusinessLocal().isEmpty()) { 230 for (String businessLocal : remoteBean.getBusinessLocal()) { 231 securityBuilder.addToPermissions(permissions, 232 remoteBean.getEjbName(), 233 EjbInterface.LOCAL.getJaccInterfaceName(), 234 businessLocal, 235 ejbModule.getClassLoader()); 236 } 237 securityBuilder.addToPermissions(componentPermissions.getUncheckedPermissions(), 238 remoteBean.getEjbName(), 239 EjbInterface.LOCAL_HOME.getJaccInterfaceName(), 240 DeploymentInfo.BusinessLocalHome.class.getName(), 241 ejbModule.getClassLoader()); 242 } 243 244 String defaultRole = securityConfiguration.getDefaultRole(); 245 securityBuilder.addComponentPermissions(defaultRole, 246 permissions, 247 ejbModule.getEjbJar().getAssemblyDescriptor(), 248 enterpriseBean.getEjbName(), 249 remoteBean.getSecurityRoleRef(), 250 componentPermissions); 251 252 } 253 // RunAs subject 254 SecurityIdentity securityIdentity = enterpriseBean.getSecurityIdentity(); 255 if (securityIdentity != null && securityIdentity.getRunAs() != null) { 256 String runAsName = securityIdentity.getRunAs(); 257 if (runAsName != null) { 258 gbean.setAttribute("runAsRole", runAsName); 259 } 260 } 261 262 gbean.setAttribute("securityEnabled", true); 263 gbean.setReferencePattern("RunAsSource", earContext.getJaccManagerName()); 264 } 265 } 266 267 public void buildEnc() throws DeploymentException { 268 // 269 // XMLBeans types must be use because Geronimo naming building is coupled via XMLBeans objects 270 // 271 272 EjbJarType ejbJarType = (EjbJarType) ejbModule.getSpecDD(); 273 274 if (!ejbJarType.getMetadataComplete()) { 275 // Create a classfinder and populate it for the naming builder(s). The absence of a 276 // classFinder in the module will convey whether metadata-complete is set (or not) 277 ejbModule.setClassFinder(createEjbJarClassFinder(ejbModule)); 278 } 279 280 EnterpriseBeansType enterpriseBeans = ejbJarType.getEnterpriseBeans(); 281 if (enterpriseBeans != null) { 282 for (SessionBeanType xmlbeansEjb : enterpriseBeans.getSessionArray()) { 283 String ejbName = xmlbeansEjb.getEjbName().getStringValue().trim(); 284 GBeanData gbean = getEjbGBean(ejbName); 285 ResourceRefType[] resourceRefs = xmlbeansEjb.getResourceRefArray(); 286 addEnc(gbean, xmlbeansEjb, resourceRefs); 287 } 288 for (MessageDrivenBeanType xmlbeansEjb : enterpriseBeans.getMessageDrivenArray()) { 289 String ejbName = xmlbeansEjb.getEjbName().getStringValue().trim(); 290 GBeanData gbean = getEjbGBean(ejbName); 291 ResourceRefType[] resourceRefs = xmlbeansEjb.getResourceRefArray(); 292 addEnc(gbean, xmlbeansEjb, resourceRefs); 293 } 294 for (EntityBeanType xmlbeansEjb : enterpriseBeans.getEntityArray()) { 295 String ejbName = xmlbeansEjb.getEjbName().getStringValue().trim(); 296 GBeanData gbean = getEjbGBean(ejbName); 297 ResourceRefType[] resourceRefs = xmlbeansEjb.getResourceRefArray(); 298 addEnc(gbean, xmlbeansEjb, resourceRefs); 299 } 300 301 } 302 303 if (!ejbJarType.getMetadataComplete()) { 304 ejbJarType.setMetadataComplete(true); 305 ejbModule.setOriginalSpecDD(ejbModule.getSpecDD().toString()); 306 } 307 } 308 309 private void addEnc(GBeanData gbean, XmlObject xmlbeansEjb, ResourceRefType[] resourceRefs) throws DeploymentException { 310 OpenejbGeronimoEjbJarType geronimoOpenejb = ejbModule.getVendorDD(); 311 312 // 313 // Build ENC 314 // 315 316 // Geronimo uses a map to pass data to the naming build and for the results data 317 Map<Object, Object> buildingContext = new HashMap<Object, Object>(); 318 buildingContext.put(NamingBuilder.GBEAN_NAME_KEY, gbean.getAbstractName()); 319 ((AnnotatedEjbJar) ejbModule.getAnnotatedApp()).setBean(xmlbeansEjb); 320 321 namingBuilder.buildNaming(xmlbeansEjb, 322 geronimoOpenejb, 323 ejbModule, buildingContext); 324 325 Map compContext = NamingBuilder.JNDI_KEY.get(buildingContext); 326 gbean.setAttribute("componentContextMap", compContext); 327 328 // 329 // Process resource refs 330 // 331 GerResourceRefType[] gerResourceRefs = null; 332 333 if (geronimoOpenejb != null) { 334 gerResourceRefs = geronimoOpenejb.getResourceRefArray(); 335 } 336 337 GBeanResourceEnvironmentBuilder refBuilder = new GBeanResourceEnvironmentBuilder(gbean); 338 resourceEnvironmentSetter.setResourceEnvironment(refBuilder, resourceRefs, gerResourceRefs); 339 } 340 341 private ClassFinder createEjbJarClassFinder(EjbModule ejbModule) throws DeploymentException { 342 343 try { 344 // Get the classloader from the module's EARContext 345 ClassLoader classLoader = ejbModule.getEarContext().getClassLoader(); 346 347 //---------------------------------------------------------------------------------------- 348 // Find the list of classes from the ejb-jar.xml we want to search for annotations in 349 //---------------------------------------------------------------------------------------- 350 List<Class> classes = new ArrayList<Class>(); 351 352 for (EnterpriseBean bean : ejbModule.getEjbJar().getEnterpriseBeans()) { 353 classes.add(classLoader.loadClass(bean.getEjbClass())); 354 } 355 356 return new ClassFinder(classes); 357 } catch (ClassNotFoundException e) { 358 throw new DeploymentException("Unable to load bean class.", e); 359 } 360 } 361 362 private GBeanData getEjbGBean(String ejbName) throws DeploymentException { 363 GBeanData gbean = gbeans.get(ejbName); 364 if (gbean == null) throw new DeploymentException("EJB not gbean not found " + ejbName); 365 return gbean; 366 } 367 368 private AbstractName createEjbName(EnterpriseBean enterpriseBean) { 369 String ejbName = enterpriseBean.getEjbName(); 370 String type = null; 371 if (enterpriseBean instanceof SessionBean) { 372 SessionBean sessionBean = (SessionBean) enterpriseBean; 373 switch (sessionBean.getSessionType()) { 374 case STATELESS: 375 type = NameFactory.STATELESS_SESSION_BEAN; 376 break; 377 case STATEFUL: 378 type = NameFactory.STATEFUL_SESSION_BEAN; 379 break; 380 } 381 } else if (enterpriseBean instanceof EntityBean) { 382 type = NameFactory.ENTITY_BEAN; 383 } else if (enterpriseBean instanceof MessageDrivenBean) { 384 type = NameFactory.MESSAGE_DRIVEN_BEAN; 385 } 386 if (type == null) { 387 throw new IllegalArgumentException("Unknown enterprise bean type XXX " + enterpriseBean.getClass().getName()); 388 } 389 return earContext.getNaming().createChildName(ejbModule.getModuleName(), ejbName, type); 390 } 391 392 private static Class assureEJBObjectInterface(String remote, ClassLoader cl) throws DeploymentException { 393 return AbstractNamingBuilder.assureInterface(remote, "javax.ejb.EJBObject", "Remote", cl); 394 } 395 396 private static Class assureEJBHomeInterface(String home, ClassLoader cl) throws DeploymentException { 397 return AbstractNamingBuilder.assureInterface(home, "javax.ejb.EJBHome", "Home", cl); 398 } 399 400 public static Class assureEJBLocalObjectInterface(String local, ClassLoader cl) throws DeploymentException { 401 return AbstractNamingBuilder.assureInterface(local, "javax.ejb.EJBLocalObject", "Local", cl); 402 } 403 404 public static Class assureEJBLocalHomeInterface(String localHome, ClassLoader cl) throws DeploymentException { 405 return AbstractNamingBuilder.assureInterface(localHome, "javax.ejb.EJBLocalHome", "LocalHome", cl); 406 } 407 }