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 }