001/*
002 * Copyright 2002-2015 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.jms.support;
018
019import javax.jms.Connection;
020import javax.jms.ConnectionFactory;
021import javax.jms.JMSException;
022import javax.jms.Session;
023
024import org.apache.commons.logging.Log;
025import org.apache.commons.logging.LogFactory;
026
027import org.springframework.beans.factory.InitializingBean;
028import org.springframework.core.Constants;
029import org.springframework.jms.JmsException;
030
031/**
032 * Base class for {@link org.springframework.jms.core.JmsTemplate} and other
033 * JMS-accessing gateway helpers, defining common properties such as the
034 * JMS {@link ConnectionFactory} to operate on. The subclass
035 * {@link org.springframework.jms.support.destination.JmsDestinationAccessor}
036 * adds further, destination-related properties.
037 *
038 * <p>Not intended to be used directly.
039 * See {@link org.springframework.jms.core.JmsTemplate}.
040 *
041 * @author Juergen Hoeller
042 * @since 1.2
043 * @see org.springframework.jms.support.destination.JmsDestinationAccessor
044 * @see org.springframework.jms.core.JmsTemplate
045 */
046public abstract class JmsAccessor implements InitializingBean {
047
048        /** Constants instance for javax.jms.Session */
049        private static final Constants sessionConstants = new Constants(Session.class);
050
051
052        /** Logger available to subclasses */
053        protected final Log logger = LogFactory.getLog(getClass());
054
055        private ConnectionFactory connectionFactory;
056
057        private boolean sessionTransacted = false;
058
059        private int sessionAcknowledgeMode = Session.AUTO_ACKNOWLEDGE;
060
061
062        /**
063         * Set the ConnectionFactory to use for obtaining JMS {@link Connection Connections}.
064         */
065        public void setConnectionFactory(ConnectionFactory connectionFactory) {
066                this.connectionFactory = connectionFactory;
067        }
068
069        /**
070         * Return the ConnectionFactory that this accessor uses for obtaining
071         * JMS {@link Connection Connections}.
072         */
073        public ConnectionFactory getConnectionFactory() {
074                return this.connectionFactory;
075        }
076
077        /**
078         * Set the transaction mode that is used when creating a JMS {@link Session}.
079         * Default is "false".
080         * <p>Note that within a JTA transaction, the parameters passed to
081         * {@code create(Queue/Topic)Session(boolean transacted, int acknowledgeMode)}
082         * method are not taken into account. Depending on the Java EE transaction context,
083         * the container makes its own decisions on these values. Analogously, these
084         * parameters are not taken into account within a locally managed transaction
085         * either, since the accessor operates on an existing JMS Session in this case.
086         * <p>Setting this flag to "true" will use a short local JMS transaction
087         * when running outside of a managed transaction, and a synchronized local
088         * JMS transaction in case of a managed transaction (other than an XA
089         * transaction) being present. This has the effect of a local JMS
090         * transaction being managed alongside the main transaction (which might
091         * be a native JDBC transaction), with the JMS transaction committing
092         * right after the main transaction.
093         * @see javax.jms.Connection#createSession(boolean, int)
094         */
095        public void setSessionTransacted(boolean sessionTransacted) {
096                this.sessionTransacted = sessionTransacted;
097        }
098
099        /**
100         * Return whether the JMS {@link Session sessions} used by this
101         * accessor are supposed to be transacted.
102         * @see #setSessionTransacted(boolean)
103         */
104        public boolean isSessionTransacted() {
105                return this.sessionTransacted;
106        }
107
108        /**
109         * Set the JMS acknowledgement mode by the name of the corresponding constant
110         * in the JMS {@link Session} interface, e.g. "CLIENT_ACKNOWLEDGE".
111         * <p>If you want to use vendor-specific extensions to the acknowledgment mode,
112         * use {@link #setSessionAcknowledgeMode(int)} instead.
113         * @param constantName the name of the {@link Session} acknowledge mode constant
114         * @see javax.jms.Session#AUTO_ACKNOWLEDGE
115         * @see javax.jms.Session#CLIENT_ACKNOWLEDGE
116         * @see javax.jms.Session#DUPS_OK_ACKNOWLEDGE
117         * @see javax.jms.Connection#createSession(boolean, int)
118         */
119        public void setSessionAcknowledgeModeName(String constantName) {
120                setSessionAcknowledgeMode(sessionConstants.asNumber(constantName).intValue());
121        }
122
123        /**
124         * Set the JMS acknowledgement mode that is used when creating a JMS
125         * {@link Session} to send a message.
126         * <p>Default is {@link Session#AUTO_ACKNOWLEDGE}.
127         * <p>Vendor-specific extensions to the acknowledgment mode can be set here as well.
128         * <p>Note that inside an EJB, the parameters to the
129         * {@code create(Queue/Topic)Session(boolean transacted, int acknowledgeMode)} method
130         * are not taken into account. Depending on the transaction context in the EJB,
131         * the container makes its own decisions on these values. See section 17.3.5
132         * of the EJB spec.
133         * @param sessionAcknowledgeMode the acknowledgement mode constant
134         * @see javax.jms.Session#AUTO_ACKNOWLEDGE
135         * @see javax.jms.Session#CLIENT_ACKNOWLEDGE
136         * @see javax.jms.Session#DUPS_OK_ACKNOWLEDGE
137         * @see javax.jms.Connection#createSession(boolean, int)
138         */
139        public void setSessionAcknowledgeMode(int sessionAcknowledgeMode) {
140                this.sessionAcknowledgeMode = sessionAcknowledgeMode;
141        }
142
143        /**
144         * Return the acknowledgement mode for JMS {@link Session sessions}.
145         */
146        public int getSessionAcknowledgeMode() {
147                return this.sessionAcknowledgeMode;
148        }
149
150        @Override
151        public void afterPropertiesSet() {
152                if (getConnectionFactory() == null) {
153                        throw new IllegalArgumentException("Property 'connectionFactory' is required");
154                }
155        }
156
157
158        /**
159         * Convert the specified checked {@link javax.jms.JMSException JMSException} to
160         * a Spring runtime {@link org.springframework.jms.JmsException JmsException}
161         * equivalent.
162         * <p>The default implementation delegates to the
163         * {@link JmsUtils#convertJmsAccessException} method.
164         * @param ex the original checked {@link JMSException} to convert
165         * @return the Spring runtime {@link JmsException} wrapping {@code ex}
166         * @see JmsUtils#convertJmsAccessException
167         */
168        protected JmsException convertJmsAccessException(JMSException ex) {
169                return JmsUtils.convertJmsAccessException(ex);
170        }
171
172        /**
173         * Create a JMS Connection via this template's ConnectionFactory.
174         * <p>This implementation uses JMS 1.1 API.
175         * @return the new JMS Connection
176         * @throws JMSException if thrown by JMS API methods
177         * @see javax.jms.ConnectionFactory#createConnection()
178         */
179        protected Connection createConnection() throws JMSException {
180                return getConnectionFactory().createConnection();
181        }
182
183        /**
184         * Create a JMS Session for the given Connection.
185         * <p>This implementation uses JMS 1.1 API.
186         * @param con the JMS Connection to create a Session for
187         * @return the new JMS Session
188         * @throws JMSException if thrown by JMS API methods
189         * @see javax.jms.Connection#createSession(boolean, int)
190         */
191        protected Session createSession(Connection con) throws JMSException {
192                return con.createSession(isSessionTransacted(), getSessionAcknowledgeMode());
193        }
194
195        /**
196         * Determine whether the given Session is in client acknowledge mode.
197         * <p>This implementation uses JMS 1.1 API.
198         * @param session the JMS Session to check
199         * @return whether the given Session is in client acknowledge mode
200         * @throws javax.jms.JMSException if thrown by JMS API methods
201         * @see javax.jms.Session#getAcknowledgeMode()
202         * @see javax.jms.Session#CLIENT_ACKNOWLEDGE
203         */
204        protected boolean isClientAcknowledge(Session session) throws JMSException {
205                return (session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE);
206        }
207
208}