KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > presumo > jms > message > AckHelper


1 /**
2  * This file is part of Presumo.
3  *
4  * Presumo is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * Presumo is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with Presumo; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  *
19  * Copyright 2001 Dan Greff
20  */

21 package com.presumo.jms.message;
22
23 import com.presumo.jms.plugin.MessageQueue;
24 import com.presumo.jms.resources.Resources;
25 import com.presumo.util.log.Logger;
26 import com.presumo.util.log.LoggerFactory;
27
28 import java.util.ArrayList JavaDoc;
29 import java.util.BitSet JavaDoc;
30
31 /**
32  * Class to keep track of information necessary for acknowledgements.
33  *
34  * @author Dan Greff
35  */

36 public class AckHelper
37 {
38   private MessageStateListener originator;
39
40   /** State listeners that are notified when the msg is deleted from
41    * persistent storage.
42    */

43   private ArrayList JavaDoc deletionListeners = new ArrayList JavaDoc();
44   private BitSet JavaDoc safeAcks = new BitSet JavaDoc();
45   private BitSet JavaDoc routedAcks = new BitSet JavaDoc();
46   private boolean deletedRemotely = true;
47
48   private final JmsMessage msg;
49
50   /** Queue the message is stored in so that it can be deleted once acked **/
51   private MessageQueue storedIn;
52
53     /////////////////////////////////////////////////////////////////////////
54
// Constructors //
55
/////////////////////////////////////////////////////////////////////////
56

57   AckHelper(JmsMessage msg)
58   {
59     this.msg = msg;
60   }
61
62
63
64     /////////////////////////////////////////////////////////////////////////
65
// Public Methods //
66
/////////////////////////////////////////////////////////////////////////
67

68   public synchronized void setMessageQueue(MessageQueue queue)
69   {
70     this.storedIn = queue;
71   }
72   
73   /**
74    * Adds a state listener that will be notified when the message
75    * is deleted from persistent storage.
76    */

77   public synchronized void addDeletionListener(MessageStateListener listener)
78   {
79     logger.entry("addDeletionListener", listener);
80
81     safeAcks.set(deletionListeners.size());
82     routedAcks.set(deletionListeners.size());
83     deletionListeners.add(listener);
84
85     logger.exit("addDeletionListener");
86   }
87
88   
89   /**
90    * Informs the message represented by this AckHelper that the
91    * RemoteSession represented by the given listener has recieved a
92    * SAFE_ACK from the remote destination the message was sent to.
93    */

94   public synchronized void safeAck(MessageStateListener listener)
95   {
96     logger.entry("safeAck", listener);
97
98     int loc = deletionListeners.indexOf(listener);
99     
100     if (loc != -1) {
101       safeAcks.clear(loc);
102       if (safeAcks.length() == 0 && originator != null)
103         originator.messageRouted(msg);
104     }
105
106     logger.exit("safeAck");
107   }
108
109
110   /**
111    * Informs the message represented by this AckHelper that the
112    * RemoteSession represented by the given listener has recieved a
113    * ROUTED_ACK from the remote destination the message was sent to.
114    * <p>
115    * If the message has recieved a ROUTED_ACK from everyone it was
116    * sent to and a DELETED_ACK from the orginator it must be deleted
117    * and then send a DELTED_ACK to every remote destination this
118    * message was sent to.
119    */

120   public synchronized void routedAck(MessageStateListener listener)
121   {
122     logger.entry("routedAck", listener);
123
124     int loc = deletionListeners.indexOf(listener);
125     
126     if (loc != -1) {
127       
128       if (safeAcks.get(loc)) {
129         // It may be possible that a safe Ack be lost but the routed
130
// ack still come since the safe ack is not AckAcked. If this
131
// is the case (like here) go ahead and call the safeAck method.
132
safeAck(listener);
133       }
134       
135       routedAcks.clear(loc);
136       if (routedAcks.length() == 0 && deletedRemotely) {
137         // delete thyself
138
try {
139           if (storedIn != null) {
140             storedIn.delete(msg.getJMSMessageID());
141           }
142         } catch (java.io.IOException JavaDoc ioe) {
143           logger.exception(ioe);
144         }
145
146         for (int i=0; i < deletionListeners.size(); ++i) {
147           MessageStateListener destListener =
148             (MessageStateListener) deletionListeners.get(i);
149           destListener.messageDeleted(msg);
150         }
151       }
152     }
153
154     logger.exit("routedAck");
155   }
156
157   /**
158    * Informs the message represented by this AckHelper that the
159    * RemoteSession represented by the given listener has recieved a
160    * DELETED_ACK from the remote destination the message was received
161    * from.
162    * <p>
163    * If the message has recieved a ROUTED_ACK from everyone it was
164    * sent to and a DELETED_ACK from the orginator it must be deleted
165    * and then send a DELTED_ACK to every remote destination this
166    * message was sent to.
167    */

168   public synchronized void deleteAck(MessageStateListener listener)
169   {
170     logger.entry("deleteAck", listener);
171
172     deletedRemotely = true;
173     if (routedAcks.length() == 0 && deletedRemotely) {
174
175       // delete thyself
176
try {
177         if (storedIn != null) {
178           storedIn.delete(msg.getJMSMessageID());
179           }
180       } catch (java.io.IOException JavaDoc ioe) {
181         logger.exception(ioe);
182       }
183
184       for (int i=0; i < deletionListeners.size(); ++i) {
185         MessageStateListener destListener =
186           (MessageStateListener) deletionListeners.get(i);
187         destListener.messageDeleted(msg);
188       }
189     }
190
191     logger.exit("deleteAck");
192   }
193
194
195   /**
196    * Sets the orginator whom must be notified that the message
197    * has been safely routed once every destination has returned the
198    * MSG_SAFE ack.
199    */

200   public synchronized void setOriginator(MessageStateListener originator)
201   {
202     logger.entry("setOriginator", originator);
203
204     this.originator = originator;
205     deletedRemotely = false;
206
207     logger.exit("setOriginator");
208   }
209   
210
211   ////////////////////////////// Misc stuff ////////////////////////////////
212

213   private static Logger logger =
214     LoggerFactory.getLogger(AckHelper.class, Resources.getBundle());
215
216   ///////////////////////////////////////////////////////////////////////////
217

218 }
219
Popular Tags