1 /***
2 * Redistribution and use of this software and associated documentation
3 * ("Software"), with or without modification, are permitted provided
4 * that the following conditions are met:
5 *
6 * 1. Redistributions of source code must retain copyright
7 * statements and notices. Redistributions must also contain a
8 * copy of this document.
9 *
10 * 2. Redistributions in binary form must reproduce the
11 * above copyright notice, this list of conditions and the
12 * following disclaimer in the documentation and/or other
13 * materials provided with the distribution.
14 *
15 * 3. The name "Exolab" must not be used to endorse or promote
16 * products derived from this Software without prior written
17 * permission of Exoffice Technologies. For written permission,
18 * please contact info@exolab.org.
19 *
20 * 4. Products derived from this Software may not be called "Exolab"
21 * nor may "Exolab" appear in their names without prior written
22 * permission of Exoffice Technologies. Exolab is a registered
23 * trademark of Exoffice Technologies.
24 *
25 * 5. Due credit should be given to the Exolab Project
26 * (http://www.exolab.org/).
27 *
28 * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32 * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39 * OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Copyright 2005 (C) Exoffice Technologies Inc. All Rights Reserved.
42 *
43 * $Id: AbstractMessageHandle.java,v 1.2 2005/08/30 07:26:49 tanderson Exp $
44 */
45 package org.exolab.jms.messagemgr;
46
47 import javax.jms.IllegalStateException;
48 import javax.jms.JMSException;
49 import javax.jms.MessageConsumer;
50
51 import org.exolab.jms.client.JmsDestination;
52 import org.exolab.jms.message.MessageImpl;
53 import org.exolab.jms.server.ServerConnection;
54
55
56 /***
57 * Abstract implementation of the {@link MessageHandle} interface.
58 *
59 * @author <a href="mailto:tma@netspace.net.au">Tim Anderson</a>
60 * @version $Revision: 1.2 $ $Date: 2005/08/30 07:26:49 $
61 */
62 public abstract class AbstractMessageHandle implements MessageHandle {
63
64 /***
65 * The cache that manages this handle.
66 */
67 private DestinationCache _cache;
68
69 /***
70 * The message reference.
71 */
72 private MessageRef _reference;
73
74 /***
75 * The message identifier.
76 */
77 private final String _messageId;
78
79 /***
80 * If <code>true</code>, indicates that the message associated with the
81 * handle has been delivered, but not acknowledged.
82 */
83 private boolean _delivered = false;
84
85 /***
86 * The message priority.
87 */
88 private final int _priority;
89
90 /***
91 * The time that the message was accepted by the server, in milliseconds.
92 */
93 private long _acceptedTime;
94
95 /***
96 * The message sequence number, assigned by the {@link MessageMgr}, used to
97 * help order the message. It also allows us to overcome the millisecond
98 * resolution problem of _acceptedTime, when ordering messages
99 */
100 private final long _sequenceNumber;
101
102 /***
103 * The time that the message expires, in milliseconds.
104 */
105 private long _expiryTime;
106
107 /***
108 * The destination that this handle belongs to.
109 */
110 private final JmsDestination _destination;
111
112 /***
113 * The identity of the {@link ConsumerEndpoint} associated with the message,
114 * or <code>-1</code> if it isn't associated with any consumer.
115 */
116 private final long _consumerId;
117
118 /***
119 * The identity of the {@link ServerConnection} associated with the message,
120 * or <code>-1</code> if it isn't associated with any connection.
121 */
122 private final long _connectionId;
123
124
125 /***
126 * Construct a new <code>AbstractMessageHandle</code>.
127 *
128 * @param cache the destination cache that owns this
129 * @param reference the reference to the message
130 * @param message the message for which the handle is created
131 * @throws JMSException if the handle cannot be constructed
132 */
133 public AbstractMessageHandle(DestinationCache cache, MessageRef reference,
134 MessageImpl message)
135 throws JMSException {
136 if (cache == null) {
137 throw new IllegalArgumentException("Argument 'cache' is null");
138 }
139 if (reference == null) {
140 throw new IllegalArgumentException("Argument 'reference' is null");
141 }
142 if (message == null) {
143 throw new IllegalArgumentException("Argument 'message' is null");
144 }
145 _cache = cache;
146 _messageId = message.getMessageId().getId();
147 _delivered = message.getJMSRedelivered();
148 _priority = message.getJMSPriority();
149 _acceptedTime = message.getAcceptedTime();
150 _sequenceNumber = message.getSequenceNumber();
151 _expiryTime = message.getJMSExpiration();
152 _destination = (JmsDestination) message.getJMSDestination();
153 _consumerId = message.getConsumerId();
154 _connectionId = message.getConnectionId();
155 _reference = reference;
156 }
157
158 /***
159 * Construct a new <code>AbstractMessageHandle</code>.
160 *
161 * @param messageId the message identifier
162 * @param priority the message priority
163 * @param acceptedTime the time the message was accepted by the server
164 * @param sequenceNumber the message sequence number
165 * @param expiryTime the time that the message will expire
166 */
167 public AbstractMessageHandle(String messageId, int priority,
168 long acceptedTime, long sequenceNumber,
169 long expiryTime, JmsDestination destination) {
170 if (messageId == null) {
171 throw new IllegalArgumentException("Argument 'messageId' is null");
172 }
173 if (destination == null) {
174 throw new IllegalArgumentException(
175 "Argument 'destination' is null");
176 }
177 _messageId = messageId;
178 _priority = priority;
179 _acceptedTime = acceptedTime;
180 _sequenceNumber = sequenceNumber;
181 _expiryTime = expiryTime;
182 _destination = destination;
183 _consumerId = -1;
184 _connectionId = -1;
185 }
186
187 /***
188 * Returns the message identifier.
189 *
190 * @return the message identifier
191 */
192 public String getMessageId() {
193 return _messageId;
194 }
195
196 /***
197 * Returns the message associated with this handle.
198 *
199 * @return the associated message, or <code>null</code> if the handle is no
200 * longer valid
201 * @throws JMSException for any error
202 */
203 public MessageImpl getMessage() throws JMSException {
204 if (_reference == null) {
205 throw new JMSException("Cannot get message with identifier="
206 + _messageId + ": MessageRef null");
207 }
208 return _reference.getMessage();
209 }
210
211
212 /***
213 * Indicates if a message has been delivered to a {@link MessageConsumer},
214 * but not acknowledged.
215 *
216 * @param delivered if <code>true</code> indicates that an attempt has been
217 * made to deliver the message
218 */
219 public void setDelivered(boolean delivered) {
220 _delivered = delivered;
221 }
222
223 /***
224 * Returns if an attempt has already been made to deliver the message.
225 *
226 * @return <code>true</code> if delivery has been attempted
227 */
228 public boolean getDelivered() {
229 return _delivered;
230 }
231
232 /***
233 * Returns the priority of the message.
234 *
235 * @return the message priority
236 */
237 public int getPriority() {
238 return _priority;
239 }
240
241 /***
242 * Returns the time that the corresponding message was accepted, in
243 * milliseconds.
244 *
245 * @return the time that the corresponding message was accepted
246 */
247 public long getAcceptedTime() {
248 return _acceptedTime;
249 }
250
251 /***
252 * Returns the time that the message expires.
253 *
254 * @return the expiry time
255 */
256 public long getExpiryTime() {
257 return _expiryTime;
258 }
259
260 /***
261 * Determines if the message has expired.
262 *
263 * @return <code>true</code> if the message has expired, otherwise
264 * <code>false</code>
265 */
266 public boolean hasExpired() {
267 return (_expiryTime != 0 && _expiryTime <= System.currentTimeMillis());
268 }
269
270 /***
271 * Returns the handle's sequence number.
272 *
273 * @return the sequence number
274 */
275 public long getSequenceNumber() {
276 return _sequenceNumber;
277 }
278
279 /***
280 * Returns the message destination.
281 *
282 * @return the message destination
283 */
284 public JmsDestination getDestination() {
285 return _destination;
286 }
287
288 /***
289 * Returns the consumer identity associated with the message.
290 *
291 * @return the consumer identity associated with the message, or *
292 * <code>-1</code> if the message isn't associated with a consumer
293 */
294 public long getConsumerId() {
295 return _consumerId;
296 }
297
298 /***
299 * Returns the persistent identity of the the consumer endpoint that owns
300 * this handle. If it is set, then a consumer owns it exclusively, otherwise
301 * the handle may be shared across a number of consumers.
302 *
303 * @return <code>null</code>
304 */
305 public String getConsumerPersistentId() {
306 return null;
307 }
308
309 /***
310 * Returns the connection identity associated with this handle.
311 *
312 * @return the connection identity associated with this handle, or
313 * <code>-1</code> if this isn't associated with a connection
314 */
315 public long getConnectionId() {
316 return _connectionId;
317 }
318
319 /***
320 * Determines if the handle is persistent.
321 *
322 * @return <code>false</code>
323 */
324 public boolean isPersistent() {
325 return false;
326 }
327
328 /***
329 * Indicates whether some other object is "equal to" this one.
330 *
331 * @param object the reference object with which to compare.
332 * @return <code>true</code> if <code>object</code> is a MessageHandle, and
333 * has the same {@link #getMessageId()
334 */
335 public boolean equals(Object object) {
336 boolean result = (object instanceof MessageHandle);
337 if (result) {
338 result
339 = _messageId.equals(
340 ((MessageHandle) object).getMessageId());
341 }
342 return result;
343 }
344
345 /***
346 * Returns a hash code value for the object.
347 *
348 * @return a hash code value for this object
349 */
350 public int hashCode() {
351 return _messageId.hashCode();
352 }
353
354 /***
355 * Return a stringified version of the handle.
356 *
357 * @return a stringified version of the handle
358 */
359 public String toString() {
360 return "MessageHandle : " + _priority + ":" + getAcceptedTime() +
361 ":" + getSequenceNumber() + ":" + _messageId;
362 }
363
364 /***
365 * Destroy this handle. If this is the last handle to reference the message,
366 * also destroys the message.
367 *
368 * @throws JMSException for any error
369 */
370 public void destroy() throws JMSException {
371 getMessageRef().dereference();
372 }
373
374 /***
375 * Release the message handle back to the cache, to recover an unsent or
376 * unacknowledged message.
377 *
378 * @throws JMSException for any error
379 */
380 public void release() throws JMSException {
381 if (_cache == null) {
382 throw new IllegalStateException(
383 "Can't release message: not associated with any cache");
384 }
385 _cache.returnMessageHandle(this);
386 }
387
388 /***
389 * Returns the message reference.
390 *
391 * @return the message reference, or <code>null</code> if none has been set
392 */
393 public MessageRef getMessageRef() {
394 return _reference;
395 }
396
397 /***
398 * Sets the message reference.
399 *
400 * @param reference the reference to the message
401 */
402 protected void setMessageRef(MessageRef reference) {
403 _reference = reference;
404 }
405
406 /***
407 * Sets the destination cache.
408 *
409 * @param cache the destination cache
410 */
411 protected void setDestinationCache(DestinationCache cache) {
412 _cache = cache;
413 }
414
415 /***
416 * Release the message handle back to the cache, to recover an unsent or
417 * unacknowledged message.
418 * <p/>
419 * This should be used when the parent in a chain of handles needs to be
420 * released.
421 *
422 * @param handle the handle to release
423 * @throws JMSException for any error
424 */
425 protected void release(MessageHandle handle) throws JMSException {
426 if (_cache == null) {
427 throw new IllegalStateException(
428 "Can't release message: not associated with any cache");
429 }
430 _cache.returnMessageHandle(handle);
431 }
432
433
434
435 }