001/* 002 * Copyright 2002-2018 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; 030import org.springframework.lang.Nullable; 031import org.springframework.util.Assert; 032 033/** 034 * Base class for {@link org.springframework.jms.core.JmsTemplate} and other 035 * JMS-accessing gateway helpers, defining common properties such as the 036 * JMS {@link ConnectionFactory} to operate on. The subclass 037 * {@link org.springframework.jms.support.destination.JmsDestinationAccessor} 038 * adds further, destination-related properties. 039 * 040 * <p>Not intended to be used directly. 041 * See {@link org.springframework.jms.core.JmsTemplate}. 042 * 043 * @author Juergen Hoeller 044 * @since 1.2 045 * @see org.springframework.jms.support.destination.JmsDestinationAccessor 046 * @see org.springframework.jms.core.JmsTemplate 047 */ 048public abstract class JmsAccessor implements InitializingBean { 049 050 /** Constants instance for {@code javax.jms.Session}. */ 051 private static final Constants sessionConstants = new Constants(Session.class); 052 053 054 /** Logger available to subclasses. */ 055 protected final Log logger = LogFactory.getLog(getClass()); 056 057 @Nullable 058 private ConnectionFactory connectionFactory; 059 060 private boolean sessionTransacted = false; 061 062 private int sessionAcknowledgeMode = Session.AUTO_ACKNOWLEDGE; 063 064 065 /** 066 * Set the ConnectionFactory to use for obtaining JMS {@link Connection Connections}. 067 */ 068 public void setConnectionFactory(@Nullable ConnectionFactory connectionFactory) { 069 this.connectionFactory = connectionFactory; 070 } 071 072 /** 073 * Return the ConnectionFactory that this accessor uses for obtaining 074 * JMS {@link Connection Connections}. 075 */ 076 @Nullable 077 public ConnectionFactory getConnectionFactory() { 078 return this.connectionFactory; 079 } 080 081 /** 082 * Obtain the ConnectionFactory for actual use. 083 * @return the ConnectionFactory (never {@code null}) 084 * @throws IllegalStateException in case of no ConnectionFactory set 085 * @since 5.0 086 */ 087 protected final ConnectionFactory obtainConnectionFactory() { 088 ConnectionFactory connectionFactory = getConnectionFactory(); 089 Assert.state(connectionFactory != null, "No ConnectionFactory set"); 090 return connectionFactory; 091 } 092 093 /** 094 * Set the transaction mode that is used when creating a JMS {@link Session}. 095 * Default is "false". 096 * <p>Note that within a JTA transaction, the parameters passed to 097 * {@code create(Queue/Topic)Session(boolean transacted, int acknowledgeMode)} 098 * method are not taken into account. Depending on the Java EE transaction context, 099 * the container makes its own decisions on these values. Analogously, these 100 * parameters are not taken into account within a locally managed transaction 101 * either, since the accessor operates on an existing JMS Session in this case. 102 * <p>Setting this flag to "true" will use a short local JMS transaction 103 * when running outside of a managed transaction, and a synchronized local 104 * JMS transaction in case of a managed transaction (other than an XA 105 * transaction) being present. This has the effect of a local JMS 106 * transaction being managed alongside the main transaction (which might 107 * be a native JDBC transaction), with the JMS transaction committing 108 * right after the main transaction. 109 * @see javax.jms.Connection#createSession(boolean, int) 110 */ 111 public void setSessionTransacted(boolean sessionTransacted) { 112 this.sessionTransacted = sessionTransacted; 113 } 114 115 /** 116 * Return whether the JMS {@link Session sessions} used by this 117 * accessor are supposed to be transacted. 118 * @see #setSessionTransacted(boolean) 119 */ 120 public boolean isSessionTransacted() { 121 return this.sessionTransacted; 122 } 123 124 /** 125 * Set the JMS acknowledgement mode by the name of the corresponding constant 126 * in the JMS {@link Session} interface, e.g. "CLIENT_ACKNOWLEDGE". 127 * <p>If you want to use vendor-specific extensions to the acknowledgment mode, 128 * use {@link #setSessionAcknowledgeMode(int)} instead. 129 * @param constantName the name of the {@link Session} acknowledge mode constant 130 * @see javax.jms.Session#AUTO_ACKNOWLEDGE 131 * @see javax.jms.Session#CLIENT_ACKNOWLEDGE 132 * @see javax.jms.Session#DUPS_OK_ACKNOWLEDGE 133 * @see javax.jms.Connection#createSession(boolean, int) 134 */ 135 public void setSessionAcknowledgeModeName(String constantName) { 136 setSessionAcknowledgeMode(sessionConstants.asNumber(constantName).intValue()); 137 } 138 139 /** 140 * Set the JMS acknowledgement mode that is used when creating a JMS 141 * {@link Session} to send a message. 142 * <p>Default is {@link Session#AUTO_ACKNOWLEDGE}. 143 * <p>Vendor-specific extensions to the acknowledgment mode can be set here as well. 144 * <p>Note that inside an EJB, the parameters to the 145 * {@code create(Queue/Topic)Session(boolean transacted, int acknowledgeMode)} method 146 * are not taken into account. Depending on the transaction context in the EJB, 147 * the container makes its own decisions on these values. See section 17.3.5 148 * of the EJB spec. 149 * @param sessionAcknowledgeMode the acknowledgement mode constant 150 * @see javax.jms.Session#AUTO_ACKNOWLEDGE 151 * @see javax.jms.Session#CLIENT_ACKNOWLEDGE 152 * @see javax.jms.Session#DUPS_OK_ACKNOWLEDGE 153 * @see javax.jms.Connection#createSession(boolean, int) 154 */ 155 public void setSessionAcknowledgeMode(int sessionAcknowledgeMode) { 156 this.sessionAcknowledgeMode = sessionAcknowledgeMode; 157 } 158 159 /** 160 * Return the acknowledgement mode for JMS {@link Session sessions}. 161 */ 162 public int getSessionAcknowledgeMode() { 163 return this.sessionAcknowledgeMode; 164 } 165 166 @Override 167 public void afterPropertiesSet() { 168 if (getConnectionFactory() == null) { 169 throw new IllegalArgumentException("Property 'connectionFactory' is required"); 170 } 171 } 172 173 174 /** 175 * Convert the specified checked {@link javax.jms.JMSException JMSException} to 176 * a Spring runtime {@link org.springframework.jms.JmsException JmsException} 177 * equivalent. 178 * <p>The default implementation delegates to the 179 * {@link JmsUtils#convertJmsAccessException} method. 180 * @param ex the original checked {@link JMSException} to convert 181 * @return the Spring runtime {@link JmsException} wrapping {@code ex} 182 * @see JmsUtils#convertJmsAccessException 183 */ 184 protected JmsException convertJmsAccessException(JMSException ex) { 185 return JmsUtils.convertJmsAccessException(ex); 186 } 187 188 /** 189 * Create a JMS Connection via this template's ConnectionFactory. 190 * <p>This implementation uses JMS 1.1 API. 191 * @return the new JMS Connection 192 * @throws JMSException if thrown by JMS API methods 193 * @see javax.jms.ConnectionFactory#createConnection() 194 */ 195 protected Connection createConnection() throws JMSException { 196 return obtainConnectionFactory().createConnection(); 197 } 198 199 /** 200 * Create a JMS Session for the given Connection. 201 * <p>This implementation uses JMS 1.1 API. 202 * @param con the JMS Connection to create a Session for 203 * @return the new JMS Session 204 * @throws JMSException if thrown by JMS API methods 205 * @see javax.jms.Connection#createSession(boolean, int) 206 */ 207 protected Session createSession(Connection con) throws JMSException { 208 return con.createSession(isSessionTransacted(), getSessionAcknowledgeMode()); 209 } 210 211 /** 212 * Determine whether the given Session is in client acknowledge mode. 213 * <p>This implementation uses JMS 1.1 API. 214 * @param session the JMS Session to check 215 * @return whether the given Session is in client acknowledge mode 216 * @throws javax.jms.JMSException if thrown by JMS API methods 217 * @see javax.jms.Session#getAcknowledgeMode() 218 * @see javax.jms.Session#CLIENT_ACKNOWLEDGE 219 */ 220 protected boolean isClientAcknowledge(Session session) throws JMSException { 221 return (session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE); 222 } 223 224}