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 2001-2003 (C) Exoffice Technologies Inc. All Rights Reserved.
42 *
43 * $Id: PersistentMessageHandle.java,v 1.17 2003/08/07 13:33:04 tanderson Exp $
44 *
45 * Date Author Changes
46 * 3/1/2001 jima Created
47 */
48 package org.exolab.jms.messagemgr;
49
50 import java.io.IOException;
51 import java.io.ObjectInput;
52 import java.io.ObjectOutput;
53 import java.sql.Connection;
54
55 import javax.jms.DeliveryMode;
56 import javax.jms.JMSException;
57 import javax.transaction.TransactionManager;
58
59 import org.exolab.core.foundation.PersistentObject;
60 import org.exolab.jms.client.JmsDestination;
61 import org.exolab.jms.client.JmsQueue;
62 import org.exolab.jms.client.JmsTopic;
63 import org.exolab.jms.message.MessageHandle;
64 import org.exolab.jms.message.MessageId;
65 import org.exolab.jms.message.MessageImpl;
66 import org.exolab.jms.persistence.DatabaseService;
67 import org.exolab.jms.persistence.PersistenceException;
68
69
70 /***
71 * A persistent message handle extends {@link MessageHandle} and references a
72 * persistent message. These messages can be discarded from the cache and later
73 * faulted in through the 'resolve' method.
74 *
75 * @version $Revision: 1.17 $ $Date: 2003/08/07 13:33:04 $
76 * @author <a href="mailto:jima@exoffice.com">Jim Alateras</a>
77 **/
78 public class PersistentMessageHandle
79 extends PersistentObject
80 implements MessageHandle, Cloneable {
81
82 /***
83 * Used for serialization
84 */
85 static final long serialVersionUID = 1;
86
87 /***
88 * This is the message id of the underlying message
89 */
90 private MessageId _id = null;
91
92 /***
93 * This is the priority of the inderlying message
94 */
95 private int _priority;
96
97 /***
98 * A flag indicating whether an attempt was made to deliver the message
99 */
100 private boolean _delivered;
101
102 /***
103 * a transient attribute, to associate this handle with an endpoint
104 */
105 private transient long _clientId = -1;
106
107 /*
108 * The time that the underlying message was accepted by the server
109 */
110 private long _acceptedTime;
111
112 /***
113 * This is the sequence number assigned to it by the message manager
114 * that created this handle
115 */
116 private long _sequenceNumber;
117
118 /***
119 * The expiry time of this message. 0 if it doesn't expire
120 */
121 private long _expiryTime;
122
123 /***
124 * The name of the durable consumer that this handle belongs too
125 */
126 private String _consumerName;
127
128 /***
129 * The destination that this handle belongs too
130 */
131 private JmsDestination _destination;
132
133
134 /***
135 * Cache the hashcode for this object
136 */
137 private transient int _hashCode = -1;
138
139
140 /***
141 * Default constructor
142 */
143 public PersistentMessageHandle() {
144 super();
145 }
146
147 /***
148 * Create a persistent handle from a message
149 *
150 * @param message - persistent message
151 * @exception JMSException - if the object cannot be constructed
152 */
153 public PersistentMessageHandle(MessageImpl message)
154 throws JMSException {
155 super();
156
157 if ((message != null) &&
158 (message.getJMSDeliveryMode() == DeliveryMode.PERSISTENT)) {
159 _id = message.getMessageId();
160 _priority = message.getJMSPriority();
161 _delivered = message.getJMSRedelivered();
162 _destination = (JmsDestination) message.getJMSDestination();
163 _acceptedTime = message.getAcceptedTime();
164 _expiryTime = message.getJMSExpiration();
165 _sequenceNumber = message.getSequenceNumber();
166 _clientId = message.getClientId();
167 } else {
168 throw new JMSException(
169 "Cannot create persistent handle from non-persistent message");
170 }
171 }
172
173 /***
174 * Set the identity of the underlying message
175 *
176 * @param id - the message id
177 */
178 public void setMessageId(MessageId id) {
179 _id = id;
180 }
181
182 /***
183 * Return the identity of the underlying message
184 *
185 * @return MessageId
186 */
187 public MessageId getMessageId() {
188 return _id;
189 }
190
191 /***
192 * Return the associated message or null if it is invalid
193 *
194 * @return MessageImpl
195 */
196 public MessageImpl getMessage() {
197 return (MessageImpl) MessageMgr.instance().getMessage(this);
198 }
199
200 /***
201 * Set the messagee priority
202 *
203 * @param id the persistent id
204 */
205 public void setPriority(int priority) {
206 _priority = priority;
207 }
208
209 /***
210 * Return the priority of the corresponding message
211 *
212 * @return int
213 */
214 public int getPriority() {
215 return _priority;
216 }
217
218 /***
219 * Set the delivered flag for the underlying message. True if an attempt
220 * has been made to deliver the message
221 *
222 * @param value - true if delivered
223 */
224 public void setDelivered(boolean value) {
225 _delivered = value;
226 }
227
228 /***
229 * Return the delivered state of the message
230 *
231 * @return long
232 */
233 public boolean getDelivered() {
234 return _delivered;
235 }
236
237 /***
238 * Set the time that the message was accepted by the server
239 *
240 * @param long - time since epoch
241 */
242 public void setAcceptedTime(long time) {
243 _acceptedTime = time;
244 }
245
246 /***
247 * Return the time that the message was accepted by the server
248 *
249 * @return long - time in ms since epoch
250 */
251 public long getAcceptedTime() {
252 return _acceptedTime;
253 }
254
255 /***
256 * Set the message's sequence number
257 *
258 * @param seq - sequence time
259 */
260 public void setSequenceNumber(long seq) {
261 _sequenceNumber = seq;
262 }
263
264 /***
265 * Return message's sequence number
266 *
267 * @return long - the sequence number
268 */
269 public long getSequenceNumber() {
270 return _sequenceNumber;
271 }
272
273 /***
274 * Set the message expiry time
275 *
276 * @long time - time in ms since epoch
277 */
278 public void setExpiryTime(long time) {
279 _expiryTime = time;
280 }
281
282 /***
283 * Return the message expiry time
284 *
285 * @return long - time in ms since epoch
286 */
287 public long getExpiryTime() {
288 return _expiryTime;
289 }
290
291 /***
292 * Determines if the message has expired
293 *
294 * @return <code>true</code> if the message has expired, otherwise
295 * <code>false</code>
296 */
297 public boolean hasExpired() {
298 return (_expiryTime != 0 && _expiryTime <= System.currentTimeMillis());
299 }
300
301 // implementation of MessageHandle.setConsumerName
302 public void setConsumerName(String name) {
303 _consumerName = name;
304 }
305
306 // implementation of MessageHandle.getConsumerName
307 public String getConsumerName() {
308 return _consumerName;
309 }
310
311 // implementation of MessageHandle.isPersistent
312 public boolean isPersistent() {
313 return true;
314 }
315
316 /***
317 * Set the destination that owns this handle
318 *
319 * @param destination - the destination
320 */
321 public void setDestination(JmsDestination destination) {
322 _destination = destination;
323 }
324
325 /***
326 * Return the destination for this handle
327 *
328 * @return JmsDestination
329 */
330 public JmsDestination getDestination() {
331 return _destination;
332 }
333
334 /***
335 * Set the client id, that owns this handle
336 *
337 * @param clientId - client identity
338 */
339 public void setClientId(long clientId) {
340 _clientId = clientId;
341 }
342
343 /***
344 * Retrieve the client identity associated with this handle
345 *
346 * @return long
347 */
348 public long getClientId() {
349 return _clientId;
350 }
351
352 /***
353 * Override the behaviour of the base class. I don't think we want to
354 * clear the handle unless there are definitely no more references.
355 */
356 public void clear() {
357 }
358
359 /***
360 * Destroy this handle
361 */
362 public void destroy() {
363 // notify the message manager
364 MessageMgr.instance().handleDestroyed(this);
365
366 // remove the handle from the database
367 Connection connection = null;
368 TransactionManager tm = null;
369
370 try {
371 connection = DatabaseService.getConnection();
372 DatabaseService.getAdapter().removeMessageHandle(connection, this);
373 connection.commit();
374 } catch (PersistenceException exception) {
375 if (connection != null) {
376 try {
377 connection.rollback();
378 } catch (Exception nested) {
379 // ignore
380 }
381 }
382 } catch (Exception exception) {
383 // ignore for the moment
384 } finally {
385 if (connection != null) {
386 try {
387 connection.close();
388 } catch (Exception nested) {
389 // ignore
390 }
391 }
392 }
393 }
394
395 /***
396 * Clone the persistent message handle object
397 *
398 * @return copy of a PersistentMessageHandle
399 * @throws CloneNotSupportedException
400 */
401 public Object clone() throws CloneNotSupportedException {
402 PersistentMessageHandle handle =
403 (PersistentMessageHandle) super.clone();
404
405 handle._id = new MessageId(_id.getId());
406 handle._priority = _priority;
407 handle._delivered = _delivered;
408 handle._acceptedTime = _acceptedTime;
409 handle._expiryTime = _expiryTime;
410 handle._consumerName = _consumerName;
411 handle._sequenceNumber = _sequenceNumber;
412
413 // clone the destination
414 if (_destination instanceof JmsQueue) {
415 handle._destination = new JmsQueue(_destination.getName());
416 } else {
417 handle._destination = new JmsTopic(_destination.getName());
418 }
419 handle._destination.setPersistent(true);
420
421 return handle;
422 }
423
424 // override the definition of equals
425 public boolean equals(Object object) {
426
427 boolean result = false;
428
429 if ((object != null) &&
430 (object instanceof PersistentMessageHandle)) {
431
432 PersistentMessageHandle mhdl = (PersistentMessageHandle) object;
433 if (mhdl._id.equals(_id)) {
434 result = true;
435 }
436
437 //if ((mhdl._id.equals(_id)) &&
438 // (mhdl._consumerName.equals(_consumerName))) {
439 // result = true;
440 //}
441 }
442
443 return result;
444 }
445
446 // override the Object.toString()
447 public String toString() {
448 return ("Handle : " + _id.getId() + "@" + _consumerName + ":" +
449 _sequenceNumber + ":" + _acceptedTime + ":" + _priority);
450 }
451
452
453 // override the definition of hashCode
454 public int hashCode() {
455 if (_hashCode == -1) {
456 _hashCode = (_id + _consumerName).hashCode();
457 }
458
459 return _hashCode;
460 }
461
462 /***
463 * This is used to set the message as delivered. This can only be called
464 * by the delivery engine and should not be used anywhere else. This will
465 * mark the message as being delivered and also update the database
466 * <p>
467 * We do not really throw an exception here....and it seems that this is
468 * a very fine grained approach to dealing with this...basically translates to
469 * a transaction for every message.
470 */
471 public void setDelivered() {
472 if (!_delivered) {
473
474 Connection connection = null;
475 TransactionManager tm = null;
476
477 try {
478 connection = DatabaseService.getConnection();
479
480 DatabaseService.getAdapter().updateMessageHandle(connection,
481 this);
482 _delivered = true;
483
484 // commit the transactions
485 connection.commit();
486 } catch (PersistenceException exception) {
487 System.err.println("Failed in setDelivereds b/c " +
488 exception.toString());
489 if (connection != null) {
490 try {
491 connection.rollback();
492 } catch (Exception nested) {
493 // ignore
494 }
495 }
496 } catch (Exception exception) {
497 // ignore for the moment
498 } finally {
499 if (connection != null) {
500 try {
501 connection.close();
502 } catch (Exception nested) {
503 // ignore
504 }
505 }
506 }
507 }
508 }
509
510 // implementation of Externalizable.writeExternal
511 public void writeExternal(ObjectOutput stream)
512 throws IOException {
513 stream.writeLong(serialVersionUID);
514 stream.writeObject(_id);
515 stream.writeInt(_priority);
516 stream.writeBoolean(_delivered);
517 stream.writeLong(_acceptedTime);
518 stream.writeLong(_sequenceNumber);
519 stream.writeLong(_expiryTime);
520 stream.writeObject(_consumerName);
521 stream.writeObject(_destination);
522 super.writeExternal(stream);
523 }
524
525 // implementation of Externalizable.writeExternal
526 public void readExternal(ObjectInput stream)
527 throws IOException, ClassNotFoundException {
528 long version = stream.readLong();
529 if (version == serialVersionUID) {
530 _id = (MessageId) stream.readObject();
531 _priority = stream.readInt();
532 _delivered = stream.readBoolean();
533 _acceptedTime = stream.readLong();
534 _sequenceNumber = stream.readLong();
535 _expiryTime = stream.readLong();
536 _consumerName = (String) stream.readObject();
537 _destination = (JmsDestination) stream.readObject();
538 super.readExternal(stream);
539 } else {
540 throw new IOException("PersistentMessageHandle with version " +
541 version + " is not supported.");
542 }
543 }
544 }
545
This page was automatically generated by Maven