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