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 }