001: /**
002: * JOnAS: Java(TM) Open Application Server
003: * Copyright (C) 1999-2005 Bull S.A.
004: * Contact: jonas-team@objectweb.org
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2.1 of the License, or any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
019: * USA
020: *
021: * --------------------------------------------------------------------------
022: * $Id: JMdbEndpointFactory.java 10144 2007-04-05 06:48:57Z durieuxp $
023: * --------------------------------------------------------------------------
024: */package org.objectweb.jonas_ejb.container;
025:
026: import java.lang.reflect.Method;
027: import java.lang.reflect.Proxy;
028: import java.util.ArrayList;
029: import java.util.LinkedList;
030: import java.util.List;
031: import java.util.ListIterator;
032:
033: import javax.ejb.EJBException;
034: import javax.ejb.MessageDrivenBean;
035: import javax.ejb.MessageDrivenContext;
036: import javax.ejb.Timer;
037: import javax.ejb.TimerService;
038: import javax.naming.Context;
039: import javax.resource.spi.ActivationSpec;
040: import javax.resource.spi.UnavailableException;
041: import javax.resource.spi.endpoint.MessageEndpoint;
042: import javax.resource.spi.endpoint.MessageEndpointFactory;
043: import javax.transaction.SystemException;
044: import javax.transaction.Transaction;
045: import javax.transaction.xa.XAResource;
046:
047: import org.objectweb.jotm.Current;
048:
049: import org.objectweb.jonas_ejb.deployment.api.ActivationConfigPropertyDesc;
050: import org.objectweb.jonas_ejb.deployment.api.MessageDrivenDesc;
051: import org.objectweb.jonas_ejb.deployment.api.MethodDesc;
052:
053: import org.objectweb.jonas.resource.Rar;
054:
055: import org.objectweb.util.monolog.api.BasicLevel;
056:
057: /**
058: * This class is a factory for a Message Driven Bean Endpoints There is one such
059: * class per MDB class. Contains all information related to the bean
060: * @author Eric Hardesty
061: */
062: public class JMdbEndpointFactory extends JFactory implements
063: MessageEndpointFactory {
064:
065: /**
066: * pool of JMessageEndpoint objects
067: */
068: private List endpool = new ArrayList();
069:
070: /**
071: * count of the instances
072: */
073: private int instanceCount = 0;
074:
075: /**
076: * minimum pool size
077: */
078: private int minPoolSize = 0;
079:
080: /**
081: * maximum number of instances in the cache
082: */
083: private int maxCacheSize = 0;
084:
085: /**
086: * ActivationSpec associated with this factory
087: */
088: private ActivationSpec as = null;
089:
090: /**
091: * Message listener type
092: */
093: private String msglistenType = null;
094:
095: /**
096: * Associated RAR object
097: */
098: private Rar rar = null;
099:
100: /**
101: * activated indicator
102: */
103: private boolean activated = false;
104:
105: /**
106: * Constructor
107: * @param dd Message Driven Descriptor
108: * @param cont Container where this bean is defined
109: * @param as ActivationSpec to link the Container to
110: */
111: public JMdbEndpointFactory(MessageDrivenDesc dd, JContainer cont,
112: ActivationSpec as) {
113: super (dd, cont);
114: String dest = dd.getDestinationJndiName();
115: // Set the AS properties and validate the required config properties
116: List acpl = null;
117: if (dd.getMdActivationConfigDesc() != null) {
118: acpl = dd.getMdActivationConfigDesc()
119: .getActivationConfigPropertyList();
120: }
121: List jAcpl = null;
122: if (dd.getJonasMdActivationConfigDesc() != null) {
123: jAcpl = dd.getJonasMdActivationConfigDesc()
124: .getActivationConfigPropertyList();
125: }
126: mdbEFInit(dd, dest, acpl, jAcpl, as);
127: }
128:
129: /**
130: * Constructor
131: * @param dd Message Driven Descriptor
132: * @param destination String of desired destination
133: * @param cont Container where this bean is defined
134: * @param as ActivationSpec to link the Container to
135: */
136: public JMdbEndpointFactory(MessageDrivenDesc dd,
137: String destination, JContainer cont, ActivationSpec as) {
138: super (dd, cont);
139:
140: // Build Activation spec linked list from variables
141:
142: List jAcpl = new LinkedList();
143: List acpl = null;
144: if (dd.getMdActivationConfigDesc() != null) {
145: acpl = dd.getMdActivationConfigDesc()
146: .getActivationConfigPropertyList();
147: }
148: buildACL(dd, jAcpl);
149:
150: mdbEFInit(dd, destination, acpl, jAcpl, as);
151: }
152:
153: /**
154: * Create the ActivationConfigProperty List
155: * @param dd MessageDrivenDesc
156: * @param jacl List to update
157: */
158: private void buildACL(MessageDrivenDesc dd, List jacl) {
159:
160: String[] aclNames = { "destination", "destinationType",
161: "messageSelector", "acknowledgeMode",
162: "subscriptionDurability" };
163:
164: ActivationConfigPropertyDesc acp = null;
165:
166: acp = new ActivationConfigPropertyDesc();
167: acp.setActivationConfigPropertyName("destination");
168: acp.setActivationConfigPropertyValue(dd
169: .getDestinationJndiName());
170: jacl.add(acp);
171:
172: acp = new ActivationConfigPropertyDesc();
173: acp.setActivationConfigPropertyName("destinationType");
174: if (dd.isTopicDestination()) {
175: acp.setActivationConfigPropertyValue("javax.jms.Topic");
176: } else {
177: acp.setActivationConfigPropertyValue("javax.jms.Queue");
178: }
179: jacl.add(acp);
180:
181: acp = new ActivationConfigPropertyDesc();
182: acp.setActivationConfigPropertyName("messageSelector");
183: acp.setActivationConfigPropertyValue(dd.getSelector());
184: jacl.add(acp);
185:
186: acp = new ActivationConfigPropertyDesc();
187: acp.setActivationConfigPropertyName("acknowledgeMode");
188: if (dd.getAcknowledgeMode() == MessageDrivenDesc.AUTO_ACKNOWLEDGE) {
189: acp.setActivationConfigPropertyValue("Auto-acknowledge");
190: } else {
191: acp.setActivationConfigPropertyValue("Dups-ok-acknowledge");
192: }
193: jacl.add(acp);
194:
195: acp = new ActivationConfigPropertyDesc();
196: acp.setActivationConfigPropertyName("subscriptionDurability");
197: if (dd.getSubscriptionDurability() == MessageDrivenDesc.SUBS_DURABLE) {
198: acp.setActivationConfigPropertyValue("Durable");
199: } else {
200: acp.setActivationConfigPropertyValue("NonDurable");
201: }
202: jacl.add(acp);
203:
204: if (dd.getSubscriptionDurability() == MessageDrivenDesc.SUBS_DURABLE) {
205: acp = new ActivationConfigPropertyDesc();
206: acp.setActivationConfigPropertyName("subscriptionName");
207: acp.setActivationConfigPropertyValue(dd.getEjbName());
208: jacl.add(acp);
209: }
210:
211: // Check existing list to determine if additional items are configured, then pass them along also
212: List acpl = null;
213: if (dd.getJonasMdActivationConfigDesc() != null) {
214: acpl = dd.getJonasMdActivationConfigDesc()
215: .getActivationConfigPropertyList();
216:
217: String acpName = null;
218: boolean found = false;
219: for (int i = 0; i < acpl.size(); i++) {
220: acp = (ActivationConfigPropertyDesc) acpl.get(i);
221: acpName = acp.getActivationConfigPropertyName();
222: found = false;
223: for (int j = 0; j < aclNames.length; j++) {
224: if (acpName.equals(aclNames[j])) {
225: found = true;
226: break;
227: }
228: }
229: if (!found) {
230: jacl.add(acp);
231: }
232: }
233:
234: }
235: }
236:
237: /**
238: * Init this endpointfactory
239: * @param dd Message Driven Descriptor
240: * @param dest String destination desired
241: * @param acpl List of activation properites
242: * @param jAcpl List of JOnAS activation properites
243: * @param aSpec ActivationSpec to link the Container to
244: */
245: private void mdbEFInit(MessageDrivenDesc dd, String dest,
246: List acpl, List jAcpl, ActivationSpec aSpec) {
247:
248: String methName = "mdbEFInit: ";
249: String ejbName = dd.getEjbName();
250:
251: // Check if tx managed by the bean or the container
252: txbeanmanaged = dd.isBeanManagedTransaction();
253:
254: // Set ActivationSpec
255: as = aSpec;
256:
257: minPoolSize = dd.getPoolMin();
258: maxCacheSize = dd.getCacheMax();
259: if (TraceEjb.isDebugJms()) {
260: TraceEjb.mdb.log(BasicLevel.DEBUG, methName
261: + "maxCacheSize = " + maxCacheSize
262: + " minPoolSize = " + minPoolSize);
263: }
264:
265: // Get the associated Resource Adapter and messagelistenerType
266: rar = Rar.getRar(dest);
267: if (rar == null) {
268: TraceEjb.mdb.log(BasicLevel.ERROR, methName
269: + "cannot retrieve associated Resource Adapter ");
270: throw new EJBException(
271: "cannot retrieve associated Resource Adapter ");
272: }
273: msglistenType = rar.getInterface(dest);
274:
275: try {
276: rar.configureAS(as, acpl, jAcpl, dest, ejbName);
277: } catch (Exception ex) {
278: TraceEjb.mdb.log(BasicLevel.ERROR, methName
279: + "cannot configure activationspec " + ex);
280: ex.printStackTrace();
281: throw new EJBException("cannot configure activationspec ",
282: ex);
283: }
284:
285: // pre-allocate a set of Endpoints
286: synchronized (endpool) {
287: for (int i = 0; i < minPoolSize; i++) {
288: JMessageEndpoint ep = null;
289: ep = createNewInstance();
290: endpool.add(ep);
291: }
292: }
293: if (minPoolSize != 0) {
294: TraceEjb.mdb.log(BasicLevel.INFO, methName
295: + "pre-allocate a set of " + minPoolSize
296: + " message driven bean instances");
297: }
298:
299: // Call to register an XAResource with JOTM
300: try {
301: ActivationSpec[] asArray = new ActivationSpec[1];
302: asArray[0] = as;
303: XAResource[] xar = rar.getResourceAdapter().getXAResources(
304: asArray);
305: if (xar != null && xar.length > 0) {
306: Current.getTransactionRecovery()
307: .registerResourceManager(
308: ejbName + msglistenType, xar[0], "",
309: null);
310: }
311: } catch (Exception ex) {
312: TraceEjb.mdb.log(BasicLevel.ERROR, ex.getMessage(), ex);
313: }
314:
315: activated = true;
316: // EndpointActivation
317: try {
318: rar.getResourceAdapter().endpointActivation(this , as);
319: } catch (Exception ex) {
320: activated = false;
321: TraceEjb.mdb.log(BasicLevel.ERROR, methName
322: + "cannot activate endpoint ", ex);
323: throw new EJBException("cannot activate endpoint ", ex);
324: }
325: }
326:
327: // ---------------------------------------------------------------
328: // Specific BeanFactory implementation
329: // ---------------------------------------------------------------
330:
331: /**
332: * Init pool of instances
333: */
334: public void initInstancePool() {
335: }
336:
337: /**
338: * @return the size of the EndpointPool
339: */
340: public int getPoolSize() {
341: return endpool.size();
342: }
343:
344: /**
345: * stop this EJB. call deactivate on the Endpoint Stop the threads and
346: * remove the beans
347: */
348: public void stop() {
349: String methName = "stop: ";
350: if (TraceEjb.isDebugJms()) {
351: TraceEjb.mdb.log(BasicLevel.DEBUG, methName);
352: }
353: try {
354: // Deactivate the endpoint
355: rar.getResourceAdapter().endpointDeactivation(this , as);
356: // Loop thru the endpool and release them
357: synchronized (endpool) {
358: if (TraceEjb.isDebugJms()) {
359: TraceEjb.mdb.log(BasicLevel.DEBUG, methName
360: + "stopping " + this );
361: }
362: JMessageEndpoint ep = null;
363: while (endpool.size() > 0) {
364: ep = (JMessageEndpoint) endpool.remove(0);
365: instanceCount--;
366: try {
367: ep.mdb.ejbRemove();
368: } catch (Exception e) {
369: TraceEjb.mdb.log(BasicLevel.ERROR, methName
370: + "Cannot remove mdb: " + ep.mdb, e);
371: }
372: }
373: }
374: } catch (Exception e) {
375: TraceEjb.mdb.log(BasicLevel.WARN, methName
376: + "Cannot deactivate the endpoint", e);
377: }
378: stopContainer();
379: }
380:
381: /**
382: * synchronize bean instances if needed
383: */
384: public void syncDirty(boolean notused) {
385: }
386:
387: /**
388: * @return the home if exist
389: */
390: public JHome getHome() {
391: return null;
392: }
393:
394: /**
395: * @return the local home if exist
396: */
397: public JLocalHome getLocalHome() {
398: return null;
399: }
400:
401: // ---------------------------------------------------------------
402: // MessageEndpointFactory implementation
403: // ---------------------------------------------------------------
404:
405: /**
406: * Create the message endpoint
407: *
408: * @param xaResource XAResource object to attach
409: * @return MessageEndpoint to deliver messages to
410: * @throws UnavailableException exception to throw
411: */
412: public MessageEndpoint createEndpoint(XAResource xaResource)
413: throws UnavailableException {
414: String methName = "createEndpoint: ";
415: if (TraceEjb.isDebugJms()) {
416: TraceEjb.mdb.log(BasicLevel.DEBUG, methName);
417: }
418:
419: if (!activated) {
420: TraceEjb.mdb
421: .log(
422: BasicLevel.ERROR,
423: methName
424: + "mdb is not usuable either initial deployment or undeployment ");
425: throw new UnavailableException(
426: "mdb is not usuable either initial deployment or undeployment ");
427: }
428:
429: JMessageEndpoint ep = null;
430: try {
431: ep = getNewInstance(xaResource);
432: } catch (Exception ex) {
433: TraceEjb.mdb.log(BasicLevel.ERROR, methName
434: + "cannot create an endpoint ");
435: throw new UnavailableException(
436: "cannot create an endpoint ", ex);
437: }
438: return ep.mep;
439: }
440:
441: /**
442: * Determine if the method is transacted
443: *
444: * @param method Method to check
445: * @return boolean whether the specified method is transacted
446: * @throws NoSuchMethodException exception to throw
447: */
448: public boolean isDeliveryTransacted(Method method)
449: throws NoSuchMethodException {
450: int txAttribute = 0;
451: try {
452: txAttribute = dd.getMethodDesc(method).getTxAttribute();
453: } catch (Exception ex) {
454: TraceEjb.mdb.log(BasicLevel.ERROR,
455: "isDeliveryTransacted: No such method exists. "
456: + method.getName(), ex);
457: throw new NoSuchMethodException("No such method exists. "
458: + method.getName());
459: }
460: return (txAttribute == MethodDesc.TX_REQUIRED);
461: }
462:
463: // ---------------------------------------------------------------
464: // Other methods
465: // ---------------------------------------------------------------
466:
467: /**
468: * Return an MessageEndpoint from the pool. If pool is empty, creates a new
469: * one.
470: * @return an MessageEndpoint from the pool.
471: * @exception Exception - if an application server fails to return an
472: * MessageEndpoint out of its pool.
473: */
474: public JMessageEndpoint getMessageEndpoint() throws Exception {
475: if (TraceEjb.isDebugJms()) {
476: TraceEjb.mdb.log(BasicLevel.DEBUG, "getMessageEndpoint: ");
477: }
478:
479: return getNewInstance(null);
480: }
481:
482: /**
483: * put the JMessageEndpoint back to the pool
484: * @param ep the MessageEndpoint
485: */
486: public void releaseEndpoint(JMessageEndpoint ep) {
487: String methName = "releaseEndpoint: ";
488: if (TraceEjb.isDebugJms()) {
489: TraceEjb.mdb.log(BasicLevel.DEBUG, methName + ep);
490: }
491:
492: ep.setReleasedState(true);
493: synchronized (endpool) {
494: endpool.add(ep);
495: if (TraceEjb.isDebugJms()) {
496: TraceEjb.mdb.log(BasicLevel.DEBUG, methName
497: + "notifyAll ");
498: }
499: endpool.notifyAll();
500: }
501: if (TraceEjb.isDebugJms()) {
502: TraceEjb.mdb.log(BasicLevel.DEBUG, methName
503: + "nb instances " + getCacheSize());
504: TraceEjb.mdb.log(BasicLevel.DEBUG, methName
505: + "nb free cached instances " + getPoolSize());
506: }
507:
508: }
509:
510: // ---------------------------------------------------------------
511: // other public methods
512: // ---------------------------------------------------------------
513:
514: /**
515: * Obtains the TimerService associated for this Bean
516: * @return a JTimerService instance.
517: */
518: public TimerService getTimerService() {
519: if (myTimerService == null) {
520: // TODO : Check that instance implements TimedObject ?
521: myTimerService = new JTimerService(this );
522: }
523: return myTimerService;
524: }
525:
526: /**
527: * @return min pool size for Jmx
528: */
529: public int getMinPoolSize() {
530: return minPoolSize;
531: }
532:
533: /**
534: * @return max cache size for Jmx
535: */
536: public int getMaxCacheSize() {
537: return maxCacheSize;
538: }
539:
540: /**
541: * @return current cache size ( = nb of instance created) for Jmx
542: */
543: public int getCacheSize() {
544: return instanceCount;
545: }
546:
547: /**
548: * @return the Transaction Attribute
549: */
550: public int getTransactionAttribute() {
551: return ((MessageDrivenDesc) dd).getTxAttribute();
552: }
553:
554: /**
555: * For Message Driven Beans, only 2 cases are possible:
556: * TX_REQUIRED or TX_NOT_SUPPORTED
557: * @param rctx The Request Context
558: */
559: public void checkTransaction(RequestCtx rctx) {
560: String methName = "checkTransaction: ";
561: if (rctx.txAttr == MethodDesc.TX_REQUIRED) {
562: try {
563: if (txbeanmanaged) {
564: if (tm.getTransaction() == null) {
565: TraceEjb.mdb.log(BasicLevel.ERROR, methName
566: + "No transaction and need one");
567: return;
568: }
569: } else {
570: if (tm.getTransaction() == null) {
571: tm.begin();
572: }
573: }
574: rctx.mustCommit = true;
575: rctx.currTx = tm.getTransaction();
576: if (TraceEjb.isDebugTx()) {
577: TraceEjb.tx.log(BasicLevel.DEBUG,
578: "Transaction started: " + rctx.currTx);
579: }
580: } catch (Exception e) {
581: // No exception raised in case of MDB
582: TraceEjb.mdb.log(BasicLevel.ERROR, methName
583: + "cannot start tx:", e);
584: return;
585: }
586: } else {
587: if (rctx.txAttr != MethodDesc.TX_NOT_SUPPORTED) {
588: TraceEjb.mdb.log(BasicLevel.ERROR, methName
589: + "Bad transaction attribute: " + rctx.txAttr);
590: }
591: try {
592: rctx.currTx = tm.getTransaction();
593: if (rctx.currTx != null) {
594: if (TraceEjb.isDebugJms()) {
595: TraceEjb.mdb.log(BasicLevel.DEBUG, methName
596: + "Suspending client tx");
597: }
598: rctx.clientTx = tm.suspend();
599: rctx.currTx = null;
600: }
601: } catch (SystemException e) {
602: TraceEjb.mdb.log(BasicLevel.ERROR, methName
603: + "cannot suspend transaction", e);
604: return;
605: }
606: }
607: }
608:
609: /**
610: * Reduce number of instances in memory in the free list we reduce to the
611: * minPoolSize
612: */
613: public void reduceCache() {
614: String methName = "reduceCache: ";
615: if (TraceEjb.isDebugJms()) {
616: TraceEjb.mdb.log(BasicLevel.DEBUG, methName);
617: }
618: // reduce the pool to the minPoolSize
619: int poolsz = minPoolSize;
620: synchronized (endpool) {
621: if (TraceEjb.isDebugJms()) {
622: TraceEjb.mdb.log(BasicLevel.DEBUG, methName
623: + "try to reduce " + endpool.size() + " to "
624: + poolsz);
625: }
626: while (endpool.size() > poolsz) {
627: ListIterator i = endpool.listIterator();
628: if (i.hasNext()) {
629: i.next();
630: i.remove();
631: instanceCount--;
632: }
633: }
634: }
635: if (TraceEjb.isDebugJms()) {
636: TraceEjb.mdb.log(BasicLevel.DEBUG, methName + "cacheSize= "
637: + getCacheSize());
638: }
639:
640: }
641:
642: /**
643: * Notify a timeout for this bean
644: * @param timer timer whose expiration caused this notification.
645: */
646: public void notifyTimeout(Timer timer) {
647: if (stopped) {
648: TraceEjb.mdb.log(BasicLevel.WARN, "Container stopped");
649: return;
650: }
651: String methName = "notifyTimeout: ";
652: if (TraceEjb.isDebugJms()) {
653: TraceEjb.mdb.log(BasicLevel.DEBUG, methName);
654: }
655:
656: // We need an instance from the pool to process the timeout.
657: JMessageEndpoint ep = null;
658: try {
659: ep = getNewInstance(null);
660: } catch (Exception e) {
661: TraceEjb.mdb.log(BasicLevel.ERROR, methName + "exception:"
662: + e);
663: throw new EJBException("Cannot deliver the timeout", e);
664: }
665:
666: // deliver the timeout to the bean
667: ep.deliverTimeout(timer);
668:
669: // release the instance
670: releaseEndpoint(ep);
671: }
672:
673: // ---------------------------------------------------------------
674: // private methods
675: // ---------------------------------------------------------------
676:
677: /**
678: * return a new instance of the bean. Try to get one from the pool, and
679: * create a new one if the pool is empty.
680: *
681: * @param xaResource XAResource to use
682: * @return JMessageEndpoint to return
683: * @throws Exception to throw
684: */
685: private JMessageEndpoint getNewInstance(XAResource xaResource)
686: throws Exception {
687: String methName = "getNewInstance: ";
688: if (TraceEjb.isDebugJms()) {
689: TraceEjb.mdb.log(BasicLevel.DEBUG, methName + "Factory: "
690: + this + " XAResource: " + xaResource);
691: }
692:
693: // try to get one from the Pool
694: JMessageEndpoint ep = null;
695:
696: // try to find a free entry in the pool
697: synchronized (endpool) {
698: if (!endpool.isEmpty()) {
699: try {
700: ep = (JMessageEndpoint) endpool.remove(0);
701: } catch (Exception ex) {
702: // This should never happen
703: TraceEjb.mdb.log(BasicLevel.ERROR, methName
704: + "Exception:" + ex);
705: throw new EJBException(
706: "Cannot get an instance from the pool", ex);
707: }
708: } else {
709: if (TraceEjb.isDebugJms()) {
710: TraceEjb.mdb.log(BasicLevel.DEBUG, methName
711: + "pool is empty");
712: }
713: if (maxCacheSize == 0 || instanceCount < maxCacheSize) {
714: // Pool has free slots, create a new MessageEndpoint object
715: ep = createNewInstance();
716: } else {
717: while (endpool.isEmpty()) {
718: if (TraceEjb.isDebugJms()) {
719: TraceEjb.mdb
720: .log(
721: BasicLevel.DEBUG,
722: methName
723: + "endpool.isEmpty() = true --> wait()");
724: }
725: try {
726: endpool.wait();
727: if (TraceEjb.isDebugJms()) {
728: TraceEjb.mdb.log(BasicLevel.DEBUG,
729: methName + "endpool notified");
730: }
731: } catch (InterruptedException e) {
732: if (TraceEjb.isDebugJms()) {
733: TraceEjb.mdb
734: .log(
735: BasicLevel.DEBUG,
736: methName
737: + "endpool waiting interrupted",
738: e);
739: }
740: } catch (Exception e) {
741: throw new EJBException(
742: "synchronization pb", e);
743: }
744: }
745: try {
746: ep = (JMessageEndpoint) endpool.remove(0);
747: } catch (Exception ex) {
748: // This should never happen
749: TraceEjb.mdb.log(BasicLevel.ERROR, methName
750: + "Exception:" + ex);
751: throw new EJBException(
752: "Cannot get an instance from the pool",
753: ex);
754: }
755: }
756:
757: }
758: if (TraceEjb.isDebugJms()) {
759: TraceEjb.mdb.log(BasicLevel.DEBUG, methName
760: + "nb instances " + getCacheSize());
761: }
762: ep.setXAResource(xaResource);
763: ep.setReleasedState(false);
764: if (TraceEjb.isDebugJms()) {
765: TraceEjb.mdb.log(BasicLevel.DEBUG, methName
766: + "Returning " + ep);
767: }
768: return ep;
769: }
770: }
771:
772: /**
773: * Create a new instance of the bean
774: *
775: * @return JMessageEndpoint to return
776: */
777: private JMessageEndpoint createNewInstance() {
778: String methName = "createNewInstance: ";
779: if (TraceEjb.isDebugJms()) {
780: TraceEjb.mdb.log(BasicLevel.DEBUG, methName);
781: }
782: JMessageEndpointProxy epProxy = null;
783: MessageEndpoint ep = null;
784: JMessageEndpoint jep = null;
785: ClassLoader cls = myClassLoader();
786:
787: // Set ContextClassLoader with the ejbclassloader.
788: // This is necessary in case ejbCreate calls another bean in the same
789: // jar.
790: ClassLoader old = Thread.currentThread()
791: .getContextClassLoader();
792: Thread.currentThread().setContextClassLoader(cls);
793:
794: // Creates the new instance
795: MessageDrivenBean mdb = null;
796: try {
797: mdb = (MessageDrivenBean) beanclass.newInstance();
798: } catch (Exception e) {
799: TraceEjb.mdb.log(BasicLevel.ERROR, methName
800: + "failed to create instance:", e);
801: resetToOldClassLoader(old);
802: throw new EJBException(
803: "Container failed to create instance of Message Driven Bean",
804: e);
805: }
806:
807: // Instanciates a new JMessageEndpoint object
808: jep = new JMessageEndpoint(this , mdb);
809: epProxy = new JMessageEndpointProxy(this , mdb, jep);
810: Class msgListenerClass = null;
811: try {
812: msgListenerClass = cls.loadClass(msglistenType);
813: } catch (ClassNotFoundException e) {
814: String error = "Container failed to load class of Message Driven Bean '"
815: + msglistenType + "'";
816: TraceEjb.mdb.log(BasicLevel.ERROR, error, e);
817: resetToOldClassLoader(old);
818: throw new EJBException(error, e);
819: }
820: ep = (MessageEndpoint) Proxy.newProxyInstance(cls, new Class[] {
821: MessageEndpoint.class, msgListenerClass }, epProxy);
822:
823: jep.setProxy(ep);
824: // starts the bean instance: setMessageDrivenContext() + ejbCreate()
825: // see EJB spec. 2.0 page 322.
826: // Both operations must be called with the correct ComponentContext
827: Context ctxsave = setComponentContext();
828: mdb.setMessageDrivenContext((MessageDrivenContext) jep);
829: try {
830: Method m = beanclass.getMethod("ejbCreate", (Class[]) null);
831:
832: boolean bm = m.isAccessible();
833: if (!bm) {
834: m.setAccessible(true);
835: }
836: m.invoke(mdb, (Object[]) null);
837: m.setAccessible(bm);
838: } catch (Exception e) {
839: TraceEjb.mdb
840: .log(
841: BasicLevel.ERROR,
842: methName
843: + " cannot call ejbCreate on message driven bean instance ",
844: e);
845: throw new EJBException(
846: "Container fails to call ejbCreate on message driven bean instance",
847: e);
848: } finally {
849: resetToOldClassLoader(old);
850: resetComponentContext(ctxsave);
851: }
852:
853: synchronized (endpool) {
854: instanceCount++;
855: }
856: return jep;
857: }
858:
859: /**
860: * Reset currentThread context ClassLoader to a given ClassLoader
861: * @param old Old ClassLoader to reuse
862: */
863: private void resetToOldClassLoader(ClassLoader old) {
864: if (old != null) {
865: Thread.currentThread().setContextClassLoader(old);
866: }
867: }
868:
869: /*
870: * Make sense only for entities
871: */
872: public void storeInstances(Transaction tx) {
873: // unused
874:
875: }
876:
877: }
|