001: /*
002: * Portions Copyright 2000-2007 Sun Microsystems, Inc. All Rights
003: * Reserved. Use is subject to license terms.
004: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License version
008: * 2 only, as published by the Free Software Foundation.
009: *
010: * This program is distributed in the hope that it will be useful, but
011: * WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * General Public License version 2 for more details (a copy is
014: * included at /legal/license.txt).
015: *
016: * You should have received a copy of the GNU General Public License
017: * version 2 along with this work; if not, write to the Free Software
018: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
019: * 02110-1301 USA
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
022: * Clara, CA 95054 or visit www.sun.com if you need additional
023: * information or have any questions.
024: */
025: package gov.nist.siplite;
026:
027: import java.util.*;
028: import java.io.*;
029: import javax.microedition.sip.SipException;
030:
031: import gov.nist.siplite.header.*;
032: import gov.nist.siplite.message.*;
033: import gov.nist.siplite.stack.*;
034: import gov.nist.core.*;
035: import gov.nist.siplite.address.*;
036:
037: import com.sun.midp.log.Logging;
038: import com.sun.midp.log.LogChannels;
039:
040: /**
041: * Implementation of the JAIN-SIP provider interface.
042: *
043: * @version JAIN-SIP-1.1
044: *
045: * <a href="{@docRoot}/uncopyright.html">
046: * This code is in the public domain.</a>
047: *
048: */
049: public final class SipProvider implements SIPTransactionEventListener {
050: /** Current SIP listener. */
051: protected SipListener sipListener;
052: /** Flag to indicate the provider is active. */
053: protected boolean isActive;
054: /** Current SIP Stack context. */
055: protected SipStack sipStack;
056: /** Current event listening filter. */
057: protected ListeningPoint listeningPoint;
058: /** Curent server transactions. */
059: protected ServerTransaction currentTransaction;
060: /** Curent event scanner processor. */
061: private EventScanner eventScanner;
062:
063: /**
064: * Stops processing messages for this provider. Post an empty
065: * message to our message processing queue that signals us to
066: * quit.
067: */
068: protected void stop() {
069: // Put an empty event in the queue and post ourselves a message.
070: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
071: Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
072: "Exiting provider");
073: }
074:
075: synchronized (this ) {
076: listeningPoint.removeSipProvider();
077: }
078:
079: this .eventScanner.stop();
080: }
081:
082: /**
083: * Handles the SIP event - because we have only one listener and we are
084: * already in the context of a separate thread, we dont need to enque
085: * the event and signal another thread.
086: *
087: * @param sipEvent is the event to process.
088: * @param transaction the current transaction
089: *
090: */
091: public void handleEvent(SipEvent sipEvent, Transaction transaction) {
092:
093: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
094: Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
095: "handleEvent " + sipEvent + "currentTransaction = "
096: + transaction + "this.sipListener = "
097: + this .sipListener);
098: }
099:
100: if (this .sipListener == null)
101: return;
102:
103: EventWrapper eventWrapper = new EventWrapper();
104: eventWrapper.sipEvent = sipEvent;
105: eventWrapper.transaction = transaction;
106:
107: if (transaction != null
108: && transaction instanceof ClientTransaction) {
109: ((ClientTransaction) transaction).setEventPending();
110: }
111:
112: this .eventScanner.addEvent(eventWrapper);
113: }
114:
115: /**
116: * Creates a new instance of SipProvider.
117: * @param sipStack the current SIP stack context
118: */
119: protected SipProvider(SipStack sipStack) {
120: this .sipStack = sipStack;
121: this .eventScanner = sipStack.eventScanner;
122: }
123:
124: /**
125: * Compares to this instance for equivalence.
126: * @param obj object for comparison
127: * @return true if the object is the same
128: */
129: public boolean equals(Object obj) {
130: return super .equals(obj);
131: }
132:
133: /**
134: * This method registers the SipListener object to this SipProvider, once
135: * registered the SIP Listener can send events on the SipProvider and
136: * recieve events emitted from the SipProvider. As JAIN SIP resticts a
137: * unicast Listener special case, that is, that one and only one Listener
138: * may be registered on the SipProvider concurrently.
139: * <p>
140: * If an attempt is made to re-register the existing SipListener this
141: * method returns silently. A previous SipListener must be removed from the
142: * SipProvider before another SipListener can be registered to
143: * the SipProvider.
144: *
145: * @param sipListener to be registered with the
146: * Provider.
147: * @throws TooManyListenersException this exception is thrown when a new
148: * SipListener attempts to register with the SipProvider when another
149: * SipListener is already registered with this SipProvider.
150: *
151: */
152: public void addSipListener(SipListener sipListener)
153: throws TooManyListenersException {
154:
155: synchronized (sipStack) {
156: Enumeration it = sipStack.getSipProviders();
157: while (it.hasMoreElements()) {
158: SipProvider provider = (SipProvider) it.nextElement();
159: if (provider.sipListener != null
160: && provider.sipListener != sipListener)
161: throw new TooManyListenersException();
162: }
163: }
164:
165: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
166: Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
167: "add SipListener " + sipListener);
168: }
169:
170: this .sipListener = sipListener;
171: sipStack.sipListener = sipListener;
172:
173: synchronized (sipStack) {
174: Enumeration it = sipStack.getSipProviders();
175: while (it.hasMoreElements()) {
176: SipProvider provider = (SipProvider) it.nextElement();
177: provider.sipListener = sipListener;
178: }
179: }
180: }
181:
182: /**
183: * Returns the ListeningPoint of this SipProvider.
184: * A SipProvider has a single Listening Point at any specific point in time.
185: *
186: * @see ListeningPoint
187: * @return the ListeningPoint of this SipProvider
188: */
189: public ListeningPoint getListeningPoint() {
190: return this .listeningPoint;
191: }
192:
193: /**
194: * Returns a unique CallIdHeader for identifying dialogues between two
195: * SIP applications.
196: *
197: * @return new CallId unique within the SIP Stack.
198: */
199: public CallIdHeader getNewCallId() {
200: String callId = SIPUtils.generateCallIdentifier(this
201: .getSipStack().getIPAddress());
202: CallIdHeader callid = new CallIdHeader();
203: callid.setCallId(callId);
204: return callid;
205:
206: }
207:
208: /**
209: * Once an application wants to a send a new request it must first request
210: * a new client transaction identifier. This method is called by an
211: * application to create the client transaction befores it sends the Request
212: * via the SipProvider on that transaction. This methods returns a new
213: * unique client transaction identifier that can be passed to the stateful
214: * sendRequest method on the SipProvider and the sendAck/sendBye
215: * methods on the Dialog in order to send a request.
216: *
217: * @param request the new Request message that is to handled
218: * statefully by the Provider.
219: * @return a new unique client transation identifier
220: * @see ClientTransaction
221: * @since v1.1
222: */
223: public ClientTransaction getNewClientTransaction(Request request)
224: throws TransactionUnavailableException {
225: if (request == null) {
226: throw new NullPointerException("null request");
227: }
228:
229: if (request.getTransaction() != null) {
230: throw new TransactionUnavailableException(
231: "Transaction already assigned to request");
232: }
233:
234: if (request.getMethod().equals(Request.CANCEL)) {
235: ClientTransaction ct = (ClientTransaction) sipStack
236: .findCancelTransaction(request, false);
237:
238: if (ct != null) {
239: ClientTransaction retval = sipStack
240: .createClientTransaction(ct.getMessageChannel());
241: ((Transaction) retval).setOriginalRequest(request);
242: ((Transaction) retval).addEventListener(this );
243: sipStack.addTransaction((ClientTransaction) retval);
244: ((ClientTransaction) retval).setDialog((Dialog) ct
245: .getDialog());
246: return retval;
247: }
248:
249: }
250:
251: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
252: Logging.report(Logging.INFORMATION, LogChannels.LC_JSR180,
253: "could not find existing transaction for "
254: + request.getFirstLine());
255: }
256:
257: String dialogId = request.getDialogId(false);
258: Dialog dialog = sipStack.getDialog(dialogId);
259: // isDialog - is request sends inside dialog
260: boolean isDialog = false;
261: if (dialog != null) {
262: int dialogState = dialog.getState();
263: if (dialogState == Dialog.EARLY_STATE
264: || dialogState == Dialog.CONFIRMED_STATE
265: || dialogState == Dialog.COMPLETED_STATE) {
266: isDialog = true;
267: }
268: }
269: Enumeration it = sipStack.getRouter().getNextHops(request,
270: isDialog);
271:
272: if (it == null || !it.hasMoreElements()) {
273: // could not route the request as out of dialog.
274: // maybe the user has no router or the router cannot resolve
275: // the route.
276: // If this is part of a dialog then use the route from the dialog
277: if (dialog != null) {
278: try {
279: Hop hop = dialog.getNextHop();
280:
281: if (hop != null) {
282: ClientTransaction ct = null;
283:
284: ct = (ClientTransaction) sipStack
285: .createMessageChannel(hop);
286:
287: String branchId = SIPUtils.generateBranchId();
288:
289: if (request.getTopmostVia() != null) {
290: request.getTopmostVia().setBranch(branchId);
291: } else {
292: // Find a message processor to assign this
293: // transaction to.
294: MessageProcessor messageProcessor = this .listeningPoint.messageProcessor;
295: ViaHeader via = messageProcessor
296: .getViaHeader();
297: request.addHeader(via);
298: }
299:
300: ct.setOriginalRequest(request);
301: ct.setBranch(branchId);
302: ct.setDialog(dialog);
303: ct.addEventListener(this );
304:
305: return ct;
306: } // end if
307: } catch (Exception ex) {
308: throw new TransactionUnavailableException(ex
309: .getMessage());
310: }
311: } else {
312: throw new TransactionUnavailableException("no route!");
313: }
314: } else {
315: try {
316: // An out of dialog route was found. Assign this to the
317: // client transaction.
318: while (it.hasMoreElements()) {
319: Hop hop = (Hop) it.nextElement();
320:
321: ClientTransaction ct = null;
322:
323: ct = (ClientTransaction) sipStack
324: .createMessageChannel(hop);
325:
326: // ClientTransaction ct =
327: // (ClientTransaction) sipStack.createMessageChannel(hop);
328:
329: if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
330: Logging.report(Logging.INFORMATION,
331: LogChannels.LC_JSR180, "hop = " + hop
332: + "ct " + ct);
333: }
334:
335: if (ct == null)
336: continue;
337:
338: String branchId = SIPUtils.generateBranchId();
339:
340: if (request.getTopmostVia() != null) {
341: request.getTopmostVia().setBranch(branchId);
342: } else {
343: // Find a message processor to assign
344: // this transaction to.
345: MessageProcessor messageProcessor = listeningPoint.messageProcessor;
346: ViaHeader via = messageProcessor.getViaHeader();
347: request.addHeader(via);
348: }
349:
350: ct.setOriginalRequest(request);
351: ct.setBranch(branchId);
352:
353: if (sipStack.isDialogCreated(request.getMethod())) {
354: // create a new dialog to contain this transaction
355: // provided this is necessary.
356: // This could be a re-invite
357: // (noticed by Brad Templeton)
358:
359: if (dialog != null) {
360: ct.setDialog(dialog);
361: } else {
362: sipStack.createDialog(ct);
363: }
364: } else {
365: ct.setDialog(dialog);
366: }
367:
368: // The provider is the event listener for all transactions.
369: ct.addEventListener(this );
370: return (ClientTransaction) ct;
371: } // end while()
372: } catch (SipException ex) {
373: throw new TransactionUnavailableException(ex
374: .getMessage());
375: }
376: } // end else
377:
378: throw new TransactionUnavailableException(
379: "Could not create transaction - could not resolve next hop! ");
380: }
381:
382: /**
383: * An application has the responsibility of deciding to respond to a
384: * Request that does not match an existing server transaction. The method
385: * is called by an application that decides to respond to an unmatched
386: * Request statefully. This methods return a new unique server transaction
387: * identifier that can be passed to the stateful sendResponse methods in
388: * order to respond to the request.
389: *
390: * @param request the initial Request message that the doesn't
391: * match an existing
392: * transaction that the application decides to handle statefully.
393: * @return a new unique server transation identifier
394: * @throws TransactionAlreadyExistsException if a transaction already exists
395: * that is already handling this Request. This may happen if the application
396: * gets retransmits of the same request before the initial transaction is
397: * allocated.
398: * @see ServerTransaction
399: * @since v1.1
400: */
401: public ServerTransaction getNewServerTransaction(Request request)
402: throws TransactionAlreadyExistsException,
403: TransactionUnavailableException {
404:
405: try {
406: ServerTransaction transaction = null;
407: Request sipRequest = (Request) request;
408: if (sipStack.isDialogCreated(sipRequest.getMethod())) {
409: if (sipStack.findTransaction((Request) request, true) != null)
410: throw new TransactionAlreadyExistsException(
411: "server transaction already exists!");
412: transaction = (ServerTransaction) this .currentTransaction;
413: if (transaction == null)
414: throw new TransactionUnavailableException(
415: "Transaction not available");
416: if (!transaction
417: .isMessagePartOfTransaction((Request) request)) {
418: throw new TransactionUnavailableException(
419: "Request Mismatch");
420: }
421: transaction.setOriginalRequest(sipRequest);
422: try {
423: sipStack.addTransaction(transaction);
424: } catch (IOException ex) {
425: throw new TransactionUnavailableException(
426: "Error sending provisional response");
427: }
428: equipADialogForTransaction(transaction, sipRequest);
429: } else {
430: transaction = (ServerTransaction) sipStack
431: .findTransaction((Request) request, true);
432: if (transaction != null)
433: throw new TransactionAlreadyExistsException(
434: "Transaction exists! ");
435: transaction = (ServerTransaction) this .currentTransaction;
436: if (transaction == null)
437: throw new TransactionUnavailableException(
438: "Transaction not available!");
439: if (!transaction
440: .isMessagePartOfTransaction((Request) request))
441: throw new TransactionUnavailableException(
442: "Request Mismatch");
443: transaction.setOriginalRequest(sipRequest);
444: // Map the transaction.
445: try {
446: sipStack.addTransaction(transaction);
447: } catch (IOException ex) {
448: throw new TransactionUnavailableException(
449: "Could not send back provisional response!");
450: }
451: String dialogId = sipRequest.getDialogId(true);
452: Dialog dialog = sipStack.getDialog(dialogId);
453: if (dialog != null) {
454: dialog.addTransaction(transaction);
455: dialog.addRoute(sipRequest);
456: }
457: }
458: return transaction;
459: } catch (RuntimeException ex) {
460: ex.printStackTrace();
461: throw ex;
462: }
463: }
464:
465: /**
466: * Find or create a dialog with the dialog-id obtained from the request.
467: * Initializing the dialog's route information.
468: * Bind the dialog and the transaction to each other.
469: * @param transaction trasaction for the request
470: * @param sipRequest request whose tags are the source of dialog-ID
471: * and route information
472: */
473: public void equipADialogForTransaction(
474: ServerTransaction transaction, Request sipRequest) {
475: // So I can handle timeouts.
476: // IMPL_NOTE: do we need it here, or in the calling code?
477: transaction.addEventListener(this );
478:
479: String dialogId = sipRequest.getDialogId(true);
480: Dialog dialog = sipStack.getDialog(dialogId);
481:
482: if (dialog == null) {
483: dialog = sipStack.createDialog(transaction);
484: }
485:
486: dialog.setStack(this .sipStack);
487: dialog.addRoute(sipRequest);
488:
489: if (dialog.getRemoteTag() != null
490: && dialog.getLocalTag() != null) {
491: this .sipStack.putDialog(dialog);
492: }
493:
494: transaction.setDialog(dialog);
495: }
496:
497: /**
498: * Returns the SipStack that this SipProvider is attached to. A SipProvider
499: * can only be attached to a single SipStack object which belongs to
500: * the same SIP stack as the SipProvider.
501: *
502: * @see SipStack
503: * @return the attached SipStack.
504: */
505: public SipStack getSipStack() {
506: return this .sipStack;
507: }
508:
509: /**
510: * Removes the SipListener from this SipProvider. This method returns
511: * silently if the <var>sipListener</var> argument is not registered
512: * with the SipProvider.
513: *
514: * @param sipListener - the SipListener to be removed from this
515: * SipProvider
516: */
517: public void removeSipListener(SipListener sipListener) {
518: if (sipListener == this .sipListener) {
519: this .sipListener = null;
520: }
521: }
522:
523: /**
524: * Sends specified Request and returns void i.e.
525: * no transaction record is associated with this action. This method
526: * implies that the application is functioning statelessly specific to this
527: * Request, hence the underlying SipProvider acts statelessly.
528: * <p>
529: * Once the Request message has been passed to this method, the SipProvider
530: * will forget about this Request. No transaction semantics will be
531: * associated with the Request and no retranmissions will occur on the
532: * Request by the SipProvider, if these semantics are required it is the
533: * responsibility of the application not the JAIN SIP Stack.
534: * <ul>
535: * <li>Stateless Proxy - A stateless proxy simply forwards every request
536: * it receives downstream and discards information about the request
537: * message once the message has been forwarded. A stateless proxy does not
538: * have any notion of a transaction.
539: * </ul>
540: *
541: * @since v1.1
542: * @see Request
543: * @param request - the Request message to send statelessly
544: * @throws SipException if implementation cannot send request for any reason
545: */
546: public void sendRequest(Request request) throws SipException {
547: // request sends out of dialog
548: Enumeration it = sipStack.getRouter().getNextHops(request,
549: false);
550: if (it == null || !it.hasMoreElements()) {
551: throw new SipException("could not determine next hop!",
552: SipException.GENERAL_ERROR);
553: }
554:
555: // Will slow down the implementation because it involves
556: // a search to see if a transaction exists.
557: // Just to double check adding some assertion
558: // checking under debug.
559: Transaction tr = sipStack.findTransaction(request, false);
560: if (tr != null) {
561: throw new SipException(
562: "Cannot send: stateless Transaction found!",
563: SipException.GENERAL_ERROR);
564: }
565:
566: while (it.hasMoreElements()) {
567: Hop nextHop = (Hop) it.nextElement();
568:
569: Request sipRequest = request;
570: String bid = sipRequest.getTransactionId();
571: ViaHeader via = sipRequest.getTopmostVia();
572: via.setBranch(bid);
573: Request newRequest;
574:
575: // Do not create a transaction for this request. If it has
576: // Mutliple route headers then take the first one off the
577: // list and copy into the request URI.
578: if (sipRequest.getHeader(Header.ROUTE) != null) {
579: newRequest = (Request) sipRequest.clone();
580: Enumeration rl = newRequest.getHeaders(Header.ROUTE);
581: RouteHeader route = (RouteHeader) rl.nextElement();
582: newRequest.setRequestURI(route.getAddress().getURI());
583: sipRequest.removeHeader(Header.ROUTE, true);
584: } else {
585: newRequest = sipRequest;
586: }
587:
588: MessageChannel messageChannel = sipStack
589: .createRawMessageChannel(nextHop);
590: try {
591: if (messageChannel != null) {
592: messageChannel.sendMessage((Message) newRequest);
593: return;
594: } else {
595: throw new SipException(
596: "Could not forward request.",
597: SipException.GENERAL_ERROR);
598: }
599:
600: } catch (IOException ex) {
601: continue;
602: }
603: }
604: }
605:
606: /**
607: * Sends specified {@link Response} and returns void i.e.
608: * no transaction record is associated with this action. This method implies
609: * that the application is functioning as either a stateless proxy or a
610: * stateless User Agent Server.
611: * <ul>
612: * <li> Stateless proxy - A stateless proxy simply forwards every response
613: * it receives upstream and discards information about the response message
614: * once the message has been forwarded. A stateless proxy does not
615: * have any notion of a transaction.
616: * <li>Stateless User Agent Server - A stateless UAS does not maintain
617: * transaction state. It replies to requests normally, but discards
618: * any state that would ordinarily be retained by a UAS after a response
619: * has been sent. If a stateless UAS receives a retransmission of a
620: * request, it regenerates the response and resends it, just as if it
621: * were replying to the first instance of the request. A UAS cannot be
622: * stateless unless the request processing for that method would always
623: * result in the same response if the requests are identical. Stateless
624: * UASs do not use a transaction layer; they receive requests directly
625: * from the transport layer and send responses directly to the transport
626: * layer.
627: * </ul>
628: *
629: * @see Response
630: * @param sipResponse the Response to send statelessly.
631: * @throws IOException if I/O error occured
632: * @throws SipException if implementation cannot send response for
633: * any other reason
634: * @see Response
635: * @since v1.1
636: */
637: public void sendResponse(Response sipResponse) throws IOException,
638: SipException {
639: ViaHeader via = sipResponse.getTopmostVia();
640: if (via == null) {
641: throw new SipException("No via header in response!",
642: SipException.INVALID_MESSAGE);
643: }
644:
645: int port = via.getPort();
646: String transport = via.getTransport();
647: // check to see if Via has "received paramaeter". If so
648: // set the host to the via parameter. Else set it to the
649: // Via host.
650: String host = via.getReceived();
651:
652: if (host == null) {
653: host = via.getHost();
654: }
655:
656: if (port == -1) {
657: port = 5060; // IMPL_NOTE: move to SIPConstants
658: }
659:
660: Hop hop = new Hop(host + ":" + port + "/" + transport);
661: MessageChannel messageChannel = sipStack
662: .createRawMessageChannel(hop);
663: messageChannel.sendMessage(sipResponse);
664: }
665:
666: /**
667: * This method sets the listening point of the SipProvider.
668: * A SipProvider can only have a single listening point at any
669: * specific time. This method returns
670: * silently if the same <var>listeningPoint</var> argument is re-set
671: * on the SipProvider.
672: * <p>
673: * JAIN SIP supports recieving messages from
674: * any port and interface that a server listens on for UDP, on that same
675: * port and interface for TCP in case a message may need to be sent
676: * using TCP, rather than UDP, if it is too large. In order to satisfy this
677: * functionality an application must create two SipProviders and set
678: * identical listeningPoints except for transport on each SipProvder.
679: * <p>
680: * Multiple SipProviders are prohibited to listen on the same
681: * listening point.
682: *
683: * @param listeningPoint of this SipProvider
684: * @see ListeningPoint
685: * @since v1.1
686: */
687: public void setListeningPoint(ListeningPoint listeningPoint) {
688: if (listeningPoint == null)
689: throw new NullPointerException("Null listening point");
690: ListeningPoint lp = (ListeningPoint) listeningPoint;
691: lp.sipProviderImpl = this ;
692: this .listeningPoint = (ListeningPoint) listeningPoint;
693:
694: }
695:
696: /**
697: * Invoked when an error has ocurred with a transaction.
698: * Propagate up to the listeners.
699: *
700: * @param transactionErrorEvent Error event.
701: */
702: public void transactionErrorEvent(
703: SIPTransactionErrorEvent transactionErrorEvent) {
704: Transaction transaction = (Transaction) transactionErrorEvent
705: .getSource();
706:
707: if (transactionErrorEvent.getErrorID() == SIPTransactionErrorEvent.TRANSPORT_ERROR) {
708:
709: if (Logging.REPORT_LEVEL <= Logging.ERROR) {
710: Logging.report(Logging.ERROR, LogChannels.LC_JSR180,
711: "TransportError occured on " + transaction);
712: }
713:
714: // handle Transport error as timeout.
715: Object errorObject = transactionErrorEvent.getSource();
716: Timeout timeout = Timeout.TRANSACTION;
717: TimeoutEvent ev = null;
718:
719: if (errorObject instanceof ServerTransaction) {
720: ev = new TimeoutEvent(this ,
721: (ServerTransaction) errorObject);
722: } else {
723: ev = new TimeoutEvent(this ,
724: (ClientTransaction) errorObject, timeout);
725: }
726: this .handleEvent(ev, (Transaction) errorObject);
727:
728: } else {
729: // This is a timeout event.
730: Object errorObject = transactionErrorEvent.getSource();
731: Timeout timeout = Timeout.TRANSACTION;
732: TimeoutEvent ev = null;
733:
734: if (errorObject instanceof ServerTransaction) {
735: ev = new TimeoutEvent(this ,
736: (ServerTransaction) errorObject);
737: } else {
738: ev = new TimeoutEvent(this ,
739: (ClientTransaction) errorObject, timeout);
740: }
741: this .handleEvent(ev, (Transaction) errorObject);
742:
743: }
744: }
745: }
|