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 2000-2003 (C) Exoffice Technologies Inc. All Rights Reserved.
42 *
43 * $Id: ObjectAdapter.java,v 1.30 2003/08/17 01:32:25 tanderson Exp $
44 *
45 * Date Author Changes
46 * $Date jimm Created
47 */
48
49
50 package org.exolab.jms.persistence;
51
52 import java.io.Externalizable;
53 import java.io.IOException;
54 import java.io.ObjectInput;
55 import java.io.ObjectOutput;
56 import java.sql.Connection;
57 import java.util.Enumeration;
58 import java.util.HashMap;
59 import java.util.Vector;
60
61 import javax.jms.JMSException;
62
63 import org.apache.commons.logging.Log;
64 import org.apache.commons.logging.LogFactory;
65
66 import org.exolab.core.database.recman.PMDHandle;
67 import org.exolab.core.database.recman.PMDHashMap;
68 import org.exolab.core.database.recman.PMDSessionManager;
69 import org.exolab.core.database.recman.PMDVector;
70 import org.exolab.core.database.recman.PageManagedDatabase;
71 import org.exolab.core.foundation.DatabaseIOException;
72 import org.exolab.core.foundation.FailedToAcquireLockException;
73 import org.exolab.core.foundation.FailedToCreateCollectionException;
74 import org.exolab.core.foundation.FailedToCreateDatabaseException;
75 import org.exolab.core.foundation.FailedToCreateLockException;
76 import org.exolab.core.foundation.FailedToCreateSessionException;
77 import org.exolab.core.foundation.FailedToDestroySessionException;
78 import org.exolab.core.foundation.HandleIfc;
79 import org.exolab.core.foundation.ObjectNameExistsException;
80 import org.exolab.core.foundation.PersistentObject;
81 import org.exolab.core.foundation.SessionIfc;
82 import org.exolab.core.foundation.TransactionException;
83 import org.exolab.core.foundation.TransactionInProgressException;
84 import org.exolab.core.foundation.TransactionNotInProgressException;
85 import org.exolab.jms.authentication.User;
86 import org.exolab.jms.client.JmsDestination;
87 import org.exolab.jms.client.JmsQueue;
88 import org.exolab.jms.client.JmsTopic;
89 import org.exolab.jms.config.Configuration;
90 import org.exolab.jms.config.ConfigurationManager;
91 import org.exolab.jms.config.DatabaseConfiguration;
92 import org.exolab.jms.events.BasicEventManager;
93 import org.exolab.jms.events.Event;
94 import org.exolab.jms.events.EventHandler;
95 import org.exolab.jms.events.IllegalEventDefinedException;
96 import org.exolab.jms.message.DestinationImpl;
97 import org.exolab.jms.message.MessageImpl;
98 import org.exolab.jms.messagemgr.PersistentMessageHandle;
99
100
101 /***
102 * This adapter is a wrapper class around the persistency mechanism.
103 * It isolates the client from the working specifics of the database, by
104 * providing a simple straight forward interface. Furure changes to
105 * the database will only require changes to the adapter.
106 *
107 * <P>For this release the PageManager is used as the underlying database.
108 *
109 * @version $Revision: 1.30 $ $Date: 2003/08/17 01:32:25 $
110 * @author <a href="mailto:mourikis@exolab.org">Jim Mourikis</a>
111 * @see org.exolab.core.database.recman.PMDSessionManager
112 * @see org.exolab.core.database.recman.PMDHashMap
113 * @see org.exolab.core.database.recman.PMDVector
114 * @see org.exolab.core.foundation.PersistentObject
115 */
116 public class ObjectAdapter
117 extends PersistenceAdapter
118 implements EventHandler {
119
120 // the database instance
121 private PageManagedDatabase db_ = null;
122
123 // The name of this database.
124 private String dbname_ = null;
125
126 // The max time to wait to aquire a lock
127 static private int MAX_WAIT_TIME = 5000;
128
129 // The root name for storing messages
130 final static private String MESSAGES = "MESSAGES";
131
132 // The root name for storing destinations
133 final static private String DESTINATIONS = "DESTINATIONS";
134
135 // All consumers or destinations have a handle
136 final static private String HANDLES = "HANDLES";
137
138 // All topics destinations are prefixed with
139 final static private String TOPIC = "T_";
140
141 // All queue destinations are prefixed with
142 final static private String QUEUE = "Q_";
143
144 //The root name of the max id storage location
145 final static private String IDSTORAGE = "IDSTORAGE";
146
147 //The database schema version root
148 final static private String VERSIONID = "VERSIONID";
149
150 // The schema version number. Note this must be incremented whenever
151 // The schema changes.
152 final static private long VERSIONNUM = 7;
153
154 // The minimum persistent consumer list size
155 private int minConsumerListSize_ = 10000;
156
157 // The minimum persistent message list size
158 private int minMessageListSize_ = 20000;
159
160 /***
161 * Reference to a dummy connection object, used to satisfy the fact
162 * that the object adapter can look like an Connection object
163 */
164 private NullConnection _connection = new NullConnection();
165
166 /***
167 * This is the interval that the automatic garbage collector will
168 * execute, if specified. It is specified in seconds.
169 */
170 private int _gcInterval = 600;
171
172 /***
173 * This is the block size that is used during purging.
174 */
175 private int _gcBlockSize = 500;
176
177 /***
178 * This is the thread priority for the GC Thread
179 */
180 private int _gcThreadPriority = Thread.NORM_PRIORITY;
181
182 /***
183 * This is the event that is fired to initiate garbage collection
184 * in the database
185 */
186 private static final int COLLECT_DATABASE_GARBAGE_EVENT = 1;
187
188 /***
189 * The size of the CACHE used by the JDBM
190 */
191 private static final int MIN_CACHE_SIZE = 512;
192
193 /***
194 * The logger
195 */
196 private static final Log _log = LogFactory.getLog(ObjectAdapter.class);
197
198
199 /***
200 * Constructs a databse with the given name, if one does not exist,
201 * otherwise opens the existing database.
202 * The database name is checked to see if it already has a ".db" at the
203 * end and stripped off if it does. The PageManagedDatabase always
204 * prefixes ".db" to any name passed in.
205 *
206 * @throws PersistenceException for any database error
207 *
208 */
209 public ObjectAdapter(String dbName, int minListSize, int minMsgSize,
210 int minCacheSize)
211 throws PersistenceException {
212
213 minConsumerListSize_ = Math.max(minConsumerListSize_, minListSize);
214 minMessageListSize_ = Math.max(minMessageListSize_, minMsgSize);
215
216 dbname_ = fixName(dbName);
217 try {
218 db_ = new PageManagedDatabase(dbname_);
219
220 // set the cache object size
221 //db_.setObjectCacheSize(Math.max(MIN_CACHE_SIZE, minCacheSize));
222
223 // initialise the session manager with the created database and
224 // then
225 // check the version to ensure that it is compatible.
226 PMDSessionManager.init(db_);
227 } catch (FailedToCreateDatabaseException exception) {
228 throw new PersistenceException(
229 "Failed to initialise database adapter", exception);
230 }
231
232 checkVersion();
233 _log.debug("minConsumerListSize = " + minConsumerListSize_);
234 _log.debug("minMessageListSize = " + minMessageListSize_);
235
236 // create the roots if they do not already exist
237 // jima - we really need to improve this part of the code
238 try {
239 createIdRoot();
240 } catch (Exception exception) {
241 throw new PersistenceException(
242 "Failed to create database root", exception);
243 }
244
245 // check whether we should initiate automatic garbage collection
246 DatabaseConfiguration config =
247 ConfigurationManager.getConfig().getDatabaseConfiguration();
248 if (config.hasGarbageCollectionInterval()) {
249 _gcInterval =
250 config.getGarbageCollectionInterval() * 1000;
251 registerEvent();
252 }
253
254 if (config.hasGarbageCollectionBlockSize()) {
255 _gcBlockSize =
256 config.getGarbageCollectionBlockSize();
257 }
258
259 if (config.hasGarbageCollectionThreadPriority()) {
260 _gcThreadPriority =
261 config.getGarbageCollectionBlockSize();
262 if (_gcThreadPriority < Thread.MIN_PRIORITY) {
263 _gcThreadPriority = Thread.MIN_PRIORITY;
264 } else if (_gcThreadPriority > Thread.MAX_PRIORITY) {
265 _gcThreadPriority = Thread.MAX_PRIORITY;
266 }
267 }
268 }
269
270 /***
271 * Fix up the database name, by striping off any ".xx" suffixes.
272 *
273 */
274 private String fixName(String dbName) {
275 String newDbName = dbName;
276 newDbName.trim();
277
278 int i = newDbName.lastIndexOf('.');
279 if (i > 0 && i < (newDbName.length() - 1)) {
280 newDbName = newDbName.substring(0, i);
281 }
282 return newDbName;
283 }
284
285 /***
286 * Close the database if open.
287 *
288 */
289 public void close() {
290 if (db_ != null) {
291 db_.close();
292 dbname_ = null;
293 db_ = null;
294 }
295 }
296
297 /***
298 * Check to see if the version is correct. if this is the first time the
299 * database has been opened, then created the version root, and itialise
300 * the version.
301 *
302 */
303 private void checkVersion() {
304 try {
305 PMDVector vector;
306 SessionIfc session = getSession();
307
308 session.getCurrentTransaction().begin();
309 if ((vector = (PMDVector) session.lookup(VERSIONID)) == null) {
310 _log.debug("Setting Version Id");
311 vector =
312 (PMDVector) session.getCollectionManager().createVector();
313 session.createObject(vector);
314 session.bind(VERSIONID, vector);
315 session.getCurrentTransaction().commit();
316
317 session.getCurrentTransaction().begin();
318 vector = (PMDVector) session.lookup(VERSIONID);
319 session.acquireLock(vector, 10);
320 vector.addElement(new PMDLongInteger(VERSIONNUM));
321 session.updateObject(vector);
322 session.getCurrentTransaction().commit();
323 } else {
324 if (vector.size() == 1) {
325 long ver;
326
327 if ((ver = ((PMDLongInteger) vector.get(0)).get())
328 != VERSIONNUM) {
329 _log.error(
330 "Incompatible Database version Schema\n" +
331 "Db Vesrsion = " + ver + "\tSchema Version = "
332 + VERSIONNUM + "\nExiting...");
333 System.exit(-1);
334 }
335 } else {
336 _log.error("Corrupted Db schema version ID:\n " +
337 "Exiting...");
338 System.exit(-1);
339 }
340 session.getCurrentTransaction().abort();
341 }
342 try {
343 PMDSessionManager.instance().destroySession();
344 } catch (FailedToDestroySessionException exception) {
345 _log.error("Failed to destroy session", exception);
346 }
347 } catch (Exception exception) {
348 _log.error("Error verifying DB schema, exiting", exception);
349 System.exit(-1);
350 }
351
352 }
353
354 /***
355 * Check to see if the Id root has been created.
356 * If not create it and initialise it. This is used as a sequencer
357 * to number all Messages that are delivered to OpenJMS server.
358 *
359 */
360 private void createIdRoot()
361 throws FailedToCreateSessionException, TransactionInProgressException,
362 FailedToCreateCollectionException, DatabaseIOException,
363 TransactionNotInProgressException, ObjectNameExistsException,
364 TransactionException, FailedToCreateLockException,
365 FailedToAcquireLockException, FailedToDestroySessionException {
366 PMDVector vector;
367 PMDHashMap map;
368 SessionIfc session = getSession();
369
370 session.getCurrentTransaction().begin();
371 if ((vector = (PMDVector) session.lookup(IDSTORAGE)) == null) {
372 _log.debug("Creating ID Storage root");
373 vector =
374 (PMDVector) session.getCollectionManager().createVector();
375 session.createObject(vector);
376 session.bind(IDSTORAGE, vector);
377 session.getCurrentTransaction().commit();
378
379 session.getCurrentTransaction().begin();
380 vector = (PMDVector) session.lookup(IDSTORAGE);
381 session.acquireLock(vector, MAX_WAIT_TIME);
382 vector.addElement(new PMDLongInteger(0));
383 session.updateObject(vector);
384 session.getCurrentTransaction().commit();
385 } else {
386 session.getCurrentTransaction().abort();
387 }
388
389 session.getCurrentTransaction().begin();
390 if ((map = (PMDHashMap) session.lookup(MESSAGES)) == null) {
391 _log.debug("Creating Messages root");
392 map =
393 (PMDHashMap) session.getCollectionManager().createHashMap();
394 session.createObject(map);
395 session.bind(MESSAGES, map);
396 session.getCurrentTransaction().commit();
397 } else {
398 session.getCurrentTransaction().abort();
399 }
400
401 session.getCurrentTransaction().begin();
402 if ((vector = (PMDVector) session.lookup(DESTINATIONS)) == null) {
403 _log.debug("Creating Destinations root");
404 vector =
405 (PMDVector) session.getCollectionManager().createVector();
406 session.createObject(vector);
407 session.bind(DESTINATIONS, vector);
408 session.getCurrentTransaction().commit();
409 } else {
410 session.getCurrentTransaction().abort();
411 }
412 PMDSessionManager.instance().destroySession();
413 }
414
415 // implementation of PersistenceAdapter.getLastIds
416 public long getLastId(Connection connection)
417 throws PersistenceException {
418 long lastId = -1;
419
420 try {
421 createIdRoot();
422 PMDVector vector;
423 SessionIfc session = getSession();
424
425 session.getCurrentTransaction().begin();
426 if ((vector = (PMDVector) session.lookup(IDSTORAGE)) != null) {
427 if (vector.size() == 1) {
428 lastId = ((PMDLongInteger) vector.get(0)).get();
429 }
430 }
431 session.getCurrentTransaction().abort();
432 } catch (Exception err) {
433 _log.error("Failed to get Id: " + err.getMessage());
434 }
435 try {
436 PMDSessionManager.instance().destroySession();
437 } catch (FailedToDestroySessionException sessErr) {
438 _log.error("Failed to destroy session: " +
439 sessErr.getMessage());
440 sessErr.printStackTrace();
441 // Session not destroyed.
442 }
443 return lastId;
444 }
445
446 // implementation of PersistenceAdapter.updateIds
447 public void updateIds(Connection connection, long id)
448 throws PersistenceException {
449 try {
450 PMDVector vector;
451 SessionIfc session = getSession();
452
453 session.getCurrentTransaction().begin();
454 if ((vector = (PMDVector) session.lookup(IDSTORAGE)) != null) {
455 session.acquireLock(vector, MAX_WAIT_TIME);
456 if (vector.size() == 1) {
457 vector.set(0, new PMDLongInteger(id));
458 session.updateObject(vector);
459 }
460
461 }
462 session.getCurrentTransaction().commit();
463 } catch (Exception err) {
464 throw new PersistenceException("Failed to get Id: " + err.getMessage());
465 }
466 try {
467 PMDSessionManager.instance().destroySession();
468 } catch (FailedToDestroySessionException sessErr) {
469 _log.error("Failed to destroy session", sessErr);
470 }
471 }
472
473 // implementation of PersistenceAdapter.addMessage
474 public synchronized void addMessage(Connection connection,
475 MessageImpl message)
476 throws PersistenceException {
477
478 try {
479 DestinationImpl dest =
480 (DestinationImpl) message.getJMSDestination();
481 String name = dest.getDestination();
482 PMDHashMap messages;
483 SessionIfc session = getSession();
484
485 session.getCurrentTransaction().begin();
486
487 messages = messageTable(session);
488
489 if (messages != null) {
490 try {
491 session.acquireLock(messages, MAX_WAIT_TIME);
492
493 // check to see that the message does not exist
494 String id = message.getMessageId().getId();
495 if (messages.get(id) == null) {
496 PersistentMessage pm = new PersistentMessage(message);
497 session.createObject(pm);
498 // when we initially add a message to the database it
499 // must go in the unprocessed list
500 messages.put(id, session.createHandle(pm));
501 session.updateObject(messages);
502 } else {
503 throw new PersistenceException("Mesage with this id: " +
504 message.getJMSMessageID() +
505 " already exists: NOT ADDING");
506 }
507 } catch (Exception err) {
508 throw new PersistenceException("Error in addMessage " +
509 err.toString());
510 }
511 } else {
512 _log.error("Attempt to save message for non register" +
513 " queue/topic, name = " + name);
514 }
515
516 session.getCurrentTransaction().commit();
517 PMDSessionManager.instance().destroySession();
518 } catch (PersistenceException exception) {
519 // rethrowe it
520 throw exception;
521 } catch (Exception err) {
522 throw new PersistenceException("Error in addMessage " + err.toString());
523 }
524 }
525
526 // implementation of PersistenceAdapter.updateMessage
527 public synchronized void updateMessage(Connection connection,
528 MessageImpl message)
529 throws PersistenceException {
530
531 try {
532 DestinationImpl dest =
533 (DestinationImpl) message.getJMSDestination();
534 String name = dest.getDestination();
535 PMDHashMap messages;
536 SessionIfc session = getSession();
537
538 session.getCurrentTransaction().begin();
539
540 messages = messageTable(session);
541
542 if (messages != null) {
543 try {
544 session.acquireLock(messages, MAX_WAIT_TIME);
545
546 // check to see that the message does not exist
547 String id = message.getMessageId().getId();
548 if (messages.get(id) != null) {
549 // remove the old message and update it
550 PMDHandle handle = (PMDHandle) messages.get(id);
551 PersistentMessage pm = (PersistentMessage) handle.resolve();
552 pm.setMessage(message);
553 pm.setProcessed(message.getProcessed());
554 session.updateObject(pm);
555 } else {
556 throw new PersistenceException("Mesage with this id: " +
557 message.getJMSMessageID() +
558 " doesn't exists: NOT UPDATING");
559 }
560 } catch (Exception err) {
561 throw new PersistenceException("Error in updateMessage " +
562 err.toString());
563 }
564 } else {
565 throw new PersistenceException("Attempt to save message for non register" +
566 " queue/topic, name = " + name);
567 }
568
569 session.getCurrentTransaction().commit();
570 PMDSessionManager.instance().destroySession();
571 } catch (PersistenceException pe) {
572 throw pe;
573 } catch (Exception err) {
574 throw new PersistenceException("Error in updateMessage " +
575 err.toString());
576 }
577 }
578
579 // implementation of PersistenceAdapter.removeMessage
580 public synchronized void removeMessage(Connection connection, String id)
581 throws PersistenceException {
582
583 try {
584 PMDHashMap map;
585 SessionIfc session = getSession();
586
587 session.getCurrentTransaction().begin();
588
589 if ((map = messageTable(session)) != null) {
590 try {
591 session.acquireLock(map, MAX_WAIT_TIME);
592 PMDHandle handle = (PMDHandle) map.remove(id);
593 if (handle != null) {
594 session.deleteObject
595 ((PersistentMessage) handle.resolve());
596 }
597
598 session.updateObject(map);
599 } catch (Exception err) {
600 throw new PersistenceException("Error in removeMessage " +
601 err.toString());
602 }
603 } else {
604 throw new PersistenceException("Error in removeMessage " +
605 "Cannot retrieve the message talbe ");
606 }
607
608 session.getCurrentTransaction().commit();
609 PMDSessionManager.instance().destroySession();
610 } catch (PersistenceException pe) {
611 throw pe;
612 } catch (Exception err) {
613 throw new PersistenceException("Error in removeMessage " +
614 err.toString());
615 }
616 }
617
618 // implementation of PersistenceAdapter.getMessage
619 public synchronized MessageImpl getMessage(Connection connection, String id)
620 throws PersistenceException {
621 MessageImpl message = null;
622
623 try {
624 PMDHashMap map;
625 SessionIfc session = getSession();
626
627 session.getCurrentTransaction().begin();
628
629 if ((map = messageTable(session)) != null) {
630 try {
631 session.acquireLock(map, MAX_WAIT_TIME);
632 PMDHandle handle = (PMDHandle) map.get(id);
633 PersistentMessage m = null;
634
635 if (handle != null) {
636 m = (PersistentMessage) handle.resolve();
637 }
638
639 if (m != null) {
640 message = m.getMessage();
641 }
642 } catch (Exception err) {
643 throw new PersistenceException("Error in getMessage " +
644 err.toString());
645 }
646 } else {
647 throw new PersistenceException("Error in getMessage " +
648 "Failed to retrieve the message table.");
649 }
650 session.getCurrentTransaction().abort();
651 PMDSessionManager.instance().destroySession();
652 } catch (PersistenceException pe) {
653 throw pe;
654 } catch (Exception err) {
655 throw new PersistenceException("Error in getMessage " +
656 err.toString());
657 }
658 return message;
659 }
660
661 // implementation of PersistenceAdapter.getUnprocessedMessages
662 public synchronized Vector getUnprocessedMessages(Connection connection)
663 throws PersistenceException {
664 Vector result = new Vector();
665
666 try {
667 PMDHashMap map;
668 SessionIfc session = getSession();
669
670 session.getCurrentTransaction().begin();
671
672 if ((map = messageTable(session)) != null) {
673 try {
674 session.acquireLock(map, MAX_WAIT_TIME);
675 Enumeration iter = map.elements();
676 while (iter.hasMoreElements()) {
677 PMDHandle handle = (PMDHandle) iter.nextElement();
678 PersistentMessage m =
679 (PersistentMessage) handle.resolve();
680
681 if (!m.getProcessed()) {
682 result.add(m.getMessage());
683 }
684 }
685 } catch (Exception err) {
686 throw new PersistenceException(
687 "Error in getUnprocessedMessages " + err.toString());
688 }
689 } else {
690 throw new PersistenceException(
691 "Error in getUnprocessedMessage. Failed to get message table");
692 }
693 session.getCurrentTransaction().abort();
694 PMDSessionManager.instance().destroySession();
695 } catch (PersistenceException pe) {
696 throw pe;
697 } catch (Exception err) {
698 throw new PersistenceException("Error in getUnprocessedMessages "
699 + err.toString());
700 }
701 return result;
702 }
703
704 // implementation of PersistenceAdapter.getMessages
705 public synchronized Vector getMessages(Connection connection,
706 PersistentMessageHandle handle)
707 throws PersistenceException {
708 Vector messages = new Vector();
709
710 // for the jdbm only ever retrieve a single message. We could improve
711 // this at a later date.
712 MessageImpl message = getMessage(connection,
713 handle.getMessageId().getId());
714 if (message != null) {
715 messages.add(message);
716 }
717
718 return messages;
719 }
720
721 // implementation of PersistenceAdapter.addMessageHandle
722 public synchronized void addMessageHandle(Connection connection,
723 PersistentMessageHandle handle)
724 throws PersistenceException {
725
726 try {
727 PMDVector vector;
728 SessionIfc session = getSession();
729 String key = getHandlesRootName(handle.getDestination(),
730 handle.getConsumerName());
731
732
733 session.getCurrentTransaction().begin();
734
735 if ((vector = handleTable(key, session)) != null) {
736 try {
737 session.acquireLock(vector, MAX_WAIT_TIME);
738 vector.addElement(handle);
739 session.updateObject(vector);
740 } catch (Exception err) {
741 throw new PersistenceException("Error in addMessageHandle " +
742 err.toString());
743 }
744 } else {
745 throw new PersistenceException("Error in addMessageHandle " +
746 "Cannot get handle table for " + key);
747 }
748
749 session.getCurrentTransaction().commit();
750 PMDSessionManager.instance().destroySession();
751 } catch (PersistenceException pe) {
752 throw pe;
753 } catch (Exception err) {
754 throw new PersistenceException("Error in addMessageHandle " +
755 err.toString());
756 }
757 }
758
759 // implementation of PersistenceAdapter.updateMessageHandle
760 public synchronized void updateMessageHandle(Connection connection,
761 PersistentMessageHandle handle)
762 throws PersistenceException {
763
764 try {
765 PMDVector vector;
766 SessionIfc session = getSession();
767 String key = getHandlesRootName(handle.getDestination(),
768 handle.getConsumerName());
769
770
771 session.getCurrentTransaction().begin();
772
773 if ((vector = handleTable(key, session)) != null) {
774 try {
775 session.acquireLock(vector, MAX_WAIT_TIME);
776
777 // linear search for the matching handle
778 Enumeration handles = vector.elements();
779 while (handles.hasMoreElements()) {
780 PersistentMessageHandle phdl =
781 (PersistentMessageHandle) handles.nextElement();
782
783 if (phdl.getMessageId().getId().equals(
784 handle.getMessageId().getId())) {
785 phdl.setDelivered(true);
786 break;
787 }
788 }
789 session.updateObject(vector);
790 } catch (Exception err) {
791 throw new PersistenceException("Error in addMessageHandle " +
792 err.toString());
793 }
794 } else {
795 throw new PersistenceException("Error in updateMessageHandle " +
796 "Failed to get handle table for " + key);
797 }
798
799 session.getCurrentTransaction().commit();
800 PMDSessionManager.instance().destroySession();
801 } catch (PersistenceException pe) {
802 throw pe;
803 } catch (Exception err) {
804 throw new PersistenceException("Error in updateMessageHandle " +
805 err.toString());
806 }
807 }
808
809 // implementation of PersistenceAdapter.removeMessageHandle
810 public synchronized void removeMessageHandle(Connection connection,
811 PersistentMessageHandle handle)
812 throws PersistenceException {
813
814 try {
815 PMDVector vector;
816 SessionIfc session = getSession();
817 String key = getHandlesRootName(handle.getDestination(),
818 handle.getConsumerName());
819
820
821 session.getCurrentTransaction().begin();
822
823 if ((vector = handleTable(key, session)) != null) {
824 try {
825 session.acquireLock(vector, MAX_WAIT_TIME);
826 vector.remove(handle);
827 session.updateObject(vector);
828 } catch (Exception err) {
829 throw new PersistenceException("Error in removeMessageHandle " +
830 err.toString());
831 }
832 } else {
833 throw new PersistenceException("Error in removeMessageHandle " +
834 "Failed to get the handle table for " + key);
835 }
836
837 session.getCurrentTransaction().commit();
838 PMDSessionManager.instance().destroySession();
839 } catch (PersistenceException pe) {
840 throw pe;
841 } catch (Exception err) {
842 throw new PersistenceException("Error in removeMessageHandle " +
843 err.toString());
844 }
845 }
846
847 // implementation of PersistenceAdapter.getMessageHandles
848 public synchronized Vector getMessageHandles(Connection connection,
849 JmsDestination destination, String name)
850 throws PersistenceException {
851 Vector result = new Vector();
852
853 try {
854 PMDVector vector;
855 SessionIfc session = getSession();
856 String key = getHandlesRootName(destination, name);
857
858
859 session.getCurrentTransaction().begin();
860
861 if ((vector = handleTable(key, session)) != null) {
862 try {
863 session.acquireLock(vector, MAX_WAIT_TIME);
864
865 Enumeration handles = vector.elements();
866 while (handles.hasMoreElements()) {
867 PersistentMessageHandle handle =
868 (PersistentMessageHandle) handles.nextElement();
869 result.addElement(handle.clone());
870 }
871 } catch (Exception err) {
872 throw new PersistenceException("Error in getMessageHandles " +
873 err.toString());
874 }
875 }
876
877 session.getCurrentTransaction().commit();
878 PMDSessionManager.instance().destroySession();
879 } catch (PersistenceException pe) {
880 throw pe;
881 } catch (Exception err) {
882 throw new PersistenceException("Error in getMessageHandles " +
883 err.toString());
884 }
885 return result;
886 }
887
888 // implementation of PersistenceAdapter.addDurableConsumer
889 public synchronized void addDurableConsumer(Connection connection,
890 String topic, String consumer)
891 throws PersistenceException {
892
893 try {
894 PMDVector vector;
895 SessionIfc session = getSession();
896
897 session.getCurrentTransaction().begin();
898
899 if ((vector = destinationTable(session)) != null) {
900 try {
901 session.acquireLock(vector, MAX_WAIT_TIME);
902 String target = "@" + consumer;
903
904 boolean found = false;
905 Enumeration entries = vector.elements();
906 while (entries.hasMoreElements()) {
907 PersistentString entry = (PersistentString) entries.nextElement();
908 if (entry.toString().endsWith(target)) {
909 found = true;
910 break;
911 }
912 }
913
914 String key = null;
915 if (!found) {
916 // add the target and also create a new table
917 // to hold handles for this consumer
918 vector.addElement(new PersistentString(TOPIC + topic + target));
919 session.updateObject(vector);
920
921 key = getHandlesRootName(consumer);
922 PMDVector handles =
923 (PMDVector) session.getCollectionManager().createVector();
924 session.createObject(handles);
925 session.bind(key, handles);
926 } else {
927 throw new PersistenceException("Error in addDurableConsumer " +
928 consumer + " already exists.");
929 }
930 } catch (Exception err) {
931 throw new PersistenceException("Error in addDurableConsumer " +
932 err.toString());
933 }
934 } else {
935 throw new PersistenceException("Error in addDurableConsumer " +
936 "Failed to get the destination table.");
937 }
938
939 session.getCurrentTransaction().commit();
940 PMDSessionManager.instance().destroySession();
941 } catch (PersistenceException pe) {
942 throw pe;
943 } catch (Exception err) {
944 throw new PersistenceException("Error in addDurableConsumer " +
945 err.toString());
946 }
947 }
948
949 // implementation of PersistenceAdapter.removeDurableConsumer
950 public synchronized void removeDurableConsumer(Connection connection,
951 String consumer)
952 throws PersistenceException {
953
954 try {
955 PMDVector vector;
956 SessionIfc session = getSession();
957
958 session.getCurrentTransaction().begin();
959
960 if ((vector = destinationTable(session)) != null) {
961 try {
962 session.acquireLock(vector, MAX_WAIT_TIME);
963 String target = "@" + consumer;
964
965 boolean found = false;
966 PersistentString entry = null;
967 Enumeration entries = vector.elements();
968 while (entries.hasMoreElements()) {
969 entry = (PersistentString) entries.nextElement();
970 if (entry.toString().endsWith(target)) {
971 vector.remove(entry);
972 found = true;
973 break;
974 }
975 }
976
977 String key = null;
978 if (found) {
979 // add the target and also create a new table
980 // to hold handles for this consumer
981 vector.removeElement(entry);
982 session.updateObject(vector);
983
984 // unbind the table (i.e delete it)
985 key = getHandlesRootName(consumer);
986 session.unbind(key);
987 } else {
988 throw new PersistenceException("Error in removeDurableConsumer " +
989 "Cannot find consumer with name " + consumer);
990 }
991 } catch (Exception err) {
992 throw new PersistenceException("Error in removeDurableConsumer " +
993 err.toString());
994 }
995 } else {
996 throw new PersistenceException("Error in removeDurableConsumer " +
997 "Cannot get access to the destination table");
998 }
999
1000 session.getCurrentTransaction().commit();
1001 PMDSessionManager.instance().destroySession();
1002 } catch (PersistenceException pe) {
1003 throw pe;
1004 } catch (Exception err) {
1005 throw new PersistenceException("Error in removeDurableConsumer " +
1006 err.toString());
1007 }
1008 }
1009
1010 // implementation of PersistenceAdapter.durableConsumerExists
1011 public synchronized boolean durableConsumerExists(Connection connection,
1012 String name)
1013 throws PersistenceException {
1014 boolean exists = false;
1015
1016 try {
1017 PMDVector vector;
1018 SessionIfc session = getSession();
1019
1020 session.getCurrentTransaction().begin();
1021
1022 if ((vector = destinationTable(session)) != null) {
1023 try {
1024 session.acquireLock(vector, MAX_WAIT_TIME);
1025 String target = "@" + name;
1026
1027 Enumeration entries = vector.elements();
1028 while (entries.hasMoreElements()) {
1029 PersistentString entry = (PersistentString) entries.nextElement();
1030 if (entry.toString().endsWith(target)) {
1031 exists = true;
1032 break;
1033 }
1034 }
1035 } catch (Exception err) {
1036 throw new PersistenceException("Error in durableConsumerExists " +
1037 err.toString());
1038 }
1039 } else {
1040 throw new PersistenceException("Error in durableConsumerExists " +
1041 "Cannot get access to the destinationtable.");
1042 }
1043
1044 session.getCurrentTransaction().commit();
1045 PMDSessionManager.instance().destroySession();
1046 } catch (PersistenceException pe) {
1047 throw pe;
1048 } catch (Exception err) {
1049 throw new PersistenceException("Error in durableConsumerExists " +
1050 err.toString());
1051 }
1052 return exists;
1053 }
1054
1055 // implementation of PersistenceAdapter.getDurableConsumers
1056 public synchronized Enumeration getDurableConsumers(Connection connection,
1057 String topic)
1058 throws PersistenceException {
1059 Vector consumers = new Vector();
1060
1061 try {
1062 PMDVector vector;
1063 SessionIfc session = getSession();
1064
1065 session.getCurrentTransaction().begin();
1066
1067 if ((vector = destinationTable(session)) != null) {
1068 try {
1069 session.acquireLock(vector, MAX_WAIT_TIME);
1070 String target = TOPIC + topic + "@";
1071
1072 Enumeration entries = vector.elements();
1073 while (entries.hasMoreElements()) {
1074 PersistentString entry =
1075 (PersistentString) entries.nextElement();
1076 if (entry.toString().startsWith(target)) {
1077 consumers.addElement(
1078 entry.toString().substring(target.length()));
1079 }
1080 }
1081 } catch (Exception err) {
1082 throw new PersistenceException("Error in getDurableConsumers " +
1083 err.toString());
1084 }
1085 } else {
1086 throw new PersistenceException("Error in getDurableConsumers " +
1087 "Failed to get access to the destination table.");
1088 }
1089
1090 session.getCurrentTransaction().commit();
1091 PMDSessionManager.instance().destroySession();
1092 } catch (PersistenceException pe) {
1093 throw pe;
1094 } catch (Exception err) {
1095 throw new PersistenceException("Error in getDurableConsumers " +
1096 err.toString());
1097 }
1098 return consumers.elements();
1099 }
1100
1101 // implementation of PersistenceAdapter.getAllDurableConsumers
1102 public HashMap getAllDurableConsumers(Connection connection)
1103 throws PersistenceException {
1104 HashMap consumers = new HashMap();
1105
1106 try {
1107 PMDVector vector;
1108 SessionIfc session = getSession();
1109
1110 session.getCurrentTransaction().begin();
1111
1112 if ((vector = destinationTable(session)) != null) {
1113 try {
1114 session.acquireLock(vector, MAX_WAIT_TIME);
1115
1116 Enumeration entries = vector.elements();
1117 while (entries.hasMoreElements()) {
1118 PersistentString entry =
1119 (PersistentString) entries.nextElement();
1120 String temp = entry.toString().substring(TOPIC.length());
1121 int index = temp.indexOf("@");
1122 if (!(entry.toString().startsWith(TOPIC)) ||
1123 (index == -1)) {
1124 // this is not a durable consumer so continue
1125 continue;
1126 }
1127
1128 // we have a durable consumer
1129 consumers.put(temp.substring(index + 1),
1130 temp.substring(0, index));
1131 }
1132 } catch (Exception err) {
1133 throw new PersistenceException("Error in getAllDurableConsumers " +
1134 err.toString());
1135 }
1136 } else {
1137 throw new PersistenceException("Error in getAllDurableConsumers " +
1138 "Failed to get access to the destination table");
1139 }
1140
1141 session.getCurrentTransaction().commit();
1142 PMDSessionManager.instance().destroySession();
1143 } catch (PersistenceException pe) {
1144 throw pe;
1145 } catch (Exception err) {
1146 throw new PersistenceException("Error in getAllDurableConsumers " +
1147 err.toString());
1148 }
1149 return consumers;
1150 }
1151
1152 // implementation of PersistenceAdapter.addDestination
1153 public synchronized void addDestination(Connection connection,
1154 String name, boolean queue)
1155 throws PersistenceException {
1156
1157 try {
1158 PMDVector vector;
1159 SessionIfc session = getSession();
1160
1161 session.getCurrentTransaction().begin();
1162
1163 if ((vector = destinationTable(session)) != null) {
1164 try {
1165 session.acquireLock(vector, MAX_WAIT_TIME);
1166 String target;
1167 if (queue) {
1168 target = QUEUE + name;
1169 } else {
1170 target = TOPIC + name;
1171 }
1172 boolean found = false;
1173 Enumeration entries = vector.elements();
1174 while (entries.hasMoreElements()) {
1175 PersistentString entry = (PersistentString) entries.nextElement();
1176 if (entry.toString().equals(target)) {
1177 found = true;
1178 break;
1179 }
1180 }
1181
1182 String key = null;
1183 if (!found) {
1184 // add the target and also create a new table
1185 // to hold handles for this consumer
1186 vector.addElement(new PersistentString(target));
1187 session.updateObject(vector);
1188
1189 // if it is a queue then we also need to construct
1190 // a handles table
1191 if (queue) {
1192 key = getHandlesRootName(name);
1193 PMDVector handles =
1194 (PMDVector) session.getCollectionManager().createVector();
1195 session.createObject(handles);
1196 session.bind(key, handles);
1197 }
1198 }
1199 } catch (Exception err) {
1200 throw new PersistenceException("Error in addDestination " +
1201 err.toString());
1202 }
1203 } else {
1204 throw new PersistenceException("Error in addDestination " +
1205 "Failed to get access to destination table");
1206 }
1207
1208 session.getCurrentTransaction().commit();
1209 PMDSessionManager.instance().destroySession();
1210 } catch (PersistenceException pe) {
1211 throw pe;
1212 } catch (Exception err) {
1213 throw new PersistenceException("Error in addDestination " +
1214 err.toString());
1215 }
1216 }
1217
1218 // implementation of PersistenceAdapter.removeDestination
1219 public synchronized void removeDestination(Connection connection,
1220 String name)
1221 throws PersistenceException {
1222 try {
1223 PMDVector vector;
1224 SessionIfc session = getSession();
1225
1226 session.getCurrentTransaction().begin();
1227
1228 if ((vector = destinationTable(session)) != null) {
1229 try {
1230 session.acquireLock(vector, MAX_WAIT_TIME);
1231
1232 // this will remove the destination and all registered
1233 // consumers.
1234 Vector to_delete = new Vector();
1235 Enumeration entries = vector.elements();
1236 while (entries.hasMoreElements()) {
1237 PersistentString wrapped_entry =
1238 (PersistentString) entries.nextElement();
1239 String entry = wrapped_entry.toString();
1240
1241 // now the destination name must appear before
1242 // the '.' separator
1243 int name_idx = entry.indexOf("@");
1244 int dest_idx = entry.indexOf(name);
1245
1246 if (entry.substring(TOPIC.length()).equals(name)) {
1247 // we have found the actual destination entry
1248 // Firstly mark it for deletion and then if it is a queue
1249 // unbind the consumer state
1250 to_delete.addElement(wrapped_entry);
1251 if (entry.startsWith(QUEUE)) {
1252 session.unbind(getHandlesRootName(name));
1253 }
1254 } else if ((name_idx >= 0) &&
1255 (dest_idx >= 0) &&
1256 (dest_idx < name_idx)) {
1257 // we have located an entry which describes a
1258 // durable consumer for a topic
1259 String consumer = entry.substring(name_idx + 1);
1260 to_delete.addElement(wrapped_entry);
1261 session.unbind(getHandlesRootName(consumer));
1262 }
1263 }
1264
1265 // now we need to go through and process the to_delete
1266 // entries
1267 Enumeration elements = to_delete.elements();
1268 while (elements.hasMoreElements()) {
1269 vector.remove((PersistentString) elements.nextElement());
1270 }
1271
1272 // update the vector object
1273 session.updateObject(vector);
1274 } catch (Exception err) {
1275 throw new PersistenceException("Error in removeDestination " +
1276 err.toString());
1277 }
1278 } else {
1279 throw new PersistenceException("Error in removeDestination " +
1280 "Failed to get access to the destination table.");
1281 }
1282
1283 session.getCurrentTransaction().commit();
1284 PMDSessionManager.instance().destroySession();
1285 } catch (PersistenceException pe) {
1286 throw pe;
1287 } catch (Exception err) {
1288 throw new PersistenceException("Error in addDestination " +
1289 err.toString());
1290 }
1291 }
1292
1293 // implementation of PersistenceAdapter.checkDestination
1294 public boolean checkDestination(Connection connection, String name)
1295 throws PersistenceException {
1296 boolean success = false;
1297
1298 try {
1299 PMDVector vector;
1300 SessionIfc session = getSession();
1301
1302 session.getCurrentTransaction().begin();
1303
1304 if ((vector = destinationTable(session)) != null) {
1305 try {
1306 session.acquireLock(vector, MAX_WAIT_TIME);
1307
1308 // this will remove the destination and all registered
1309 // consumers.
1310 Vector to_delete = new Vector();
1311 Enumeration entries = vector.elements();
1312 while (entries.hasMoreElements()) {
1313 PersistentString entry =
1314 (PersistentString) entries.nextElement();
1315
1316 // check that it is the specified destination
1317 if (entry.toString().substring(
1318 TOPIC.length()).equals(name)) {
1319 success = true;
1320 break;
1321 }
1322 }
1323 } catch (Exception err) {
1324 throw new PersistenceException("Error in checkDestination " +
1325 err.toString());
1326 }
1327 } else {
1328 throw new PersistenceException("Error in checkDestination " +
1329 "Failed to get access to destination table.");
1330 }
1331
1332 session.getCurrentTransaction().abort();
1333 PMDSessionManager.instance().destroySession();
1334 } catch (PersistenceException pe) {
1335 throw pe;
1336 } catch (Exception err) {
1337 throw new PersistenceException("Error in checkDestination " +
1338 err.toString());
1339 }
1340 return success;
1341 }
1342
1343 // implementation of PersistenceAdapter.getAllDestinations
1344 public synchronized Enumeration getAllDestinations(Connection connection)
1345 throws PersistenceException {
1346 Vector destinations = new Vector();
1347
1348 try {
1349 PMDVector vector;
1350 SessionIfc session = getSession();
1351
1352 session.getCurrentTransaction().begin();
1353
1354 if ((vector = destinationTable(session)) != null) {
1355 try {
1356 session.acquireLock(vector, MAX_WAIT_TIME);
1357
1358 // this will remove the destination and all registered
1359 // consumers.
1360 Vector to_delete = new Vector();
1361 Enumeration entries = vector.elements();
1362 while (entries.hasMoreElements()) {
1363 PersistentString entry =
1364 (PersistentString) entries.nextElement();
1365 String dest = entry.toString();
1366 // check that it is the specified destination
1367 if (dest.indexOf("@") == -1) {
1368 if (dest.startsWith(QUEUE)) {
1369 destinations.addElement(
1370 new JmsQueue(dest.substring(QUEUE.length())));
1371 } else if (dest.startsWith(TOPIC)) {
1372 destinations.addElement(
1373 new JmsTopic(dest.substring(TOPIC.length())));
1374 }
1375 }
1376 }
1377 } catch (Exception err) {
1378 throw new PersistenceException("Error in checkDestination " +
1379 err.toString());
1380 }
1381 } else {
1382 throw new PersistenceException("Error in checkDestination " +
1383 "Failed to get access to the destination table.");
1384 }
1385
1386 session.getCurrentTransaction().abort();
1387 PMDSessionManager.instance().destroySession();
1388 } catch (PersistenceException pe) {
1389 throw pe;
1390 } catch (Exception err) {
1391 throw new PersistenceException("Error in checkDestination " +
1392 err.toString());
1393 }
1394
1395 return destinations.elements();
1396 }
1397
1398 // implementation of PersistenceAdapter.getQueueMessageCount
1399 public synchronized int getQueueMessageCount(Connection connection,
1400 String queue)
1401 throws PersistenceException {
1402 int count = -1;
1403
1404 try {
1405 PMDVector vector;
1406 SessionIfc session = getSession();
1407 String key = getHandlesRootName(queue);
1408
1409
1410 session.getCurrentTransaction().begin();
1411
1412 if ((vector = handleTable(key, session)) != null) {
1413 try {
1414 session.acquireLock(vector, MAX_WAIT_TIME);
1415 count = vector.size();
1416 } catch (Exception err) {
1417 throw new PersistenceException("Error in getQueueMessageCount " +
1418 err.toString());
1419 }
1420 } else {
1421 throw new PersistenceException("Error in getQueueMessageCount " +
1422 "Failed to get access to queue " + queue);
1423 }
1424 session.getCurrentTransaction().abort();
1425 PMDSessionManager.instance().destroySession();
1426 } catch (PersistenceException pe) {
1427 throw pe;
1428 } catch (Exception err) {
1429 throw new PersistenceException("Error in getQueueMessageCount " +
1430 err.toString());
1431 }
1432
1433 return count;
1434 }
1435
1436 // implementation of PersistenceAdapter.getQueueMessageCount
1437 public synchronized int getDurableConsumerMessageCount(Connection connection,
1438 String topic, String name)
1439 throws PersistenceException {
1440 int count = -1;
1441
1442 try {
1443 PMDVector vector;
1444 SessionIfc session = getSession();
1445 String key = getHandlesRootName(name);
1446
1447
1448 session.getCurrentTransaction().begin();
1449
1450 if ((vector = handleTable(key, session)) != null) {
1451 try {
1452 session.acquireLock(vector, MAX_WAIT_TIME);
1453 count = vector.size();
1454 } catch (Exception err) {
1455 throw new PersistenceException("Error in getDurableConsumerMessageCount " +
1456 err.toString());
1457 }
1458 } else {
1459 throw new PersistenceException("Error in getDurableConsumerMessageCount " +
1460 "Cannot access table for " + topic + " : " + name);
1461 }
1462
1463 session.getCurrentTransaction().abort();
1464 PMDSessionManager.instance().destroySession();
1465 } catch (PersistenceException pe) {
1466 throw pe;
1467 } catch (Exception err) {
1468 throw new PersistenceException("Error in getDurableConsumerMessageCount " +
1469 err.toString());
1470 }
1471
1472 return count;
1473 }
1474
1475 // implementation of PersistenceAdapter.getQueueMessageCount
1476 public synchronized void removeExpiredMessages(Connection connection)
1477 throws PersistenceException {
1478
1479 SessionIfc session = null;
1480 try {
1481 PMDVector vector;
1482 PMDHashMap map;
1483 session = getSession();
1484
1485 session.getCurrentTransaction().begin();
1486 long now = System.currentTimeMillis();
1487
1488 if ((map = messageTable(session)) != null) {
1489 try {
1490 session.acquireLock(map, MAX_WAIT_TIME);
1491 Enumeration iter = map.elements();
1492 Vector to_remove = new Vector();
1493
1494 // collect a list of messages that have expired so that
1495 // they can be deleted later
1496 while (iter.hasMoreElements()) {
1497 PMDHandle handle = (PMDHandle) iter.nextElement();
1498 PersistentMessage msg = (PersistentMessage) handle.resolve();
1499 if ((msg.getExpiryTime() != 0) &&
1500 (msg.getExpiryTime() <= now)) {
1501 session.deleteObject(msg);
1502 to_remove.add(msg.getMessage().getJMSMessageID());
1503 }
1504 }
1505
1506 // delete the expired messages
1507 while (to_remove.size() > 0) {
1508 map.remove(to_remove.remove(0));
1509 }
1510 session.updateObject(map);
1511 } catch (Exception err) {
1512 throw new PersistenceException("Error in removeExpiredMessages " +
1513 err.toString());
1514 }
1515
1516 // now we need to go through all the handle tables and
1517 // remove expired messages. Very long and tedious
1518 if ((vector = destinationTable(session)) != null) {
1519 try {
1520 session.acquireLock(vector, MAX_WAIT_TIME);
1521 Enumeration entries = vector.elements();
1522 Vector to_remove = new Vector();
1523
1524 while (entries.hasMoreElements()) {
1525 to_remove.clear();
1526 PersistentString entry = (PersistentString) entries.nextElement();
1527 String name = getHandlesRootNameFromDestination(
1528 entry.toString());
1529 if (name == null) {
1530 continue;
1531 }
1532
1533 // retrieve the handle tbale based on the name
1534 PMDVector handles_vector = handleTable(name, session);
1535 if (handles_vector == null) {
1536 continue;
1537 }
1538
1539 // we have the handle table. Now iterate over all the
1540 // messages and removed expired messages
1541 Enumeration handles = handles_vector.elements();
1542 while (handles.hasMoreElements()) {
1543 PersistentMessageHandle handle =
1544 (PersistentMessageHandle) handles.nextElement();
1545 if ((handle.getExpiryTime() != 0) &&
1546 (handle.getExpiryTime() <= now)) {
1547 to_remove.add(handle);
1548 }
1549 }
1550
1551 // now remove the handles
1552 while (to_remove.size() > 0) {
1553 handles_vector.remove(
1554 (PersistentMessageHandle) to_remove.remove(0));
1555 }
1556 session.updateObject(handles_vector);
1557 }
1558 } catch (Exception err) {
1559 throw new PersistenceException("Error in removeExpiredMessages " +
1560 err.toString());
1561 }
1562 } else {
1563 throw new PersistenceException("Error in removeExpiredMessages " +
1564 "Failed to get the message table");
1565 }
1566 }
1567 session.getCurrentTransaction().commit();
1568 PMDSessionManager.instance().destroySession();
1569 } catch (PersistenceException pe) {
1570 try {
1571 session.getCurrentTransaction().abort();
1572 } catch (Exception exception) {
1573 // ignore
1574 }
1575 throw pe;
1576 } catch (Exception err) {
1577 throw new PersistenceException("Error in removeExpiredMessages " +
1578 err.toString());
1579 }
1580 }
1581
1582 // implementation of PersistenceAdapter.removeExpiredMessageHandles
1583 public void removeExpiredMessageHandles(Connection connection,
1584 String consumer)
1585 throws PersistenceException {
1586
1587 // no operation
1588 }
1589
1590 // implementation of PersistenceAdapter.getQueueMessageCount
1591 public synchronized Vector getNonExpiredMessages(Connection connection,
1592 JmsDestination destination)
1593 throws PersistenceException {
1594 Vector result = new Vector();
1595
1596 SessionIfc session = null;
1597 try {
1598 PMDVector vector;
1599 session = getSession();
1600
1601 session.getCurrentTransaction().begin();
1602 long now = System.currentTimeMillis();
1603
1604 // now we need to go through all the handle tables and
1605 // retrieve messages which have not expired for the specified
1606 // destination
1607 if ((vector = destinationTable(session)) != null) {
1608 try {
1609 session.acquireLock(vector, MAX_WAIT_TIME);
1610 Enumeration entries = vector.elements();
1611 while (entries.hasMoreElements()) {
1612 PersistentString entry = (PersistentString) entries.nextElement();
1613
1614 // check to see if we are interested in this destination
1615 if (entry.toString().indexOf(destination.getName()) == -1) {
1616 continue;
1617 }
1618
1619 // attempt to retrieve the handle name table for the specified
1620 // destination,
1621 String name = getHandlesRootNameFromDestination(
1622 entry.toString());
1623 if (name == null) {
1624 continue;
1625 }
1626
1627 // retrieve the handle tbale based on the name
1628 PMDVector handles_vector = handleTable(name, session);
1629 if (handles_vector == null) {
1630 continue;
1631 }
1632
1633 // we have the handle table. Now iterate over all the
1634 // messages and removed expired messages
1635 Enumeration handles = handles_vector.elements();
1636 while (handles.hasMoreElements()) {
1637 PersistentMessageHandle handle =
1638 (PersistentMessageHandle) handles.nextElement();
1639 if ((handle.getExpiryTime() != 0) &&
1640 (handle.getExpiryTime() > now)) {
1641 result.add(handle);
1642 }
1643 }
1644 }
1645 } catch (Exception err) {
1646 throw new PersistenceException("Error in removeExpiredMessages " +
1647 err.toString());
1648 }
1649 } else {
1650 throw new PersistenceException("Error in removeExpiredMessages " +
1651 "The destination table does not exist");
1652 }
1653 session.getCurrentTransaction().commit();
1654 PMDSessionManager.instance().destroySession();
1655 } catch (PersistenceException pe) {
1656 try {
1657 session.getCurrentTransaction().abort();
1658 } catch (Exception exception) {
1659 // ignore
1660 }
1661 throw pe;
1662 } catch (Exception err) {
1663 throw new PersistenceException("Error in removeExpiredMessages " +
1664 err.toString());
1665 }
1666
1667 return result;
1668 }
1669
1670 // implementation of PersistenceAdapter.purgeMessages
1671 public synchronized int purgeMessages() {
1672 boolean errorSet = false;
1673 Vector keep = new Vector();
1674 int count = -1;
1675
1676 try {
1677 PMDHashMap map;
1678 PMDVector vector;
1679 SessionIfc session = getSession();
1680
1681 session.getCurrentTransaction().begin();
1682 long now = System.currentTimeMillis();
1683
1684 // now we need to go through all the handle tables and
1685 // get a unique list of unacked messages
1686 if ((vector = destinationTable(session)) != null) {
1687 try {
1688 session.acquireLock(vector, MAX_WAIT_TIME);
1689 Enumeration entries = vector.elements();
1690 while (entries.hasMoreElements()) {
1691 PersistentString entry = (PersistentString) entries.nextElement();
1692
1693 // attempt to retrieve the handle name table for the specified
1694 // destination,
1695 String name = getHandlesRootNameFromDestination(
1696 entry.toString());
1697 if (name == null) {
1698 continue;
1699 }
1700 // retrieve the handle table based on the name
1701 PMDVector handles_vector = handleTable(name, session);
1702 if (handles_vector == null) {
1703 continue;
1704 }
1705
1706 // we have the handle table. Now iterate over all the
1707 // messages and removed expired messages
1708 Enumeration handles = handles_vector.elements();
1709 while (handles.hasMoreElements()) {
1710 PersistentMessageHandle handle =
1711 (PersistentMessageHandle) handles.nextElement();
1712 String id = handle.getMessageId().getId();
1713 if (!keep.contains(id)) {
1714 keep.add(id);
1715 }
1716 }
1717 }
1718
1719
1720 // now that we have a definitive list of messages we
1721 // need to remove messages that are not in the list
1722 if ((map = messageTable(session)) != null) {
1723 try {
1724 session.acquireLock(map, MAX_WAIT_TIME);
1725 Enumeration iter = map.keys();
1726 Vector to_remove = new Vector();
1727
1728 // collect a list of messages that have expired so that
1729 // they can be deleted later
1730 while (iter.hasMoreElements()) {
1731 String id = (String) iter.nextElement();
1732 if (!keep.contains(id)) {
1733 session.deleteObject((PersistentMessage)
1734 ((PMDHandle) map.get(id)).resolve());
1735 to_remove.add(id);
1736 }
1737 }
1738
1739 // delete the expired messages
1740 count = to_remove.size();
1741 while (to_remove.size() > 0) {
1742 map.remove(to_remove.remove(0));
1743 }
1744 session.updateObject(map);
1745 _log.info("GC removed " +
1746 count + " messages from database.");
1747 } catch (Exception exception) {
1748 errorSet = true;
1749 _log.error("Error in purgeMessages", exception);
1750 }
1751 } else {
1752 _log.error("Message table does not exist");
1753 errorSet = true;
1754 }
1755 } catch (Exception err) {
1756 errorSet = true;
1757 _log.error("Error in getNonExpiredMessages", err);
1758 }
1759 } else {
1760 // topic does not exists, may have been removed already.
1761 errorSet = true;
1762 }
1763
1764 if (!errorSet) {
1765 session.getCurrentTransaction().commit();
1766 } else {
1767 session.getCurrentTransaction().abort();
1768 }
1769 PMDSessionManager.instance().destroySession();
1770 } catch (FailedToDestroySessionException sessErr) {
1771 // Session not destroyed but message saved.
1772 _log.error("Failed to destroy session", sessErr);
1773 } catch (Exception err) {
1774 _log.error(err, err);
1775 }
1776
1777 return count;
1778 }
1779
1780 public void addUser(Connection connection, User user)
1781 throws PersistenceException {
1782 // unsupported
1783 }
1784
1785 public Enumeration getAllUsers(Connection connection)
1786 throws PersistenceException {
1787 // unsupported
1788 return new Vector().elements();
1789 }
1790
1791 public User getUser(Connection connection, User user)
1792 throws PersistenceException {
1793 // unsupported
1794 return null;
1795 }
1796
1797 public void removeUser(Connection connection, User user)
1798 throws PersistenceException {
1799 // unsupported
1800 }
1801
1802 public void updateUser(Connection connection, User user)
1803 throws PersistenceException {
1804 // unsupported
1805 }
1806
1807 // implementation of PersistenceAdapter.getConnection
1808 public Connection getConnection()
1809 throws PersistenceException {
1810 return _connection;
1811 }
1812
1813 // implementation of EventHandler.getHandle
1814 public HandleIfc getHandle() {
1815 return null;
1816 }
1817
1818 // implementation of EventHandler.handleEvent
1819 public void handleEvent(int event, Object callback, long time) {
1820 if (event == COLLECT_DATABASE_GARBAGE_EVENT) {
1821 // collect garbage now, but before doing so change the thread
1822 // priority to low.
1823 try {
1824 Thread.currentThread().setPriority(_gcThreadPriority);
1825 purgeMessages();
1826 } finally {
1827 Thread.currentThread().setPriority(Thread.NORM_PRIORITY);
1828 registerEvent();
1829 }
1830 }
1831 }
1832
1833 /***
1834 * Get the session from the session manager.
1835 *
1836 * @return SessionIfc The unique session for this thread.
1837 * @exception FailedToCreateSessionException internal error
1838 *
1839 */
1840 private SessionIfc getSession() throws FailedToCreateSessionException {
1841 return PMDSessionManager.instance().getSession();
1842 }
1843
1844 /***
1845 * Return the map where messages are stored.
1846 *
1847 * @param session - the session to use
1848 * @return PMDHashMap
1849 */
1850 private PMDHashMap messageTable(SessionIfc session) {
1851 return (PMDHashMap) session.lookup(MESSAGES);
1852 }
1853
1854 /***
1855 * Return the vector used to store destinations and also the
1856 * registered dursble consumers.
1857 *
1858 * @param session - the session to use
1859 * @return PMDHashMap
1860 */
1861 private PMDVector destinationTable(SessionIfc session) {
1862 return (PMDVector) session.lookup(DESTINATIONS);
1863 }
1864
1865 /***
1866 * Return the message handle table for the specified destination and
1867 * and name.
1868 * <p>
1869 * Assume this is only called from within a transaction
1870 *
1871 * @param key - the key to the consumer
1872 * @param session - the session object.
1873 * @return PMDHashMap the root object if it exists or null.
1874 *
1875 */
1876 private PMDVector handleTable(String key, SessionIfc session) {
1877 return (PMDVector) session.lookup(key);
1878 }
1879
1880 /***
1881 * Return a generated root name to store consumer handles using the
1882 * destination and name
1883 *
1884 * @param destination - the destination
1885 * @param name - the consumer name
1886 * @return String - the root name
1887 */
1888 private String getHandlesRootName(JmsDestination destination, String name) {
1889 if (destination instanceof JmsQueue) {
1890 return getHandlesRootName(destination.getName());
1891 } else {
1892 return getHandlesRootName(name);
1893 }
1894 }
1895
1896 /***
1897 * Return the handles root name given an internal string, which is an
1898 * entry from the destination table.
1899 * <p>
1900 * The format of the entries are QUEUE_<queue_name> for queues
1901 * or TOPIC_<topic_name>.<consumer_name> for topics.
1902 *
1903 * @param entry - the destination table entry
1904 * @return String - the associated handle table name
1905 */
1906 private String getHandlesRootNameFromDestination(String entry) {
1907 String name = null;
1908
1909 if (entry.startsWith(QUEUE)) {
1910 name = HANDLES + "@" + entry.substring(QUEUE.length());
1911 } else if (entry.startsWith(TOPIC)) {
1912 int index = entry.indexOf("@");
1913 if (index != -1) {
1914 name = HANDLES + "@" + entry.substring(index + 1);
1915 }
1916 }
1917
1918 return name;
1919 }
1920
1921 /***
1922 * Return a generated root name to store consumer handles using the
1923 * destination and name. The destination is always the name of a queue
1924 * destination
1925 *
1926 * @param queue - the name of the queue destination
1927 * @return String - the root name
1928 */
1929 private String getHandlesRootName(String name) {
1930 return HANDLES + "@" + name;
1931 }
1932
1933 /***
1934 * Strip the "ID:" prefix from the string, and increment the long
1935 * by one, then add the prefix again.
1936 *
1937 * @param st The string to increment.
1938 * @return String The string incremented by 1.
1939 *
1940 */
1941 private String increment(String st) {
1942 String newId = null;
1943
1944 try {
1945 newId = "ID:" + (Long.parseLong(st.substring(3)) + 1);
1946 } catch (NumberFormatException err) {
1947 _log.error("Invalid id: " + st);
1948 System.exit(-1);
1949 }
1950 return newId;
1951 }
1952
1953 /***
1954 * Register an event to collect and remove processed messages with the
1955 * {@link BasicEventManager}
1956 */
1957 private void registerEvent() {
1958 try {
1959 BasicEventManager.instance().registerEventRelative(
1960 new Event(COLLECT_DATABASE_GARBAGE_EVENT, this, null),
1961 _gcInterval);
1962 } catch (IllegalEventDefinedException exception) {
1963 _log.error("registerEvent failed", exception);
1964 }
1965 }
1966 }
1967
1968
1969 /***
1970 * A simple wrapper to store long values in the database.
1971 *
1972 */
1973 class PMDLongInteger
1974 extends PersistentObject
1975 implements Externalizable {
1976
1977 /***
1978 * The actual value
1979 */
1980 private long value_;
1981
1982
1983 /***
1984 * Used for serialization
1985 */
1986 static final long serialVersionUID = 1;
1987
1988 public PMDLongInteger() {
1989 }
1990
1991 public PMDLongInteger(long value) {
1992 value_ = value;
1993 }
1994
1995 public long get() {
1996 return value_;
1997 }
1998
1999 // implementation of Externalizable.writeExternal
2000 public void writeExternal(ObjectOutput stream)
2001 throws IOException {
2002 stream.writeLong(serialVersionUID);
2003 stream.writeLong(value_);
2004 super.writeExternal(stream);
2005 }
2006
2007 // implementation of Externalizable.writeExternal
2008 public void readExternal(ObjectInput stream)
2009 throws IOException, ClassNotFoundException {
2010 long version = stream.readLong();
2011 if (version == serialVersionUID) {
2012 value_ = stream.readLong();
2013 super.readExternal(stream);
2014 } else {
2015 throw new IOException("PMDLongInteger with version " +
2016 version + " is not supported.");
2017 }
2018 }
2019
2020 } //-- ObjectAdapter
This page was automatically generated by Maven