mq5.0-source.main.mq-client.src.main.java.com.sun.messaging.jmq.jmsclient.MessageProducerImpl Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 2000-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
/*
* @(#)MessageProducerImpl.java 1.40 06/27/07
*/
package com.sun.messaging.jmq.jmsclient;
import java.util.Hashtable;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Collections;
import java.util.ArrayList;
import java.util.Iterator;
import javax.jms.*;
import com.sun.messaging.AdministeredObject;
import com.sun.messaging.jmq.io.*;
import com.sun.messaging.jmq.jmsclient.resources.ClientResources;
import java.util.logging.*;
/** A client uses a message producer to send messages to a Destination. It is
* created by passing a Destination to a create message producer method
* supplied by a Session.
*
* A client also has the option of creating a message producer without
* supplying a Destination. In this case, a Destination must be input on
* every send operation. A typical use for this style of message producer is
* to send replies to requests using the request's replyTo Destination.
*
*
A client can specify a default delivery mode, priority and time-to-live
* for messages sent by a message producer. It can also specify delivery
* mode, priority and time-to-live per message.
*
*
A client can specify a time-to-live value in milliseconds for each
* message it sends. This value defines a message expiration time which
* is the sum of the message's time-to-live and the GMT it is sent (for
* transacted sends, this is the time the client sends the message, not
* the time the transaction is committed).
*
*
A JMS provider should do its best to accurately expire messages;
* however, JMS does not define the accuracy provided.
*
* @see javax.jms.TopicPublisher
* @see javax.jms.QueueSender
* @see javax.jms.Session
*/
public class MessageProducerImpl implements MessageProducer {
protected boolean inClosing = false;
protected boolean isClosed = false;
protected boolean disableMessageId = false; //default in spec.
protected boolean disableMessageTimestamp = false; //default in spec.
protected int deliveryMode = DeliveryMode.PERSISTENT; //default in spec.
protected int priority = 4; //default;
protected long timeToLive = 0L; // default
protected long deliveryDelay = javax.jms.Message.DEFAULT_DELIVERY_DELAY;
protected Destination destination = null;
protected SessionImpl session = null;
protected MessageConvert messageConvert = null;
//dest used when sending a message producer pkt to the broker.
protected Destination addProducerDest = null;
//XXX PROTOCOL3.5 --
//Producer flow control.
protected Hashtable destinations = new Hashtable();
protected Hashtable producerStates = new Hashtable();
//contains destName/xmlValidator
//private static Hashtable validationTable = new Hashtable();
private boolean debug = Debug.debug;
private boolean _forJMSBridge = false;
protected static final Logger sessionLogger = SessionImpl.sessionLogger;
public MessageProducerImpl(SessionImpl session, Destination destination)
throws JMSException {
try {
this.session = session;
this.destination = destination;
if (destination != null) {
session.getProtocolHandler().createMessageProducer(this);
}
session.addMessageProducer(this);
if ( sessionLogger.isLoggable(Level.FINE) ) {
this.logLifeCycle(ClientResources.I_PRODUCER_CREATED);
}
} catch (JMSException jmse) {
ExceptionHandler.throwJMSException(jmse);
}
}
/**
* This method is called by ConnectionRecover during connection
* failover or auto-reconnect.
*/
public void recreateProducer() throws JMSException {
if (destination != null) {
// Create the producer again.
session.getProtocolHandler().createMessageProducer(this);
}
else {
// No need to physically recreate any producers! Instead
// cleanup all the unbound producers created before. They
// will be created again on demand...
Enumeration enum2 = destinations.elements();
while (enum2.hasMoreElements()) {
ProducerState ps = (ProducerState) enum2.nextElement();
session.connection.removeMessageProducer(
new Long(ps.getProducerID()));
}
destinations.clear();
producerStates.clear();
}
}
/**
* Check if this is a JMQ message. If this is, the same reference
* is returned. Otherwise, the message is converted to JMQ message
* implementation and returned.
*/
protected Message checkJMQMessage(Message message) throws JMSException {
if (message instanceof MessageImpl){
return message;
}
//this is a foreign message
if (messageConvert == null){
messageConvert = MessageConvert.getInstance();
}
return messageConvert.convertJMSMessage (message);
}
protected void checkState() throws JMSException {
if (inClosing) {
String errorString = AdministeredObject.cr.getKString(
AdministeredObject.cr.X_PRODUCER_CLOSING);
JMSException jmse = new javax.jms.IllegalStateException(errorString,
AdministeredObject.cr.X_PRODUCER_CLOSING);
ExceptionHandler.throwJMSException(jmse);
}
if (isClosed){
String errorString = AdministeredObject.cr.getKString(
AdministeredObject.cr.X_PRODUCER_CLOSED);
JMSException jmse = new javax.jms.IllegalStateException(errorString,
AdministeredObject.cr.X_PRODUCER_CLOSED);
ExceptionHandler.throwJMSException(jmse);
}
}
/**
* Reset foreign message header after it is sent.
*/
protected void
resetForeignMessageHeader (Message message, Message foreignMessage) throws JMSException {
if (!_forJMSBridge) {
messageConvert.resetForeignMessageHeader( message, foreignMessage );
}
}
protected void
writeJMSMessage(Message message, CompletionListener completionListener,
Message foreignMessage)
throws JMSException {
writeJMSMessage(destination, message,
completionListener, foreignMessage);
}
protected void
writeJMSMessage(Destination dest, Message message,
CompletionListener completionListener,
Message foreignMessage)
throws JMSException {
AsyncSendCallback asynccb = null;
try {
if (completionListener != null) {
asynccb = new AsyncSendCallback(this, dest, message,
completionListener, foreignMessage);
session.addAsyncSendCallback(asynccb);
checkState();
}
session.connection.checkReconnecting(null, true);
checkFlowControl(dest, message, true);
try {
session.writeJMSMessage(message, asynccb);
if (sessionLogger.isLoggable(Level.FINER)) {
//String pktType =
// PacketType.getString
// (((MessageImpl) message).getPacket().getPacketType());
//String param = pktType + ", " + session.toString() + getDestInfo (dest);
//sessionLogger.log(Level.FINEST,
// ClientResources.I_PRODUCER_SENDING_MESSAGE,
// param);
this.logMessageProduced(dest, message, completionListener);
}
if (asynccb != null) {
asynccb.sendSuccessReturn();
}
} catch (Exception e) {
ExceptionHandler.handleException(e, AdministeredObject.cr.X_CAUGHT_EXCEPTION);
}
} finally {
if (asynccb != null) {
asynccb.sendReturn();
}
}
}
private void logMessageProduced (Destination dest, Message message,
CompletionListener completionListener)
throws JMSException {
if (sessionLogger.isLoggable(Level.FINER)) {
//String pktType =
// PacketType.getString
// (((MessageImpl) message).getPacket().getPacketType());
//String param = pktType + ", " + session.toString() + getDestInfo (dest);
//sessionLogger.log(Level.FINEST,
// ClientResources.I_PRODUCER_SENDING_MESSAGE,
// param);
com.sun.messaging.Destination mqDest = ((com.sun.messaging.Destination) dest);
String domain = (mqDest.isQueue()? "Queue":"Topic");
String pktType = PacketType.getString( ((MessageImpl) message).getPacket().getPacketType());
ProducerState ps = (ProducerState) destinations.get(mqDest.getName());
long pid = ps.getProducerID();
String param = "MQTrace=MessageProducer" +
", ThreadID=" + Thread.currentThread().getId() +
", ClientID=" + session.connection.getClientID() +
", ConnectionID=" + session.connection.getConnectionID() +
", SessionID=" + session.getBrokerSessionID() +
", ProducerID=" + pid +
", Destination=" + mqDest.getName() +
", Domain=" + domain +
", MessageID=" + message.getJMSMessageID() +
", MessageType=" + pktType;
String logkey = ClientResources.I_PRODUCER_SENT_MESSAGE;
if (completionListener != null) {
logkey = ClientResources.I_PRODUCER_ASYNC_SENDING_MESSAGE;
}
sessionLogger.log(Level.FINER, logkey, param);
if (sessionLogger.isLoggable(Level.FINEST)) {
param = "MQTrace=MessageProducer" +
", ProducerID=" + pid +
", Message=" + message.toString();
sessionLogger.log(Level.FINEST, logkey, param);
}
}
}
/** Gets the Destination associated with this MessageProducer
.
*
* @return this sender's Destination
*
* @exception JMSException if the JMS provider fails to get the destination for
* this MessageProducer
* due to some internal error.
* @since 1.1
*/
public Destination
getDestination() throws JMSException {
checkState();
return destination;
}
/** Set whether message IDs are disabled.
*
*
Since message ID's take some effort to create and increase a
* message's size, some JMS providers may be able to optimize message
* overhead if they are given a hint that message ID is not used by
* an application. JMS message Producers provide a hint to disable
* message ID. When a client sets a Producer to disable message ID
* they are saying that they do not depend on the value of message
* ID for the messages it produces. These messages must either have
* message ID set to null or, if the hint is ignored, messageID must
* be set to its normal unique value.
*
*
Message IDs are enabled by default.
*
* @param value indicates if message IDs are disabled.
*
* @exception JMSException if JMS fails to set disabled message
* Id due to some internal error.
*/
public void
setDisableMessageID(boolean value) throws JMSException {
checkState();
disableMessageId = value;
}
/** Get an indication of whether message IDs are disabled.
*
* @return an indication of whether message IDs are disabled.
*
* @exception JMSException if JMS fails to get disabled message
* Id due to some internal error.
*/
public boolean
getDisableMessageID() throws JMSException {
checkState();
return disableMessageId;
}
/** Set whether message timestamps are disabled.
*
*
Since timestamps take some effort to create and increase a
* message's size, some JMS providers may be able to optimize message
* overhead if they are given a hint that timestamp is not used by an
* application. JMS message Producers provide a hint to disable
* timestamps. When a client sets a producer to disable timestamps
* they are saying that they do not depend on the value of timestamp
* for the messages it produces. These messages must either have
* timestamp set to null or, if the hint is ignored, timestamp must
* be set to its normal value.
*
*
Message timestamps are enabled by default.
*
* @param value indicates if message timestamps are disabled.
*
* @exception JMSException if JMS fails to set disabled message
* timestamp due to some internal error.
*/
public void
setDisableMessageTimestamp(boolean value) throws JMSException {
checkState();
disableMessageTimestamp = value;
}
/** Get an indication of whether message timestamps are disabled.
*
* @return an indication of whether message IDs are disabled.
*
* @exception JMSException if JMS fails to get disabled message
* timestamp due to some internal error.
*/
public boolean
getDisableMessageTimestamp() throws JMSException {
checkState();
return disableMessageTimestamp;
}
/** Set the producer's default delivery mode.
*
*
Delivery mode is set to PERSISTENT by default.
*
* @param deliveryMode the message delivery mode for this message
* producer. Legal values are DeliveryMode.NON_PERSISTENT
* or DeliveryMode.PERSISTENT
.
*
* @exception JMSException if JMS fails to set delivery mode
* due to some internal error.
*
* @see javax.jms.MessageProducer#getDeliveryMode
* @see javax.jms.DeliveryMode#NON_PERSISTENT
* @see javax.jms.DeliveryMode#PERSISTENT
* @see javax.jms.Message#DEFAULT_DELIVERY_MODE
*/
public void
setDeliveryMode(int deliveryMode) throws JMSException {
checkState();
if (deliveryMode != DeliveryMode.NON_PERSISTENT &&
deliveryMode != DeliveryMode.PERSISTENT){
String errorString = AdministeredObject.cr.getKString(AdministeredObject.cr.X_INVALID_DELIVERY_PARAM,
"DeliveryMode", String.valueOf(deliveryMode));
ExceptionHandler.throwJMSException
(new JMSException(errorString, AdministeredObject.cr.X_INVALID_DELIVERY_PARAM));
}
this.deliveryMode = deliveryMode;
}
/** Get the producer's default delivery mode.
*
* @return the message delivery mode for this message producer.
*
* @exception JMSException if JMS fails to get delivery mode
* due to some internal error.
*
* @see javax.jms.MessageProducer#setDeliveryMode
*/
public int
getDeliveryMode() throws JMSException {
checkState();
return deliveryMode;
}
/** Set the producer's default priority.
*
*
JMS defines a 10 level priority value with 0 as the lowest
* and 9 as the highest. Clients should consider 0-4 as
* gradients of normal priority and 5-9 as gradients of expedited
* priority. Priority is set to 4, by default.
*
* @param priority the message priority for this message producer.
* Priority must be a value between 0 and 9.
*
*
* @exception JMSException if JMS fails to set priority
* due to some internal error.
*
* @see javax.jms.MessageProducer#getPriority
* @see javax.jms.Message#DEFAULT_PRIORITY
*/
public void
setPriority(int defaultPriority) throws JMSException {
checkState();
if ( defaultPriority < 0 || defaultPriority > 9 ) {
String errorString = AdministeredObject.cr.getKString(AdministeredObject.cr.X_INVALID_DELIVERY_PARAM,
"DeliveryPriority", String.valueOf(defaultPriority));
ExceptionHandler.throwJMSException
(new JMSException(errorString, AdministeredObject.cr.X_INVALID_DELIVERY_PARAM));
}
this.priority = defaultPriority;
}
/** Get the producer's default priority.
*
* @return the message priority for this message producer.
*
* @exception JMSException if JMS fails to get priority
* due to some internal error.
*
* @see javax.jms.MessageProducer#setPriority
*/
public int
getPriority() throws JMSException {
checkState();
return priority;
}
/** Set the default length of time in milliseconds from its dispatch time
* that a produced message should be retained by the message system.
*
*
Time to live is set to zero by default.
*
* @param timeToLive the message time to live in milliseconds; zero is
* unlimited
*
* @exception JMSException if JMS fails to set Time to Live
* due to some internal error.
*
* @see javax.jms.MessageProducer#getTimeToLive
* @see javax.jms.Message#DEFAULT_TIME_TO_LIVE
*/
public void
setTimeToLive(long timeToLive) throws JMSException {
checkState();
if ( timeToLive < 0 ) {
String errorString = AdministeredObject.cr.getKString(AdministeredObject.cr.X_INVALID_DELIVERY_PARAM,
"TimeToLive", String.valueOf(timeToLive));
ExceptionHandler.throwJMSException
(new JMSException(errorString, AdministeredObject.cr.X_INVALID_DELIVERY_PARAM));
}
this.timeToLive = timeToLive;
}
/** Get the default length of time in milliseconds from its dispatch time
* that a produced message should be retained by the message system.
*
* @return the message time to live in milliseconds; zero is unlimited
*
* @exception JMSException if JMS fails to get Time to Live
* due to some internal error.
*
* @see javax.jms.MessageProducer#setTimeToLive
*/
public long
getTimeToLive() throws JMSException {
checkState();
return timeToLive;
}
/**
* Sets the minimum length of time in milliseconds that must elapse after a
* message is sent before the JMS provider may deliver the message to a
* consumer.
*
* For transacted sends, this time starts when the client sends the message,
* not when the transaction is committed.
*
* deliveryDelay is set to zero by default.
*
* @param deliveryDelay
* the delivery delay in milliseconds.
*
* @exception JMSException
* if the JMS provider fails to set the delivery delay due to
* some internal error.
*
* @see javax.jms.MessageProducer#getDeliveryDelay
* @see javax.jms.Message#DEFAULT_DELIVERY_DELAY
*
* @since 2.0
*/
public void
setDeliveryDelay(long deliveryDelay) throws JMSException {
checkState();
if ( deliveryDelay < 0L ) {
String errorString = AdministeredObject.cr.getKString(AdministeredObject.cr.X_INVALID_DELIVERY_PARAM,
"DeliveryDelay", String.valueOf(deliveryDelay));
ExceptionHandler.throwJMSException
(new JMSException(errorString, AdministeredObject.cr.X_INVALID_DELIVERY_PARAM));
}
this.deliveryDelay = deliveryDelay;
}
/**
* Gets the minimum length of time in milliseconds that must elapse after a
* message is sent before the JMS provider may deliver the message to a
* consumer.
*
* @return the delivery delay in milliseconds.
*
* @exception JMSException
* if the JMS provider fails to get the delivery delay due to
* some internal error.
*
* @see javax.jms.MessageProducer#setDeliveryDelay
*
* @since 2.0
*/
public long
getDeliveryDelay() throws JMSException {
checkState();
return deliveryDelay;
}
/** Since a provider may allocate some resources on behalf of a
* MessageProducer outside the JVM, clients should close them when they
* are not needed. Relying on garbage collection to eventually reclaim
* these resources may not be timely enough.
*
* @exception JMSException if JMS fails to close the producer
* due to some error.
*/
//XXX note currently producers are not cleaned up on session close
//need to address this for 2.1
public void
close() throws JMSException {
session.checkPermissionForAsyncSend();
//XXX PROTOCOL3.5 --
// Producer flow control. Raptor broker keeps track of
// producers.
try {
inClosing = true;
try {
Enumeration enum2 = producerStates.elements();
while (enum2.hasMoreElements()) {
ProducerState ps = (ProducerState) enum2.nextElement();
if (session.connection.getBrokerProtocolLevel() >=
PacketType.VERSION350 && session.getProtocolHandler() != null) {
session.connection.removeMessageProducer(
new Long(ps.getProducerID()));
//delete only if connection is not broken
if (session.connection.isBroken() == false) {
session.getProtocolHandler().deleteMessageProducer(
ps.getProducerID());
}
}
ps.close();
}
session.removeMessageProducer(this);
destinations.clear();
producerStates.clear();
} finally {
session.waitAllAsyncSendCompletion(this);
}
} finally {
isClosed = true;
//log producer closed
if (session.sessionLogger.isLoggable(Level.FINE) ) {
logLifeCycle(ClientResources.I_PRODUCER_CLOSED);
}
}
}
/** Sends a message using the MessageProducer
's
* default delivery mode, priority, and time to live.
*
* @param message the message to send
*
* @exception JMSException if the JMS provider fails to send the message
* due to some internal error.
* @exception MessageFormatException if an invalid message is specified.
* @exception InvalidDestinationException if a client uses
* this method with a MessageProducer
with
* an invalid Destination.
* @exception java.lang.UnsupportedOperationException if a client uses this
* method with a MessageProducer
that did
* not specify a destination at creation time.
*
* @see javax.jms.Session#createProducer
* @see javax.jms.MessageProducer#getDeliveryMode
* @see javax.jms.MessageProducer#getTimeToLive
* @see javax.jms.MessageProducer#getPriority
* @since 1.1
*/
public void
send(Message message) throws JMSException {
_send(message, null);
}
private void
_send(Message message, CompletionListener completionListener)
throws JMSException {
Message foreignMessage = null;
checkState();
if (destination == null) {
throw new UnsupportedOperationException();
}
checkTemporaryDestination(destination);
if ((message instanceof MessageImpl) == false ) {
foreignMessage = message;
}
message = checkJMQMessage(message);
message.setJMSDestination(destination);
message.setJMSDeliveryMode(getDeliveryMode());
message.setJMSPriority(getPriority());
message.setJMSExpiration(getTimeToLive());
message.setJMSDeliveryTime(getDeliveryDelay());
if (session.connection.jmqOverrideJMSMsgHeaders){
Destination d = message.getJMSDestination();
if (session.connection.jmqOverrideMsgsToTempDests
|| ((!(d instanceof TemporaryQueue))
&& (!(d instanceof TemporaryTopic)))){
if (session.connection.jmqOverrideJMSDeliveryMode){
message.setJMSDeliveryMode(session.connection.jmqJMSDeliveryMode);
}
if (session.connection.jmqOverrideJMSPriority){
message.setJMSPriority(session.connection.jmqJMSPriority);
}
if (session.connection.jmqOverrideJMSExpiration){
message.setJMSExpiration(session.connection.jmqJMSExpiration);
}
}
}
writeJMSMessage(message, completionListener, foreignMessage);
if (foreignMessage != null && completionListener == null) {
resetForeignMessageHeader(message, foreignMessage);
}
}
/** Sends a message to the Destination, specifying delivery mode, priority, and
* time to live.
*
* @param message the message to send
* @param deliveryMode the delivery mode to use
* @param priority the priority for this message
* @param timeToLive the message's lifetime (in milliseconds)
*
* @exception JMSException if the JMS provider fails to send the message
* due to some internal error.
* @exception MessageFormatException if an invalid message is specified.
* @exception InvalidDestinationException if a client uses
* this method with a MessageProducer
with
* an invalid Destination.
* @exception java.lang.UnsupportedOperationException if a client uses this
* method with a MessageProducer
that did
* not specify a destination at creation time.
*
* @see javax.jms.Session#createProducer
* @since 1.1
*/
public void
send(Message message, int deliveryMode, int priority, long timeToLive) throws JMSException {
_send(message, deliveryMode, priority, timeToLive, null);
}
private void
_send(Message message, int deliveryMode, int priority, long timeToLive,
CompletionListener completionListener) throws JMSException {
Message foreignMessage = null;
checkState();
if (destination == null){
throw new UnsupportedOperationException();
}
checkTemporaryDestination(destination);
if ((message instanceof MessageImpl) == false){
foreignMessage = message;
}
message = checkJMQMessage(message);
message.setJMSDestination(destination);
message.setJMSDeliveryMode(deliveryMode);
message.setJMSPriority(priority);
message.setJMSExpiration(timeToLive);
message.setJMSDeliveryTime(getDeliveryDelay());
if (session.connection.jmqOverrideJMSMsgHeaders){
Destination d = message.getJMSDestination();
if (session.connection.jmqOverrideMsgsToTempDests
|| ((!(d instanceof TemporaryQueue))
&& (!(d instanceof TemporaryTopic)))){
if (session.connection.jmqOverrideJMSDeliveryMode){
message.setJMSDeliveryMode(session.connection.jmqJMSDeliveryMode);
}
if (session.connection.jmqOverrideJMSPriority){
message.setJMSPriority(session.connection.jmqJMSPriority);
}
if (session.connection.jmqOverrideJMSExpiration){
message.setJMSExpiration(session.connection.jmqJMSExpiration);
}
}
}
writeJMSMessage(message, completionListener, foreignMessage);
if (foreignMessage != null && completionListener == null){
resetForeignMessageHeader (message, foreignMessage);
}
}
/**Sends a message to a Destination for an unidentified message producer.
* Uses the MessageProducer
's default delivery mode, priority,
* and time to live.
*
*
Typically, a message producer is assigned a destination at creation
* time; however, the JMS API also supports unidentified message producers,
* which require that the Destination be supplied every time a message is
* sent.
*
* @param destination the destination to send this message to
* @param message the message to send
*
* @exception JMSException if the JMS provider fails to send the message
* due to some internal error.
* @exception MessageFormatException if an invalid message is specified.
* @exception InvalidDestinationException if a client uses
* this method with an invalid Destination.
* @exception java.lang.UnsupportedOperationException if a client uses this
* method with a MessageProducer
that did
* specify a destination at creation time.
*
* @see javax.jms.Session#createProducer
* @see javax.jms.MessageProducer#getDeliveryMode
* @see javax.jms.MessageProducer#getTimeToLive
* @see javax.jms.MessageProducer#getPriority
* @since 1.1
*/
public void send(Destination destination, Message message) throws JMSException {
_send(destination, message, null);
}
private void
_send(Destination destination, Message message,
CompletionListener completionListener) throws JMSException {
Message foreignMessage = null;
checkState();
if (destination == null) {
String errorString =
AdministeredObject.cr.getKString(AdministeredObject.cr.X_DESTINATION_NOTFOUND, "null");
ExceptionHandler.throwJMSException (
new InvalidDestinationException(errorString,
AdministeredObject.cr.X_DESTINATION_NOTFOUND));
}
if (this.destination != null) {
throw new UnsupportedOperationException();
}
checkTemporaryDestination(destination);
if ((message instanceof MessageImpl) == false){
foreignMessage = message;
}
checkForUnspecifiedProducer(destination);
message = checkJMQMessage(message);
message.setJMSDestination(destination);
message.setJMSDeliveryMode(getDeliveryMode());
message.setJMSPriority(getPriority());
message.setJMSExpiration(getTimeToLive());
message.setJMSDeliveryTime(getDeliveryDelay());
if (session.connection.jmqOverrideJMSMsgHeaders){
Destination d = message.getJMSDestination();
if (session.connection.jmqOverrideMsgsToTempDests
|| ((!(d instanceof TemporaryQueue))
&& (!(d instanceof TemporaryTopic)))){
if (session.connection.jmqOverrideJMSDeliveryMode){
message.setJMSDeliveryMode(session.connection.jmqJMSDeliveryMode);
}
if (session.connection.jmqOverrideJMSPriority){
message.setJMSPriority(session.connection.jmqJMSPriority);
}
if (session.connection.jmqOverrideJMSExpiration){
message.setJMSExpiration(session.connection.jmqJMSExpiration);
}
}
}
writeJMSMessage(destination, message, completionListener, foreignMessage);
if (foreignMessage != null && completionListener == null){
resetForeignMessageHeader (message, foreignMessage);
}
}
/** Sends a message to a Destination for an unidentified message producer,
* specifying delivery mode, priority and time to live.
*
*
Typically, a message producer is assigned a destination at creation
* time; however, the JMS API also supports unidentified message producers,
* which require that the Destination be supplied every time a message is
* sent.
*
* @param destination the destination to send this message to
* @param message the message to send
* @param deliveryMode the delivery mode to use
* @param priority the priority for this message
* @param timeToLive the message's lifetime (in milliseconds)
*
* @exception JMSException if the JMS provider fails to send the message
* due to some internal error.
* @exception MessageFormatException if an invalid message is specified.
* @exception InvalidDestinationException if a client uses
* this method with an invalid Destination.
* @exception java.lang.UnsupportedOperationException if a client uses this
* method with a MessageConsumer
that
* specified a destination at creation time.
*
* @see javax.jms.Session#createProducer
* @since 1.1
*/
public void
send(Destination destination, Message message,
int deliveryMode, int priority, long timeToLive)
throws JMSException {
_send(destination, message, deliveryMode, priority, timeToLive, null);
}
private void
_send(Destination destination, Message message, int deliveryMode,
int priority, long timeToLive, CompletionListener completionListener)
throws JMSException {
Message foreignMessage = null;
checkState();
if (destination == null) {
String errorString =
AdministeredObject.cr.getKString(AdministeredObject.cr.X_DESTINATION_NOTFOUND, "null");
ExceptionHandler.throwJMSException (
new InvalidDestinationException(errorString,
AdministeredObject.cr.X_DESTINATION_NOTFOUND));
}
if (this.destination != null) {
throw new UnsupportedOperationException();
}
checkTemporaryDestination(destination);
if ((message instanceof MessageImpl) == false){
foreignMessage = message;
}
checkForUnspecifiedProducer(destination);
message = checkJMQMessage(message);
message.setJMSDestination(destination);
message.setJMSDeliveryMode(deliveryMode);
message.setJMSPriority(priority);
message.setJMSExpiration(timeToLive);
message.setJMSDeliveryTime(getDeliveryDelay());
if (session.connection.jmqOverrideJMSMsgHeaders){
Destination d = message.getJMSDestination();
if (session.connection.jmqOverrideMsgsToTempDests || (!(d instanceof TemporaryQueue))) {
if (session.connection.jmqOverrideJMSDeliveryMode){
message.setJMSDeliveryMode(session.connection.jmqJMSDeliveryMode);
}
if (session.connection.jmqOverrideJMSPriority){
message.setJMSPriority(session.connection.jmqJMSPriority);
}
if (session.connection.jmqOverrideJMSExpiration){
message.setJMSExpiration(session.connection.jmqJMSExpiration);
}
}
}
writeJMSMessage(destination, message, completionListener, foreignMessage);
if (foreignMessage != null && completionListener == null) {
resetForeignMessageHeader (message, foreignMessage);
}
}
public void _setForJMSBridge() {
_forJMSBridge = true;
}
/*
protected long getProducerID() {
return producerID;
}
*/
protected void setProducerID(Destination dest, long producerID) {
String dn = ((com.sun.messaging.Destination) dest).getName();
ProducerState ps = (ProducerState) destinations.get(dn);
if (ps == null) {
ps = new ProducerState();
destinations.put(dn, ps);
}
else {
if (debug) {
Debug.println("Replacing ProducerID. old = " +
ps.getProducerID() + ", new = " + producerID);
}
producerStates.remove(new Long(ps.getProducerID()));
session.connection.removeMessageProducer(
new Long(ps.getProducerID()));
}
ps.setProducerID(producerID);
producerStates.put(new Long(producerID), ps);
session.connection.addMessageProducer(new Long(producerID), this);
}
protected void setFlowLimit(long producerID, int flowLimit) {
if (debug) {
Debug.println("Setting flowLimit = " + flowLimit +
" for producerID = " + producerID);
}
ProducerState ps = (ProducerState) producerStates.get(
new Long(producerID));
ps.setFlowLimit(flowLimit);
}
protected void setFlowBytesLimit(long producerID, long flowBytesLimit) {
if (debug) {
Debug.println("Setting flowBytesLimit = " + flowBytesLimit +
" for producerID = " + producerID);
}
ProducerState ps = (ProducerState) producerStates.get(
new Long(producerID));
ps.setFlowBytesLimit(flowBytesLimit);
}
private void checkFlowControl(Destination dest, Message message, boolean block)
throws JMSException {
String dn = ((com.sun.messaging.Destination) dest).getName();
ProducerState ps = (ProducerState) destinations.get(dn);
if (ps != null)
ps.checkFlowControl(message, block);
}
protected SessionImpl getSession() {
return session;
}
public String toString() {
//return "MessageProducer: " + session.getConnection().toString();
String destName = null;
long pid = -1;
try {
if ( destination != null ) {
destName = ((com.sun.messaging.Destination) destination).
getName();
ProducerState ps = (ProducerState) destinations.get(destName);
pid = ps.getProducerID();
}
} catch (Exception e) {
//if we catch exception, pid would be -1
if ( debug) {
Debug.printStackTrace(e);
}
}
return session.toString() +
", ProducerID=" + pid + ", DestName=" + destName;
}
protected void checkForUnspecifiedProducer(Destination dest)
throws JMSException {
//XXX: Should not be using d.getName();
com.sun.messaging.Destination d =
(com.sun.messaging.Destination) dest;
String dn = d.getName();
if (destinations.get(dn) == null) {
session.getProtocolHandler().createMessageProducer(this, d);
}
}
protected void checkTemporaryDestination(Destination dest) throws JMSException {
if (dest instanceof TemporaryDestination) {
// check whether the temporary destination has been deleted
if (((TemporaryDestination) dest).isDeleted()) {
String errorString = AdministeredObject.cr.getKString(AdministeredObject.cr.X_TEMP_DESTINATION_DELETED,
((TemporaryDestination) dest).getName());
ExceptionHandler.throwJMSException(new InvalidDestinationException(errorString,
AdministeredObject.cr.X_TEMP_DESTINATION_DELETED));
}
// check whether the owning connection is closed
ConnectionImpl connection = ((TemporaryDestination) dest).connection;
if (connection != null) { // local temp destination.
if (connection.isClosed) {
String errorString = AdministeredObject.cr.getKString(
AdministeredObject.cr.X_TEMP_DESTINATION_INVALID, ((TemporaryDestination) dest).getName());
ExceptionHandler.throwJMSException(new InvalidDestinationException(errorString,
AdministeredObject.cr.X_TEMP_DESTINATION_INVALID));
}
}
}
}
public void logLifeCycle (String key) {
if ( sessionLogger.isLoggable(Level.FINE) ) {
sessionLogger.log(Level.FINE, key, this);
}
}
private String getDestInfo (Destination destination) {
long pid = -1;
String info = null;
try {
if (destination != null) {
String destName = ((com.sun.messaging.Destination) destination).
getName();
ProducerState ps = (ProducerState) destinations.get(destName);
pid = ps.getProducerID();
info = ", destName=" + destName + ", producerID=" + pid;
}
} catch (Exception e) {
//if we catch exception, pid would be -1
if (debug) {
Debug.printStackTrace(e);
}
}
return info;
}
class ProducerState {
private long flowBytesLimit;
private int flowLimit;
private long producerID;
private boolean blocked = false;
private boolean _psclosed = false;
private int TEST_minResume = Integer.MAX_VALUE;
private int TEST_maxResume = -1;
private int TEST_resumeCount = 0;
private int TEST_pauseCount = 0;
private int TEST_forcePauseCount = 0;
protected long getFlowBytesLimit() {
return flowBytesLimit;
}
protected synchronized void setFlowBytesLimit(long flowBytesLimit) {
this.flowBytesLimit = flowBytesLimit;
}
protected int getFlowLimit() {
return flowLimit;
}
protected synchronized void setFlowLimit(int flowLimit) {
this.flowLimit = flowLimit;
if (flowLimit < TEST_minResume)
TEST_minResume = flowLimit;
if (flowLimit > TEST_maxResume)
TEST_maxResume = flowLimit;
if (flowLimit != 0)
TEST_resumeCount++;
else
TEST_forcePauseCount++;
notifyAll();
}
protected long getProducerID() {
return producerID;
}
protected void setProducerID(long producerID) {
this.producerID = producerID;
}
protected synchronized void close() {
_psclosed = true;
notifyAll();
}
private synchronized void checkFlowControl(Message message, boolean block)
throws JMSException {
while (flowLimit == 0 && ! isClosed && !_psclosed) {
try {
if (!block) {
throw new JMSException("XXXWOULD-BLOCK");
}
blocked = true;
wait();
blocked = false;
}
catch (InterruptedException e) {}
}
if (isClosed || _psclosed) {
String errorString = AdministeredObject.cr.getKString(AdministeredObject.cr.X_PRODUCER_CLOSED);
JMSException jmse =
new javax.jms.JMSException(errorString, AdministeredObject.cr.X_PRODUCER_CLOSED);
ExceptionHandler.throwJMSException(jmse);
}
if (flowLimit > 0)
flowLimit--;
if (flowLimit == 0) {
TEST_pauseCount++;
}
ReadWritePacket pkt = ((MessageImpl) message).getPacket();
pkt.setProducerID(producerID);
pkt.setConsumerFlow((flowLimit == 0));
}
protected Hashtable getDebugState(boolean verbose) {
Hashtable ht = new Hashtable();
ht.put("producerID", String.valueOf(producerID));
ht.put("flowLimit", String.valueOf(flowLimit));
ht.put("flowBytesLimit", String.valueOf(flowBytesLimit));
ht.put("blocked", String.valueOf(blocked));
ht.put("pauseCount", String.valueOf(TEST_pauseCount));
ht.put("resumeCount", String.valueOf(TEST_resumeCount));
ht.put("maxResume", String.valueOf(TEST_maxResume));
ht.put("minResume", String.valueOf(TEST_minResume));
ht.put("forcedPauses", String.valueOf(TEST_forcePauseCount));
return ht;
}
}
protected Hashtable getDebugState(boolean verbose) {
Hashtable ht = new Hashtable();
ht.put("isClosed", String.valueOf(isClosed));
ht.put("deliveryMode", String.valueOf(deliveryMode));
ht.put("priority", String.valueOf(priority));
ht.put("timeToLive", String.valueOf(timeToLive));
ht.put("deliveryDelay", String.valueOf(deliveryDelay));
ht.put("disableMessageId", String.valueOf(disableMessageId));
ht.put("disableTimestamp",
String.valueOf(disableMessageTimestamp));
if (destination != null) {
ht.put("Destination Class", destination.getClass().getName());
if (destination instanceof com.sun.messaging.Destination) {
ht.put("Destination", ((com.sun.messaging.Destination)
destination).getName());
}
Enumeration enum2 = producerStates.elements();
while (enum2.hasMoreElements()) {
ProducerState ps = (ProducerState) enum2.nextElement();
ht.putAll(ps.getDebugState(verbose));
}
}
else {
// Unbound producer...
ht.put("isBound", "false");
ht.put("# Destinations", String.valueOf(destinations.size()));
int n = 0;
Enumeration enum2 = destinations.keys();
while (enum2.hasMoreElements()) {
String dn = (String) enum2.nextElement();
ProducerState ps = (ProducerState) destinations.get(dn);
Hashtable tmp = ps.getDebugState(verbose);
tmp.put("Destination", dn);
ht.put("ProducerState[" + n + "]", tmp);
n++;
}
}
return ht;
}
@Override
public void send(Message message, CompletionListener completionListener)
throws JMSException {
if (completionListener == null) {
throw new IllegalArgumentException("CompletionListener must not be null");
}
_send(message, completionListener);
}
@Override
public void send(Message message, int deliveryMode, int priority,
long timeToLive, CompletionListener completionListener)
throws JMSException {
if (completionListener == null) {
throw new IllegalArgumentException("CompletionListener must not be null");
}
_send(message, deliveryMode, priority, timeToLive, completionListener);
}
@Override
public void send(Destination destination, Message message,
CompletionListener completionListener)
throws JMSException {
if (completionListener == null) {
throw new IllegalArgumentException("CompletionListener must not be null");
}
_send(destination, message, completionListener);
}
@Override
public void send(Destination destination, Message message,
int deliveryMode, int priority, long timeToLive,
CompletionListener completionListener)
throws JMSException {
if (completionListener == null) {
throw new IllegalArgumentException("CompletionListener must not be null");
}
_send(destination, message, deliveryMode, priority, timeToLive, completionListener);
}
}