View Javadoc

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  package org.exolab.jms.tools.migration.proxy;
44  
45  import java.sql.Connection;
46  import java.sql.PreparedStatement;
47  import java.sql.ResultSet;
48  import java.sql.SQLException;
49  import java.util.ArrayList;
50  import java.util.HashMap;
51  import java.util.Iterator;
52  import java.util.List;
53  
54  import javax.jms.JMSException;
55  
56  import org.exolab.jms.client.JmsDestination;
57  import org.exolab.jms.client.JmsQueue;
58  import org.exolab.jms.client.JmsTopic;
59  import org.exolab.jms.persistence.SQLHelper;
60  import org.exolab.jms.persistence.PersistenceException;
61  import org.exolab.jms.tools.migration.Store;
62  import org.exolab.jms.tools.migration.StoreIterator;
63  import org.exolab.jms.tools.migration.IteratorAdapter;
64  
65  
66  /***
67   * Provides persistency for {@link JmsDestination} instances.
68   *
69   * @version     $Revision: 1.2 $ $Date: 2005/10/20 14:07:03 $
70   * @author      <a href="mailto:tma@netspace.net.au">Tim Anderson</a>
71   */
72  public class DestinationStore implements Store, DBConstants {
73  
74      /***
75       * The database conection.
76       */
77      private final Connection _connection;
78  
79      /***
80       * Map of destinations keyed on name.
81       */
82      private final HashMap _destinations = new HashMap();
83  
84      /***
85       * Map of destinations keyed on identity.
86       */
87      private final HashMap _ids = new HashMap();
88  
89      /***
90       * The seed to generate identifiers for destination instances.
91       */
92      private long _seed = 0;
93  
94  
95      /***
96       * Construct a new <code>DestinationStore</code>.
97       *
98       * @param connection the database connection
99       * @throws PersistenceException for any persistence error
100      */
101     public DestinationStore(Connection connection) throws PersistenceException {
102         _connection = connection;
103         load();
104     }
105 
106     /***
107      * Export the destinations.
108      *
109      * @return an iterator over the collection
110      * @throws JMSException         for any JMS error
111      * @throws PersistenceException for any persistence error
112      */
113     public StoreIterator exportCollection() throws JMSException,
114             PersistenceException {
115         List destinations = getDestinations();
116         return new IteratorAdapter(destinations.iterator());
117     }
118 
119     /***
120      * Import destinations into the store.
121      *
122      * @param iterator an iterator over the collection
123      * @throws JMSException         for any JMS error
124      * @throws PersistenceException for any persistence error
125      */
126     public void importCollection(StoreIterator iterator) throws JMSException,
127             PersistenceException {
128         while (iterator.hasNext()) {
129             JmsDestination destination = (JmsDestination) iterator.next();
130             add(destination);
131         }
132     }
133 
134     /***
135      * Returns the number of elements in the collection.
136      *
137      * @return the number of elements in the collection
138      */
139     public int size() throws PersistenceException {
140         return _destinations.size();
141     }
142 
143     /***
144      * Add a new destination to the database, assigning it a unique identity.
145      * 
146      * @param destination the destination to add
147      * @throws PersistenceException for any persistence error
148      */
149     public synchronized void add(JmsDestination destination) 
150         throws PersistenceException {
151 
152         PreparedStatement insert = null;
153         try {
154             long destinationId = ++_seed;
155             String name = destination.getName();
156             boolean isQueue = (destination instanceof JmsQueue);
157 
158             insert = _connection.prepareStatement(
159                 "insert into " + DESTINATION_TABLE + " values (?, ?, ?)");
160             insert.setLong(1, destinationId);
161             insert.setString(2, name);
162             insert.setBoolean(3, isQueue);
163             insert.executeUpdate();
164             cache(destination, destinationId);
165         } catch (SQLException exception) {
166             throw new PersistenceException("Failed to add destination="
167                                            + destination.getName(),
168                                            exception);
169         } finally {
170             SQLHelper.close(insert);
171         }
172     }
173 
174     /***
175      * Returns the destination associated with the specified identifier.
176      * 
177      * @param destinationId the destination identifier
178      * @return the destination, or <code>null</code> if no corresponding
179      * destination exists
180      */
181     public synchronized JmsDestination get(long destinationId) {
182         Pair pair = (Pair) _ids.get(new Long(destinationId));
183         return (pair != null) ? pair.destination : null;
184     }
185 
186     /***
187      * Returns the destination identifier for a given destination.
188      * 
189      * @param destination the destination
190      * @return the destination identifier, or <code>-1</code> if no 
191      * corresponding destination exists
192      */
193     public synchronized long getId(JmsDestination destination) {
194         Pair pair = (Pair) _destinations.get(destination.getName());
195         return (pair != null) ? pair.destinationId : -1;
196     }
197 
198     /***
199      * Returns the list of destination objects.
200      * 
201      * @return a list of <code>javax.jms.Destination</code> instances
202      */
203     public synchronized List getDestinations() {
204         List result = new ArrayList(_destinations.size());
205 
206         Iterator iterator = _destinations.values().iterator();
207         while (iterator.hasNext()) {
208             Pair pair = (Pair) iterator.next();
209             result.add(pair.destination);
210         }
211             
212         return result;
213     }
214 
215     /***
216      * Load all destinations.
217      *
218      * @throws PersistenceException for any persistence error
219      */
220     protected void load() throws PersistenceException {
221         PreparedStatement select = null;
222         ResultSet set = null;
223         try {
224             select = _connection.prepareStatement(
225                     "select * from " + DESTINATION_TABLE);
226 
227             set = select.executeQuery();
228             while (set.next()) {
229                 long destinationId = set.getLong("destination_id");
230                 String name = set.getString("name");
231                 boolean isQueue = set.getBoolean("is_queue");
232                 JmsDestination destination = (isQueue) 
233                     ? (JmsDestination) new JmsQueue(name) 
234                     : (JmsDestination) new JmsTopic(name);
235                 destination.setPersistent(true);
236                 cache(destination, destinationId);
237             }
238         } catch (SQLException exception) {
239             throw new PersistenceException("FGailed to load destinations",
240                                            exception);
241         } finally {
242             SQLHelper.close(set);
243             SQLHelper.close(select);
244         }
245     }
246 
247     /***
248      * Cache a destination.
249      *
250      * @param destination the destination to cache
251      * @param destinationId the destination identity
252      */
253     private void cache(JmsDestination destination, long destinationId) {
254         Pair pair = new Pair(destination, destinationId);
255 
256         _destinations.put(destination.getName(), pair);
257         _ids.put(new Long(destinationId), pair);
258     }
259 
260     /***
261      * Helper class to hold the name and identity of a destination.
262      */
263     private static class Pair {
264 
265         public JmsDestination destination;
266 
267         public long destinationId;
268 
269         public Pair(JmsDestination destination, long destinationId) {
270             this.destination = destination;
271             this.destinationId = destinationId;
272         }      
273   
274     }
275 
276 }