001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.ejb.plugins.local;
023:
024: import java.lang.reflect.InvocationHandler;
025: import java.lang.reflect.Method;
026: import java.lang.reflect.Proxy;
027: import java.lang.reflect.Constructor;
028: import java.rmi.AccessException;
029: import java.rmi.NoSuchObjectException;
030: import java.security.Principal;
031: import java.security.PrivilegedAction;
032: import java.security.AccessController;
033: import java.util.ArrayList;
034: import java.util.Collection;
035: import java.util.Collections;
036: import java.util.HashMap;
037: import java.util.Iterator;
038: import java.util.Map;
039: import javax.ejb.AccessLocalException;
040: import javax.ejb.EJBLocalHome;
041: import javax.ejb.EJBLocalObject;
042: import javax.ejb.NoSuchObjectLocalException;
043: import javax.ejb.TransactionRequiredLocalException;
044: import javax.ejb.TransactionRolledbackLocalException;
045: import javax.naming.Context;
046: import javax.naming.InitialContext;
047: import javax.transaction.Transaction;
048: import javax.transaction.TransactionManager;
049: import javax.transaction.TransactionRequiredException;
050: import javax.transaction.TransactionRolledbackException;
051:
052: import org.jboss.ejb.Container;
053: import org.jboss.ejb.EJBProxyFactoryContainer;
054: import org.jboss.ejb.LocalProxyFactory;
055: import org.jboss.invocation.InvocationType;
056: import org.jboss.invocation.MarshalledInvocation;
057: import org.jboss.invocation.LocalEJBInvocation;
058: import org.jboss.logging.Logger;
059: import org.jboss.metadata.BeanMetaData;
060: import org.jboss.util.naming.Util;
061: import org.jboss.security.SecurityAssociation;
062: import org.jboss.util.NestedRuntimeException;
063: import org.jboss.tm.TransactionLocal;
064:
065: /**
066: * The LocalProxyFactory implementation that handles local ejb interface
067: * proxies.
068: *
069: * @author <a href="mailto:docodan@mvcsoft.com">Daniel OConnor</a>
070: * @author <a href="mailto:scott.stark@jboss.org">Scott Stark</a>
071: * @author <a href="mailto:dain@daingroup.com">Dain Sundstrom</a>
072: * @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
073: * $Revision: 57209 $
074: */
075: public class BaseLocalProxyFactory implements LocalProxyFactory {
076: // Attributes ----------------------------------------------------
077: protected static Logger log = Logger
078: .getLogger(BaseLocalProxyFactory.class);
079:
080: /**
081: * A map of the BaseLocalProxyFactory instances keyed by localJndiName
082: */
083: protected static Map invokerMap = Collections
084: .synchronizedMap(new HashMap());
085:
086: protected Container container;
087:
088: /**
089: * The JNDI name of the local home interface binding
090: */
091: protected String localJndiName;
092:
093: protected TransactionManager transactionManager;
094:
095: // The home can be one.
096: protected EJBLocalHome home;
097:
098: // The Stateless Object can be one.
099: protected EJBLocalObject statelessObject;
100:
101: protected Map beanMethodInvokerMap;
102: protected Map homeMethodInvokerMap;
103: protected Class localHomeClass;
104: protected Class localClass;
105:
106: protected Constructor proxyClassConstructor;
107:
108: private final TransactionLocal cache = new TransactionLocal() {
109: protected Object initialValue() {
110: return new HashMap();
111: }
112: };
113:
114: // Static --------------------------------------------------------
115:
116: // Constructors --------------------------------------------------
117:
118: // Public --------------------------------------------------------
119:
120: // ContainerService implementation -------------------------------
121:
122: public void setContainer(Container con) {
123: this .container = con;
124: }
125:
126: public void create() throws Exception {
127: BeanMetaData metaData = container.getBeanMetaData();
128: localJndiName = metaData.getLocalJndiName();
129: }
130:
131: public void start() throws Exception {
132: BeanMetaData metaData = container.getBeanMetaData();
133: EJBProxyFactoryContainer invokerContainer = (EJBProxyFactoryContainer) container;
134: localHomeClass = invokerContainer.getLocalHomeClass();
135: localClass = invokerContainer.getLocalClass();
136: if (localHomeClass == null || localClass == null) {
137: log.debug(metaData.getEjbName()
138: + " cannot be Bound, doesn't "
139: + "have local and local home interfaces");
140: return;
141: }
142:
143: // this is faster than newProxyInstance
144: Class[] intfs = { localClass };
145: Class proxyClass = Proxy.getProxyClass(ClassLoaderAction.UTIL
146: .get(localClass), intfs);
147: final Class[] constructorParams = { InvocationHandler.class };
148:
149: proxyClassConstructor = proxyClass
150: .getConstructor(constructorParams);
151:
152: Context iniCtx = new InitialContext();
153: String beanName = metaData.getEjbName();
154:
155: // Set the transaction manager and transaction propagation
156: // context factory of the GenericProxy class
157: transactionManager = (TransactionManager) iniCtx
158: .lookup("java:/TransactionManager");
159:
160: // Create method mappings for container invoker
161: Method[] methods = localClass.getMethods();
162: beanMethodInvokerMap = new HashMap();
163: for (int i = 0; i < methods.length; i++) {
164: long hash = MarshalledInvocation.calculateHash(methods[i]);
165: beanMethodInvokerMap.put(new Long(hash), methods[i]);
166: }
167:
168: methods = localHomeClass.getMethods();
169: homeMethodInvokerMap = new HashMap();
170: for (int i = 0; i < methods.length; i++) {
171: long hash = MarshalledInvocation.calculateHash(methods[i]);
172: homeMethodInvokerMap.put(new Long(hash), methods[i]);
173: }
174:
175: // bind that referance to my name
176: Util.rebind(iniCtx, localJndiName, getEJBLocalHome());
177: invokerMap.put(localJndiName, this );
178: log.info("Bound EJB LocalHome '" + beanName + "' to jndi '"
179: + localJndiName + "'");
180: }
181:
182: public void stop() {
183: // Clean up the home proxy binding
184: try {
185: if (invokerMap.remove(localJndiName) == this ) {
186: log.info("Unbind EJB LocalHome '"
187: + container.getBeanMetaData().getEjbName()
188: + "' from jndi '" + localJndiName + "'");
189:
190: InitialContext ctx = new InitialContext();
191: ctx.unbind(localJndiName);
192: }
193: } catch (Exception ignore) {
194: }
195: }
196:
197: public void destroy() {
198: if (beanMethodInvokerMap != null) {
199: beanMethodInvokerMap.clear();
200: }
201: if (homeMethodInvokerMap != null) {
202: homeMethodInvokerMap.clear();
203: }
204: MarshalledInvocation.removeHashes(localHomeClass);
205: MarshalledInvocation.removeHashes(localClass);
206:
207: container = null;
208: }
209:
210: public Constructor getProxyClassConstructor() {
211: if (proxyClassConstructor == null) {
212: }
213: return proxyClassConstructor;
214: }
215:
216: // EJBProxyFactory implementation -------------------------------
217: public EJBLocalHome getEJBLocalHome() {
218: if (home == null) {
219: EJBProxyFactoryContainer cic = (EJBProxyFactoryContainer) container;
220: InvocationHandler handler = new LocalHomeProxy(
221: localJndiName, this );
222: ClassLoader loader = ClassLoaderAction.UTIL.get(cic
223: .getLocalHomeClass());
224: Class[] interfaces = { cic.getLocalHomeClass() };
225:
226: home = (EJBLocalHome) Proxy.newProxyInstance(loader,
227: interfaces, handler);
228: }
229: return home;
230: }
231:
232: public EJBLocalObject getStatelessSessionEJBLocalObject() {
233: if (statelessObject == null) {
234: EJBProxyFactoryContainer cic = (EJBProxyFactoryContainer) container;
235: InvocationHandler handler = new StatelessSessionProxy(
236: localJndiName, this );
237: ClassLoader loader = ClassLoaderAction.UTIL.get(cic
238: .getLocalClass());
239: Class[] interfaces = { cic.getLocalClass() };
240:
241: statelessObject = (EJBLocalObject) Proxy.newProxyInstance(
242: loader, interfaces, handler);
243: }
244: return statelessObject;
245: }
246:
247: public EJBLocalObject getStatefulSessionEJBLocalObject(Object id) {
248: InvocationHandler handler = new StatefulSessionProxy(
249: localJndiName, id, this );
250: try {
251: return (EJBLocalObject) proxyClassConstructor
252: .newInstance(new Object[] { handler });
253: } catch (Exception ex) {
254: throw new NestedRuntimeException(ex);
255: }
256: }
257:
258: public Object getEntityEJBObject(Object id) {
259: return getEntityEJBLocalObject(id);
260: }
261:
262: public EJBLocalObject getEntityEJBLocalObject(Object id,
263: boolean create) {
264: EJBLocalObject result = null;
265: if (id != null) {
266: final Transaction tx = cache.getTransaction();
267: if (tx == null) {
268: result = createEJBLocalObject(id);
269: } else {
270: Map map = (Map) cache.get(tx);
271: if (create) {
272: result = createEJBLocalObject(id);
273: map.put(id, result);
274: } else {
275: result = (EJBLocalObject) map.get(id);
276: if (result == null) {
277: result = createEJBLocalObject(id);
278: map.put(id, result);
279: }
280: }
281: }
282: }
283: return result;
284: }
285:
286: public EJBLocalObject getEntityEJBLocalObject(Object id) {
287: return getEntityEJBLocalObject(id, false);
288: }
289:
290: public Collection getEntityLocalCollection(Collection ids) {
291: ArrayList list = new ArrayList(ids.size());
292: Iterator iter = ids.iterator();
293: while (iter.hasNext()) {
294: final Object nextId = iter.next();
295: list.add(getEntityEJBLocalObject(nextId));
296: }
297: return list;
298: }
299:
300: /**
301: * Invoke a Home interface method.
302: */
303: public Object invokeHome(Method m, Object[] args) throws Exception {
304: // Set the right context classloader
305: ClassLoader oldCl = TCLAction.UTIL.getContextClassLoader();
306: boolean setCl = !oldCl.equals(container.getClassLoader());
307: if (setCl) {
308: TCLAction.UTIL.setContextClassLoader(container
309: .getClassLoader());
310: }
311:
312: SecurityActions sa = SecurityActions.UTIL.getSecurityActions();
313: try {
314: LocalEJBInvocation invocation = new LocalEJBInvocation(
315: null, m, args, getTransaction(), sa.getPrincipal(),
316: sa.getCredential());
317: invocation.setType(InvocationType.LOCALHOME);
318:
319: return container.invoke(invocation);
320: } catch (AccessException ae) {
321: throw new AccessLocalException(ae.getMessage(), ae);
322: } catch (NoSuchObjectException nsoe) {
323: throw new NoSuchObjectLocalException(nsoe.getMessage(),
324: nsoe);
325: } catch (TransactionRequiredException tre) {
326: throw new TransactionRequiredLocalException(tre
327: .getMessage());
328: } catch (TransactionRolledbackException trbe) {
329: throw new TransactionRolledbackLocalException(trbe
330: .getMessage(), trbe);
331: } finally {
332: if (setCl) {
333: TCLAction.UTIL.setContextClassLoader(oldCl);
334: }
335: }
336: }
337:
338: public String getJndiName() {
339: return localJndiName;
340: }
341:
342: /**
343: * Return the transaction associated with the current thread.
344: * Returns <code>null</code> if the transaction manager was never
345: * set, or if no transaction is associated with the current thread.
346: */
347: Transaction getTransaction()
348: throws javax.transaction.SystemException {
349: if (transactionManager == null) {
350: return null;
351: }
352: return transactionManager.getTransaction();
353: }
354:
355: /**
356: * Invoke a local interface method.
357: */
358: public Object invoke(Object id, Method m, Object[] args)
359: throws Exception {
360: // Set the right context classloader
361: ClassLoader oldCl = TCLAction.UTIL.getContextClassLoader();
362: boolean setCl = !oldCl.equals(container.getClassLoader());
363: if (setCl) {
364: TCLAction.UTIL.setContextClassLoader(container
365: .getClassLoader());
366: }
367:
368: SecurityActions sa = SecurityActions.UTIL.getSecurityActions();
369: try {
370: LocalEJBInvocation invocation = new LocalEJBInvocation(id,
371: m, args, getTransaction(), sa.getPrincipal(), sa
372: .getCredential());
373: invocation.setType(InvocationType.LOCAL);
374:
375: return container.invoke(invocation);
376: } catch (AccessException ae) {
377: throw new AccessLocalException(ae.getMessage(), ae);
378: } catch (NoSuchObjectException nsoe) {
379: throw new NoSuchObjectLocalException(nsoe.getMessage(),
380: nsoe);
381: } catch (TransactionRequiredException tre) {
382: throw new TransactionRequiredLocalException(tre
383: .getMessage());
384: } catch (TransactionRolledbackException trbe) {
385: throw new TransactionRolledbackLocalException(trbe
386: .getMessage(), trbe);
387: } finally {
388: if (setCl) {
389: TCLAction.UTIL.setContextClassLoader(oldCl);
390: }
391: }
392: }
393:
394: private EJBLocalObject createEJBLocalObject(Object id) {
395: InvocationHandler handler = new EntityProxy(localJndiName, id,
396: this );
397: try {
398: return (EJBLocalObject) proxyClassConstructor
399: .newInstance(new Object[] { handler });
400: } catch (Exception ex) {
401: throw new NestedRuntimeException(ex);
402: }
403: }
404:
405: interface ClassLoaderAction {
406: class UTIL {
407: static ClassLoaderAction getClassLoaderAction() {
408: return System.getSecurityManager() == null ? NON_PRIVILEGED
409: : PRIVILEGED;
410: }
411:
412: static ClassLoader get(Class clazz) {
413: return getClassLoaderAction().get(clazz);
414: }
415: }
416:
417: ClassLoaderAction PRIVILEGED = new ClassLoaderAction() {
418: public ClassLoader get(final Class clazz) {
419: return (ClassLoader) AccessController
420: .doPrivileged(new PrivilegedAction() {
421: public Object run() {
422: return clazz.getClassLoader();
423: }
424: });
425: }
426: };
427:
428: ClassLoaderAction NON_PRIVILEGED = new ClassLoaderAction() {
429: public ClassLoader get(Class clazz) {
430: return clazz.getClassLoader();
431: }
432: };
433:
434: ClassLoader get(Class clazz);
435: }
436:
437: interface SecurityActions {
438: class UTIL {
439: static SecurityActions getSecurityActions() {
440: return System.getSecurityManager() == null ? NON_PRIVILEGED
441: : PRIVILEGED;
442: }
443: }
444:
445: SecurityActions NON_PRIVILEGED = new SecurityActions() {
446: public Principal getPrincipal() {
447: return SecurityAssociation.getPrincipal();
448: }
449:
450: public Object getCredential() {
451: return SecurityAssociation.getCredential();
452: }
453: };
454:
455: SecurityActions PRIVILEGED = new SecurityActions() {
456: private final PrivilegedAction getPrincipalAction = new PrivilegedAction() {
457: public Object run() {
458: return SecurityAssociation.getPrincipal();
459: }
460: };
461:
462: private final PrivilegedAction getCredentialAction = new PrivilegedAction() {
463: public Object run() {
464: return SecurityAssociation.getCredential();
465: }
466: };
467:
468: public Principal getPrincipal() {
469: return (Principal) AccessController
470: .doPrivileged(getPrincipalAction);
471: }
472:
473: public Object getCredential() {
474: return AccessController
475: .doPrivileged(getCredentialAction);
476: }
477: };
478:
479: Principal getPrincipal();
480:
481: Object getCredential();
482: }
483:
484: interface TCLAction {
485: class UTIL {
486: static TCLAction getTCLAction() {
487: return System.getSecurityManager() == null ? NON_PRIVILEGED
488: : PRIVILEGED;
489: }
490:
491: static ClassLoader getContextClassLoader() {
492: return getTCLAction().getContextClassLoader();
493: }
494:
495: static ClassLoader getContextClassLoader(Thread thread) {
496: return getTCLAction().getContextClassLoader(thread);
497: }
498:
499: static void setContextClassLoader(ClassLoader cl) {
500: getTCLAction().setContextClassLoader(cl);
501: }
502:
503: static void setContextClassLoader(Thread thread,
504: ClassLoader cl) {
505: getTCLAction().setContextClassLoader(thread, cl);
506: }
507: }
508:
509: TCLAction NON_PRIVILEGED = new TCLAction() {
510: public ClassLoader getContextClassLoader() {
511: return Thread.currentThread().getContextClassLoader();
512: }
513:
514: public ClassLoader getContextClassLoader(Thread thread) {
515: return thread.getContextClassLoader();
516: }
517:
518: public void setContextClassLoader(ClassLoader cl) {
519: Thread.currentThread().setContextClassLoader(cl);
520: }
521:
522: public void setContextClassLoader(Thread thread,
523: ClassLoader cl) {
524: thread.setContextClassLoader(cl);
525: }
526: };
527:
528: TCLAction PRIVILEGED = new TCLAction() {
529: private final PrivilegedAction getTCLPrivilegedAction = new PrivilegedAction() {
530: public Object run() {
531: return Thread.currentThread()
532: .getContextClassLoader();
533: }
534: };
535:
536: public ClassLoader getContextClassLoader() {
537: return (ClassLoader) AccessController
538: .doPrivileged(getTCLPrivilegedAction);
539: }
540:
541: public ClassLoader getContextClassLoader(final Thread thread) {
542: return (ClassLoader) AccessController
543: .doPrivileged(new PrivilegedAction() {
544: public Object run() {
545: return thread.getContextClassLoader();
546: }
547: });
548: }
549:
550: public void setContextClassLoader(final ClassLoader cl) {
551: AccessController.doPrivileged(new PrivilegedAction() {
552: public Object run() {
553: Thread.currentThread()
554: .setContextClassLoader(cl);
555: return null;
556: }
557: });
558: }
559:
560: public void setContextClassLoader(final Thread thread,
561: final ClassLoader cl) {
562: AccessController.doPrivileged(new PrivilegedAction() {
563: public Object run() {
564: thread.setContextClassLoader(cl);
565: return null;
566: }
567: });
568: }
569: };
570:
571: ClassLoader getContextClassLoader();
572:
573: ClassLoader getContextClassLoader(Thread thread);
574:
575: void setContextClassLoader(ClassLoader cl);
576:
577: void setContextClassLoader(Thread thread, ClassLoader cl);
578: }
579: }
|