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 2001-2003 (C) Exoffice Technologies Inc. All Rights Reserved. 42 * 43 * $Id: TopicDestinationCache.java,v 1.22 2003/10/21 14:41:24 tanderson Exp $ 44 * 45 * Date Author Changes 46 * 3/1/2001 jima Created 47 */ 48 package org.exolab.jms.messagemgr; 49 50 import java.sql.Connection; 51 import java.util.Iterator; 52 import java.util.List; 53 54 import javax.jms.DeliveryMode; 55 import javax.jms.JMSException; 56 import javax.transaction.TransactionManager; 57 58 import org.apache.commons.logging.Log; 59 import org.apache.commons.logging.LogFactory; 60 61 import org.exolab.jms.client.JmsDestination; 62 import org.exolab.jms.client.JmsTopic; 63 import org.exolab.jms.message.MessageHandle; 64 import org.exolab.jms.message.MessageImpl; 65 import org.exolab.jms.persistence.PersistenceException; 66 67 68 /*** 69 * A DestinationCache for Topics. This cache extends DestinationCache but does 70 * not actually hold a reference to the messages. Instead it forwards them on 71 * to registered consumers. 72 * <p> 73 * We may need to build the cache for clients that fail over to the new server 74 * so we should maintain a cache of at least persistent messages handles. This 75 * is something that needs to be considered. As for non-persistent messages well 76 * that is the penalty for using them. If you want to ensure that you get every 77 * message, even during failover then you best publsih them using persistent 78 * delivery mode. 79 * 80 * @version $Revision: 1.22 $ $Date: 2003/10/21 14:41:24 $ 81 * @author <a href="mailto:jima@exoffice.com">Jim Alateras</a> 82 **/ 83 public class TopicDestinationCache 84 extends DestinationCache { 85 86 /*** 87 * Underlying destination 88 */ 89 private JmsTopic _topic = null; 90 91 /*** 92 * The logger 93 */ 94 private static final Log _log = 95 LogFactory.getLog(TopicDestinationCache.class); 96 97 98 /*** 99 * Construct a message cache for a particular destination. This object 100 * does not cache any messages. 101 * 102 * @param destination - the destination that owns this cache 103 * @throws FailedToInitializeException 104 */ 105 TopicDestinationCache(JmsTopic destination) 106 throws FailedToInitializeException { 107 super(); 108 109 // don't need the local messages cache for the initial release, will need 110 // it for clustering 111 _topic = destination; 112 113 // call init on the base class 114 try { 115 init(); 116 } catch (FailedToInitializeException exception) { 117 // rethrow 118 throw exception; 119 } catch (Exception exception) { 120 throw new FailedToInitializeException( 121 "Failed to construct TopicDestinationCache " + 122 exception.toString()); 123 } 124 } 125 126 /*** 127 * Construct a message cache for a particular destination using the specified 128 * {@link Connection} to complete any database access. 129 * 130 * @param connection - the connection to use. 131 * @param destination - the destination that owns this cache 132 * @throws FailedToInitializeException 133 */ 134 TopicDestinationCache(Connection connection, JmsTopic destination) 135 throws FailedToInitializeException { 136 super(); 137 138 // don't need the local messages cache for the initial release, will need 139 // it for clustering 140 _topic = destination; 141 142 // call init on the base class 143 try { 144 init(connection); 145 } catch (FailedToInitializeException exception) { 146 // rethrow 147 throw exception; 148 } catch (Exception exception) { 149 throw new FailedToInitializeException( 150 "Failed to construct TopicDestinationCache " + 151 exception.toString()); 152 } 153 } 154 155 // implementation of DestinationCache.getDestination 156 public JmsDestination getDestination() { 157 return _topic; 158 } 159 160 // implementation of MessageMgr.messageAdded 161 public boolean messageAdded(JmsDestination destination, MessageImpl message) { 162 boolean processed = false; 163 164 if ((destination != null) && 165 (message != null)) { 166 // check that it is not already present before adding it. 167 if (destination.equals(_topic)) { 168 processed = notifyOnAddMessage(message); 169 // create a lease iff one is required and the message has actually 170 // been accepted by at least one endpoint 171 if (processed) { 172 checkMessageExpiry(message); 173 } 174 } 175 } 176 177 return processed; 178 } 179 180 // implementation of MessageMgr.messageRemoved 181 public void messageRemoved(JmsDestination destination, MessageImpl message) { 182 if ((destination != null) && 183 (message != null)) { 184 // call remove regardless whether it exists 185 if (destination.equals(_topic)) { 186 notifyOnRemoveMessage(message); 187 } 188 } 189 } 190 191 // implementation of MessageMgr.persistentMessageAdded 192 public boolean persistentMessageAdded(Connection connection, 193 JmsDestination destination, MessageImpl message) 194 throws PersistenceException { 195 boolean processed = false; 196 197 if ((destination != null) && 198 (message != null)) { 199 // check that it is not already present before adding it. 200 if (destination.equals(_topic)) { 201 processed = notifyOnAddPersistentMessage(connection, message); 202 203 // create a lease iff one is required and the message has actually 204 // been accepted by at least one endpoint 205 if (processed) { 206 checkMessageExpiry(message); 207 } 208 } 209 } 210 211 return processed; 212 } 213 214 // implementation of MessageMgr.persistentMessageRemoved 215 public void persistentMessageRemoved(Connection connection, 216 JmsDestination destination, MessageImpl message) 217 throws PersistenceException { 218 if ((destination != null) && 219 (message != null)) { 220 // call remove regardless whether it exists 221 if (destination.equals(_topic)) { 222 notifyOnRemovePersistentMessage(connection, message); 223 } 224 } 225 } 226 227 // implementation of DestinationCache.notifyOnAddMessage 228 boolean notifyOnAddMessage(MessageImpl message) { 229 boolean processed = true; 230 231 // process for all the active consumers. 232 Object[] iter = getConsumersByArray(); 233 for (int index = 0; index < iter.length; index++) { 234 DestinationCacheEventListener listener = 235 (DestinationCacheEventListener) iter[index]; 236 processed |= listener.messageAdded(message); 237 } 238 239 return processed; 240 } 241 242 // implementation of DestinationCache.notifyOnRemoveMessage 243 void notifyOnRemoveMessage(MessageImpl message) { 244 Object[] iter = getConsumersByArray(); 245 for (int index = 0; index < iter.length; index++) { 246 if (((DestinationCacheEventListener) 247 iter[index]).messageRemoved(message)) { 248 } 249 } 250 } 251 252 // implementation of DestinationCache.notifyOnAddPersistentMessage 253 boolean notifyOnAddPersistentMessage(Connection connection, 254 MessageImpl message) 255 throws PersistenceException { 256 boolean processed = true; 257 258 // This is not done in MessageMgr 259 // first let's create a persistent message handle for all registered 260 // durable consumers 261 //try { 262 // processed |= ConsumerManager.instance().persistentMessageAdded( 263 // connection, message); 264 //} catch (Exception exception) { 265 // throw new PersistenceException("Error in notifyOnAddPersistentMessage " + 266 // exception); 267 //} 268 269 // now send the message to all active durable and non-durable consumers 270 Object[] iter = getConsumersByArray(); 271 for (int index = 0; index < iter.length; index++) { 272 DestinationCacheEventListener listener = 273 (DestinationCacheEventListener) iter[index]; 274 processed |= listener.persistentMessageAdded(connection, message); 275 } 276 277 return processed; 278 } 279 280 // implementation of DestinationCache.notifyOnRemovePersistentMessage 281 void notifyOnRemovePersistentMessage(Connection connection, 282 MessageImpl message) 283 throws PersistenceException { 284 285 Object[] iter = getConsumersByArray(); 286 for (int index = 0; index < iter.length; index++) { 287 DestinationCacheEventListener listener = 288 (DestinationCacheEventListener) iter[index]; 289 // if the listener is of type {@link DurableConsumerEndpoint} then 290 // indicate that a persistentMessage has been removed. If the listener 291 // is a {@link TopicConsumerEndpoint} then indicatw that non- 292 // persistent message has been removed. 293 if (listener instanceof DurableConsumerEndpoint) { 294 listener.persistentMessageRemoved(connection, message); 295 } else if (listener instanceof TopicConsumerEndpoint) { 296 listener.messageRemoved(message); 297 } 298 } 299 300 // since it is a persistent message we need to send it 301 // to inactive durable consumers subscribing to the destination 302 try { 303 ConsumerManager.instance().persistentMessageRemoved(connection, 304 message); 305 } catch (Exception exception) { 306 _log.error("Error in notifyOnRemovePersistentMessage", 307 exception); 308 } 309 } 310 311 // override implementation of DestinationCache.registerConsumer 312 public boolean registerConsumer(ConsumerEndpoint consumer) { 313 314 boolean result = false; 315 316 // check to see that the consumer can actually subscribe to 317 // this destination 318 JmsTopic cdest = (JmsTopic) consumer.getDestination(); 319 JmsTopic ddest = (JmsTopic) getDestination(); 320 321 if (cdest.match(ddest)) { 322 if (!_consumers.contains(consumer)) { 323 _consumers.add(consumer); 324 consumer.setMaximumSize(this.getMaximumSize()); 325 result = true; 326 } 327 } 328 329 return result; 330 } 331 332 // implementation of DestinationCache.hasActiveConsumers 333 boolean hasActiveConsumers() { 334 return (_consumers.size() > 0); 335 } 336 337 // implementation of DestinationCache.getMessageCount 338 public int getMessageCount() { 339 return 0; 340 } 341 342 /*** 343 * Determines if this cache can be destroyed. 344 * A <code>TopicDestinationCache</code> can be destroyed if there 345 * are no active consumers. 346 * 347 * @return <code>true</code> if the cache can be destroyed, otherwise 348 * <code>false</code> 349 */ 350 public boolean canDestroy() { 351 return !hasActiveConsumers(); 352 } 353 354 // override Object.toString 355 public String toString() { 356 return _topic.toString(); 357 } 358 359 // override Object.hashCode 360 public int hashCode() { 361 return _topic.hashCode(); 362 } 363 364 /*** 365 * Resolve an expired message through its handle 366 * 367 * @param handle the expired message's handle 368 * @return the expired message. May be null. 369 */ 370 protected MessageImpl resolveExpiredMessage(MessageHandle handle) { 371 MessageImpl message = null; 372 373 if (handle.getConsumerName() != null) { 374 message = super.resolveExpiredMessage(handle); 375 } else { 376 // can't resolve the message through the handle 377 // Need to find the first consumer which has it. 378 // @todo - design flaw! 379 Iterator iterator = _consumers.iterator(); 380 while (iterator.hasNext()) { 381 ConsumerEndpoint endpoint = (ConsumerEndpoint) iterator.next(); 382 message = endpoint.getMessage(handle); 383 if (message != null) { 384 break; 385 } 386 } 387 } 388 return message; 389 } 390 391 } 392

This page was automatically generated by Maven