1 /*** 2 * 3 * Copyright 2004 Protique Ltd 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 **/ 18 package org.codehaus.activemq; 19 20 import org.codehaus.activemq.management.JMSProducerStatsImpl; 21 import org.codehaus.activemq.management.StatsCapable; 22 import org.codehaus.activemq.message.ActiveMQDestination; 23 import org.codehaus.activemq.util.IdGenerator; 24 25 import javax.jms.DeliveryMode; 26 import javax.jms.Destination; 27 import javax.jms.IllegalStateException; 28 import javax.jms.InvalidDestinationException; 29 import javax.jms.JMSException; 30 import javax.jms.Message; 31 import javax.jms.MessageFormatException; 32 import javax.jms.MessageProducer; 33 import javax.management.j2ee.statistics.Stats; 34 35 /*** 36 * A client uses a <CODE>MessageProducer</CODE> object to send messages to a 37 * destination. A <CODE>MessageProducer</CODE> object is created by passing a 38 * <CODE>Destination</CODE> object to a message-producer creation method 39 * supplied by a session. 40 * <P> 41 * <CODE>MessageProducer</CODE> is the parent interface for all message 42 * producers. 43 * <P> 44 * A client also has the option of creating a message producer without 45 * supplying a destination. In this case, a destination must be provided with 46 * every send operation. A typical use for this kind of message producer is to 47 * send replies to requests using the request's <CODE>JMSReplyTo</CODE> 48 * destination. 49 * <P> 50 * A client can specify a default delivery mode, priority, and time to live for 51 * messages sent by a message producer. It can also specify the delivery mode, 52 * priority, and time to live for an individual message. 53 * <P> 54 * A client can specify a time-to-live value in milliseconds for each message 55 * it sends. This value defines a message expiration time that is the sum of 56 * the message's time-to-live and the GMT when it is sent (for transacted 57 * sends, this is the time the client sends the message, not the time the 58 * transaction is committed). 59 * <P> 60 * A JMS provider should do its best to expire messages accurately; however, 61 * the JMS API does not define the accuracy provided. 62 * 63 * @version $Revision: 1.18 $ 64 * @see javax.jms.TopicPublisher 65 * @see javax.jms.QueueSender 66 * @see javax.jms.Session#createProducer 67 */ 68 public class ActiveMQMessageProducer implements MessageProducer, StatsCapable { 69 protected ActiveMQSession session; 70 protected String producerId; 71 private IdGenerator idGenerator; 72 protected boolean closed; 73 private boolean disableMessageID; 74 private boolean disableMessageTimestamp; 75 private int defaultDeliveryMode; 76 private int defaultPriority; 77 private long defaultTimeToLive; 78 protected ActiveMQDestination defaultDestination; 79 private long startTime; 80 private JMSProducerStatsImpl stats; 81 82 protected ActiveMQMessageProducer(ActiveMQSession theSession, ActiveMQDestination destination) throws JMSException { 83 this.session = theSession; 84 this.defaultDestination = destination; 85 this.idGenerator = new IdGenerator(); 86 this.disableMessageID = false; 87 this.disableMessageTimestamp = false; 88 this.defaultDeliveryMode = Message.DEFAULT_DELIVERY_MODE; 89 this.defaultPriority = Message.DEFAULT_PRIORITY; 90 this.defaultTimeToLive = Message.DEFAULT_TIME_TO_LIVE; 91 this.startTime = System.currentTimeMillis(); 92 this.session.addProducer(this); 93 this.stats = new JMSProducerStatsImpl(theSession.getSessionStats(), destination); 94 } 95 96 public Stats getStats() { 97 return stats; 98 } 99 100 public JMSProducerStatsImpl getProducerStats() { 101 return stats; 102 } 103 104 /*** 105 * Sets whether message IDs are disabled. 106 * <P> 107 * Since message IDs take some effort to create and increase a message's 108 * size, some JMS providers may be able to optimize message overhead if 109 * they are given a hint that the message ID is not used by an application. 110 * By calling the <CODE>setDisableMessageID</CODE> method on this message 111 * producer, a JMS client enables this potential optimization for all 112 * messages sent by this message producer. If the JMS provider accepts this 113 * hint, these messages must have the message ID set to null; if the 114 * provider ignores the hint, the message ID must be set to its normal 115 * unique value. 116 * <P> 117 * Message IDs are enabled by default. 118 * 119 * @param value indicates if message IDs are disabled 120 * @throws JMSException if the JMS provider fails to close the producer due to 121 * some internal error. 122 */ 123 public void setDisableMessageID(boolean value) throws JMSException { 124 checkClosed(); 125 this.disableMessageID = value; 126 } 127 128 /*** 129 * Gets an indication of whether message IDs are disabled. 130 * 131 * @return an indication of whether message IDs are disabled 132 * @throws JMSException if the JMS provider fails to determine if message IDs are 133 * disabled due to some internal error. 134 */ 135 public boolean getDisableMessageID() throws JMSException { 136 checkClosed(); 137 return this.disableMessageID; 138 } 139 140 /*** 141 * Sets whether message timestamps are disabled. 142 * <P> 143 * Since timestamps take some effort to create and increase a message's 144 * size, some JMS providers may be able to optimize message overhead if 145 * they are given a hint that the timestamp is not used by an application. 146 * By calling the <CODE>setDisableMessageTimestamp</CODE> method on this 147 * message producer, a JMS client enables this potential optimization for 148 * all messages sent by this message producer. If the JMS provider accepts 149 * this hint, these messages must have the timestamp set to zero; if the 150 * provider ignores the hint, the timestamp must be set to its normal 151 * value. 152 * <P> 153 * Message timestamps are enabled by default. 154 * 155 * @param value indicates if message timestamps are disabled 156 * @throws JMSException if the JMS provider fails to close the producer due to 157 * some internal error. 158 */ 159 public void setDisableMessageTimestamp(boolean value) throws JMSException { 160 checkClosed(); 161 this.disableMessageTimestamp = value; 162 } 163 164 /*** 165 * Gets an indication of whether message timestamps are disabled. 166 * 167 * @return an indication of whether message timestamps are disabled 168 * @throws JMSException if the JMS provider fails to close the producer due to 169 * some internal error. 170 */ 171 public boolean getDisableMessageTimestamp() throws JMSException { 172 checkClosed(); 173 return this.disableMessageTimestamp; 174 } 175 176 /*** 177 * Sets the producer's default delivery mode. 178 * <P> 179 * Delivery mode is set to <CODE>PERSISTENT</CODE> by default. 180 * 181 * @param newDeliveryMode the message delivery mode for this message producer; legal 182 * values are <code>DeliveryMode.NON_PERSISTENT</code> and 183 * <code>DeliveryMode.PERSISTENT</code> 184 * @throws JMSException if the JMS provider fails to set the delivery mode due to 185 * some internal error. 186 * @see javax.jms.MessageProducer#getDeliveryMode 187 * @see javax.jms.DeliveryMode#NON_PERSISTENT 188 * @see javax.jms.DeliveryMode#PERSISTENT 189 * @see javax.jms.Message#DEFAULT_DELIVERY_MODE 190 */ 191 public void setDeliveryMode(int newDeliveryMode) throws JMSException { 192 if (newDeliveryMode != DeliveryMode.PERSISTENT && newDeliveryMode != DeliveryMode.NON_PERSISTENT) { 193 throw new IllegalStateException("unkown delivery mode: " + newDeliveryMode); 194 } 195 checkClosed(); 196 this.defaultDeliveryMode = newDeliveryMode; 197 } 198 199 /*** 200 * Gets the producer's default delivery mode. 201 * 202 * @return the message delivery mode for this message producer 203 * @throws JMSException if the JMS provider fails to close the producer due to 204 * some internal error. 205 */ 206 public int getDeliveryMode() throws JMSException { 207 checkClosed(); 208 return this.defaultDeliveryMode; 209 } 210 211 /*** 212 * Sets the producer's default priority. 213 * <P> 214 * The JMS API defines ten levels of priority value, with 0 as the lowest 215 * priority and 9 as the highest. Clients should consider priorities 0-4 as 216 * gradations of normal priority and priorities 5-9 as gradations of 217 * expedited priority. Priority is set to 4 by default. 218 * 219 * @param newDefaultPriority the message priority for this message producer; must be a 220 * value between 0 and 9 221 * @throws JMSException if the JMS provider fails to set the delivery mode due to 222 * some internal error. 223 * @see javax.jms.MessageProducer#getPriority 224 * @see javax.jms.Message#DEFAULT_PRIORITY 225 */ 226 public void setPriority(int newDefaultPriority) throws JMSException { 227 if (newDefaultPriority < 0 || newDefaultPriority > 9) { 228 throw new IllegalStateException("default priority must be a value between 0 and 9"); 229 } 230 checkClosed(); 231 this.defaultPriority = newDefaultPriority; 232 } 233 234 /*** 235 * Gets the producer's default priority. 236 * 237 * @return the message priority for this message producer 238 * @throws JMSException if the JMS provider fails to close the producer due to 239 * some internal error. 240 * @see javax.jms.MessageProducer#setPriority 241 */ 242 public int getPriority() throws JMSException { 243 checkClosed(); 244 return this.defaultPriority; 245 } 246 247 /*** 248 * Sets the default length of time in milliseconds from its dispatch time 249 * that a produced message should be retained by the message system. 250 * <P> 251 * Time to live is set to zero by default. 252 * 253 * @param timeToLive the message time to live in milliseconds; zero is unlimited 254 * @throws JMSException if the JMS provider fails to set the time to live due to 255 * some internal error. 256 * @see javax.jms.MessageProducer#getTimeToLive 257 * @see javax.jms.Message#DEFAULT_TIME_TO_LIVE 258 */ 259 public void setTimeToLive(long timeToLive) throws JMSException { 260 if (timeToLive < 0l) { 261 throw new IllegalStateException("cannot set a negative timeToLive"); 262 } 263 checkClosed(); 264 this.defaultTimeToLive = timeToLive; 265 } 266 267 /*** 268 * Gets the default length of time in milliseconds from its dispatch time 269 * that a produced message should be retained by the message system. 270 * 271 * @return the message time to live in milliseconds; zero is unlimited 272 * @throws JMSException if the JMS provider fails to get the time to live due to 273 * some internal error. 274 * @see javax.jms.MessageProducer#setTimeToLive 275 */ 276 public long getTimeToLive() throws JMSException { 277 checkClosed(); 278 return this.defaultTimeToLive; 279 } 280 281 /*** 282 * Gets the destination associated with this <CODE>MessageProducer</CODE>. 283 * 284 * @return this producer's <CODE>Destination/ <CODE> 285 * @throws JMSException if the JMS provider fails to close the producer due to 286 * some internal error. 287 * @since 1.1 288 */ 289 public Destination getDestination() throws JMSException { 290 checkClosed(); 291 return this.defaultDestination; 292 } 293 294 /*** 295 * Closes the message producer. 296 * <P> 297 * Since a provider may allocate some resources on behalf of a <CODE> 298 * MessageProducer</CODE> outside the Java virtual machine, clients should 299 * close them when they are not needed. Relying on garbage collection to 300 * eventually reclaim these resources may not be timely enough. 301 * 302 * @throws JMSException if the JMS provider fails to close the producer due to 303 * some internal error. 304 */ 305 public void close() throws JMSException { 306 this.session.removeProducer(this); 307 closed = true; 308 } 309 310 protected void checkClosed() throws IllegalStateException { 311 if (closed) { 312 throw new IllegalStateException("The producer is closed"); 313 } 314 } 315 316 /*** 317 * Sends a message using the <CODE>MessageProducer</CODE>'s default 318 * delivery mode, priority, and time to live. 319 * 320 * @param message the message to send 321 * @throws JMSException if the JMS provider fails to send the message due to some 322 * internal error. 323 * @throws MessageFormatException if an invalid message is specified. 324 * @throws InvalidDestinationException if a client uses this method with a <CODE> 325 * MessageProducer</CODE> with an invalid destination. 326 * @throws java.lang.UnsupportedOperationException 327 * if a client uses this method with a <CODE> 328 * MessageProducer</CODE> that did not specify a 329 * destination at creation time. 330 * @see javax.jms.Session#createProducer 331 * @see javax.jms.MessageProducer 332 * @since 1.1 333 */ 334 public void send(Message message) throws JMSException { 335 this.send(this.defaultDestination, message, this.defaultDeliveryMode, this.defaultPriority, 336 this.defaultTimeToLive); 337 } 338 339 /*** 340 * Sends a message to the destination, specifying delivery mode, priority, 341 * and time to live. 342 * 343 * @param message the message to send 344 * @param deliveryMode the delivery mode to use 345 * @param priority the priority for this message 346 * @param timeToLive the message's lifetime (in milliseconds) 347 * @throws JMSException if the JMS provider fails to send the message due to some 348 * internal error. 349 * @throws MessageFormatException if an invalid message is specified. 350 * @throws InvalidDestinationException if a client uses this method with a <CODE> 351 * MessageProducer</CODE> with an invalid destination. 352 * @throws java.lang.UnsupportedOperationException 353 * if a client uses this method with a <CODE> 354 * MessageProducer</CODE> that did not specify a 355 * destination at creation time. 356 * @see javax.jms.Session#createProducer 357 * @since 1.1 358 */ 359 public void send(Message message, int deliveryMode, int priority, long timeToLive) throws JMSException { 360 this.send(this.defaultDestination, message, deliveryMode, priority, timeToLive); 361 } 362 363 /*** 364 * Sends a message to a destination for an unidentified message producer. 365 * Uses the <CODE>MessageProducer</CODE>'s default delivery mode, 366 * priority, and time to live. 367 * <P> 368 * Typically, a message producer is assigned a destination at creation 369 * time; however, the JMS API also supports unidentified message producers, 370 * which require that the destination be supplied every time a message is 371 * sent. 372 * 373 * @param destination the destination to send this message to 374 * @param message the message to send 375 * @throws JMSException if the JMS provider fails to send the message due to some 376 * internal error. 377 * @throws MessageFormatException if an invalid message is specified. 378 * @throws InvalidDestinationException if a client uses this method with an invalid destination. 379 * @throws java.lang.UnsupportedOperationException 380 * if a client uses this method with a <CODE> 381 * MessageProducer</CODE> that specified a destination at 382 * creation time. 383 * @see javax.jms.Session#createProducer 384 * @see javax.jms.MessageProducer 385 * @since 1.1 386 */ 387 public void send(Destination destination, Message message) throws JMSException { 388 this.send(destination, message, this.defaultDeliveryMode, this.defaultPriority, this.defaultTimeToLive); 389 } 390 391 /*** 392 * Sends a message to a destination for an unidentified message producer, 393 * specifying delivery mode, priority and time to live. 394 * <P> 395 * Typically, a message producer is assigned a destination at creation 396 * time; however, the JMS API also supports unidentified message producers, 397 * which require that the destination be supplied every time a message is 398 * sent. 399 * 400 * @param destination the destination to send this message to 401 * @param message the message to send 402 * @param deliveryMode the delivery mode to use 403 * @param priority the priority for this message 404 * @param timeToLive the message's lifetime (in milliseconds) 405 * @throws JMSException if the JMS provider fails to send the message due to some 406 * internal error. 407 * @throws MessageFormatException if an invalid message is specified. 408 * @throws InvalidDestinationException if a client uses this method with an invalid destination. 409 * @see javax.jms.Session#createProducer 410 * @since 1.1 411 */ 412 public void send(Destination destination, Message message, int deliveryMode, int priority, long timeToLive) 413 throws JMSException { 414 checkClosed(); 415 if (destination == null) { 416 throw new InvalidDestinationException("Dont understand null destinations"); 417 } 418 this.session.send(this, destination, message, deliveryMode, priority, timeToLive); 419 stats.onMessage(message); 420 } 421 422 423 /*** 424 * @return Returns the producerId. 425 */ 426 protected String getProducerId() { 427 return producerId; 428 } 429 430 /*** 431 * @param producerId The producerId to set. 432 */ 433 protected void setProducerId(String producerId) { 434 this.producerId = producerId; 435 } 436 437 protected long getStartTime() { 438 return this.startTime; 439 } 440 441 protected IdGenerator getIdGenerator() { 442 return this.idGenerator; 443 } 444 445 }