001/* 002 * Copyright 2002-2012 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.JMSException; 021import javax.jms.MessageConsumer; 022import javax.jms.MessageProducer; 023import javax.jms.QueueBrowser; 024import javax.jms.QueueRequestor; 025import javax.jms.Session; 026 027import org.apache.commons.logging.Log; 028import org.apache.commons.logging.LogFactory; 029 030import org.springframework.jms.InvalidClientIDException; 031import org.springframework.jms.InvalidDestinationException; 032import org.springframework.jms.InvalidSelectorException; 033import org.springframework.jms.JmsException; 034import org.springframework.jms.JmsSecurityException; 035import org.springframework.jms.MessageEOFException; 036import org.springframework.jms.MessageFormatException; 037import org.springframework.jms.MessageNotReadableException; 038import org.springframework.jms.MessageNotWriteableException; 039import org.springframework.jms.ResourceAllocationException; 040import org.springframework.jms.TransactionInProgressException; 041import org.springframework.jms.TransactionRolledBackException; 042import org.springframework.jms.UncategorizedJmsException; 043import org.springframework.lang.Nullable; 044import org.springframework.util.Assert; 045 046/** 047 * Generic utility methods for working with JMS. Mainly for internal use 048 * within the framework, but also useful for custom JMS access code. 049 * 050 * @author Juergen Hoeller 051 * @since 1.1 052 */ 053public abstract class JmsUtils { 054 055 private static final Log logger = LogFactory.getLog(JmsUtils.class); 056 057 058 /** 059 * Close the given JMS Connection and ignore any thrown exception. 060 * This is useful for typical {@code finally} blocks in manual JMS code. 061 * @param con the JMS Connection to close (may be {@code null}) 062 */ 063 public static void closeConnection(@Nullable Connection con) { 064 closeConnection(con, false); 065 } 066 067 /** 068 * Close the given JMS Connection and ignore any thrown exception. 069 * This is useful for typical {@code finally} blocks in manual JMS code. 070 * @param con the JMS Connection to close (may be {@code null}) 071 * @param stop whether to call {@code stop()} before closing 072 */ 073 public static void closeConnection(@Nullable Connection con, boolean stop) { 074 if (con != null) { 075 try { 076 if (stop) { 077 try { 078 con.stop(); 079 } 080 finally { 081 con.close(); 082 } 083 } 084 else { 085 con.close(); 086 } 087 } 088 catch (javax.jms.IllegalStateException ex) { 089 logger.debug("Ignoring Connection state exception - assuming already closed: " + ex); 090 } 091 catch (JMSException ex) { 092 logger.debug("Could not close JMS Connection", ex); 093 } 094 catch (Throwable ex) { 095 // We don't trust the JMS provider: It might throw RuntimeException or Error. 096 logger.debug("Unexpected exception on closing JMS Connection", ex); 097 } 098 } 099 } 100 101 /** 102 * Close the given JMS Session and ignore any thrown exception. 103 * This is useful for typical {@code finally} blocks in manual JMS code. 104 * @param session the JMS Session to close (may be {@code null}) 105 */ 106 public static void closeSession(@Nullable Session session) { 107 if (session != null) { 108 try { 109 session.close(); 110 } 111 catch (JMSException ex) { 112 logger.trace("Could not close JMS Session", ex); 113 } 114 catch (Throwable ex) { 115 // We don't trust the JMS provider: It might throw RuntimeException or Error. 116 logger.trace("Unexpected exception on closing JMS Session", ex); 117 } 118 } 119 } 120 121 /** 122 * Close the given JMS MessageProducer and ignore any thrown exception. 123 * This is useful for typical {@code finally} blocks in manual JMS code. 124 * @param producer the JMS MessageProducer to close (may be {@code null}) 125 */ 126 public static void closeMessageProducer(@Nullable MessageProducer producer) { 127 if (producer != null) { 128 try { 129 producer.close(); 130 } 131 catch (JMSException ex) { 132 logger.trace("Could not close JMS MessageProducer", ex); 133 } 134 catch (Throwable ex) { 135 // We don't trust the JMS provider: It might throw RuntimeException or Error. 136 logger.trace("Unexpected exception on closing JMS MessageProducer", ex); 137 } 138 } 139 } 140 141 /** 142 * Close the given JMS MessageConsumer and ignore any thrown exception. 143 * This is useful for typical {@code finally} blocks in manual JMS code. 144 * @param consumer the JMS MessageConsumer to close (may be {@code null}) 145 */ 146 public static void closeMessageConsumer(@Nullable MessageConsumer consumer) { 147 if (consumer != null) { 148 // Clear interruptions to ensure that the consumer closes successfully... 149 // (working around misbehaving JMS providers such as ActiveMQ) 150 boolean wasInterrupted = Thread.interrupted(); 151 try { 152 consumer.close(); 153 } 154 catch (JMSException ex) { 155 logger.trace("Could not close JMS MessageConsumer", ex); 156 } 157 catch (Throwable ex) { 158 // We don't trust the JMS provider: It might throw RuntimeException or Error. 159 logger.trace("Unexpected exception on closing JMS MessageConsumer", ex); 160 } 161 finally { 162 if (wasInterrupted) { 163 // Reset the interrupted flag as it was before. 164 Thread.currentThread().interrupt(); 165 } 166 } 167 } 168 } 169 170 /** 171 * Close the given JMS QueueBrowser and ignore any thrown exception. 172 * This is useful for typical {@code finally} blocks in manual JMS code. 173 * @param browser the JMS QueueBrowser to close (may be {@code null}) 174 */ 175 public static void closeQueueBrowser(@Nullable QueueBrowser browser) { 176 if (browser != null) { 177 try { 178 browser.close(); 179 } 180 catch (JMSException ex) { 181 logger.trace("Could not close JMS QueueBrowser", ex); 182 } 183 catch (Throwable ex) { 184 // We don't trust the JMS provider: It might throw RuntimeException or Error. 185 logger.trace("Unexpected exception on closing JMS QueueBrowser", ex); 186 } 187 } 188 } 189 190 /** 191 * Close the given JMS QueueRequestor and ignore any thrown exception. 192 * This is useful for typical {@code finally} blocks in manual JMS code. 193 * @param requestor the JMS QueueRequestor to close (may be {@code null}) 194 */ 195 public static void closeQueueRequestor(@Nullable QueueRequestor requestor) { 196 if (requestor != null) { 197 try { 198 requestor.close(); 199 } 200 catch (JMSException ex) { 201 logger.trace("Could not close JMS QueueRequestor", ex); 202 } 203 catch (Throwable ex) { 204 // We don't trust the JMS provider: It might throw RuntimeException or Error. 205 logger.trace("Unexpected exception on closing JMS QueueRequestor", ex); 206 } 207 } 208 } 209 210 /** 211 * Commit the Session if not within a JTA transaction. 212 * @param session the JMS Session to commit 213 * @throws JMSException if committing failed 214 */ 215 public static void commitIfNecessary(Session session) throws JMSException { 216 Assert.notNull(session, "Session must not be null"); 217 try { 218 session.commit(); 219 } 220 catch (javax.jms.TransactionInProgressException | javax.jms.IllegalStateException ex) { 221 // Ignore -> can only happen in case of a JTA transaction. 222 } 223 } 224 225 /** 226 * Rollback the Session if not within a JTA transaction. 227 * @param session the JMS Session to rollback 228 * @throws JMSException if committing failed 229 */ 230 public static void rollbackIfNecessary(Session session) throws JMSException { 231 Assert.notNull(session, "Session must not be null"); 232 try { 233 session.rollback(); 234 } 235 catch (javax.jms.TransactionInProgressException | javax.jms.IllegalStateException ex) { 236 // Ignore -> can only happen in case of a JTA transaction. 237 } 238 } 239 240 /** 241 * Build a descriptive exception message for the given JMSException, 242 * incorporating a linked exception's message if appropriate. 243 * @param ex the JMSException to build a message for 244 * @return the descriptive message String 245 * @see javax.jms.JMSException#getLinkedException() 246 */ 247 public static String buildExceptionMessage(JMSException ex) { 248 String message = ex.getMessage(); 249 Exception linkedEx = ex.getLinkedException(); 250 if (linkedEx != null) { 251 if (message == null) { 252 message = linkedEx.toString(); 253 } 254 else { 255 String linkedMessage = linkedEx.getMessage(); 256 if (linkedMessage != null && !message.contains(linkedMessage)) { 257 message = message + "; nested exception is " + linkedEx; 258 } 259 } 260 } 261 return message; 262 } 263 264 /** 265 * Convert the specified checked {@link javax.jms.JMSException JMSException} to a 266 * Spring runtime {@link org.springframework.jms.JmsException JmsException} equivalent. 267 * @param ex the original checked JMSException to convert 268 * @return the Spring runtime JmsException wrapping the given exception 269 */ 270 public static JmsException convertJmsAccessException(JMSException ex) { 271 Assert.notNull(ex, "JMSException must not be null"); 272 273 if (ex instanceof javax.jms.IllegalStateException) { 274 return new org.springframework.jms.IllegalStateException((javax.jms.IllegalStateException) ex); 275 } 276 if (ex instanceof javax.jms.InvalidClientIDException) { 277 return new InvalidClientIDException((javax.jms.InvalidClientIDException) ex); 278 } 279 if (ex instanceof javax.jms.InvalidDestinationException) { 280 return new InvalidDestinationException((javax.jms.InvalidDestinationException) ex); 281 } 282 if (ex instanceof javax.jms.InvalidSelectorException) { 283 return new InvalidSelectorException((javax.jms.InvalidSelectorException) ex); 284 } 285 if (ex instanceof javax.jms.JMSSecurityException) { 286 return new JmsSecurityException((javax.jms.JMSSecurityException) ex); 287 } 288 if (ex instanceof javax.jms.MessageEOFException) { 289 return new MessageEOFException((javax.jms.MessageEOFException) ex); 290 } 291 if (ex instanceof javax.jms.MessageFormatException) { 292 return new MessageFormatException((javax.jms.MessageFormatException) ex); 293 } 294 if (ex instanceof javax.jms.MessageNotReadableException) { 295 return new MessageNotReadableException((javax.jms.MessageNotReadableException) ex); 296 } 297 if (ex instanceof javax.jms.MessageNotWriteableException) { 298 return new MessageNotWriteableException((javax.jms.MessageNotWriteableException) ex); 299 } 300 if (ex instanceof javax.jms.ResourceAllocationException) { 301 return new ResourceAllocationException((javax.jms.ResourceAllocationException) ex); 302 } 303 if (ex instanceof javax.jms.TransactionInProgressException) { 304 return new TransactionInProgressException((javax.jms.TransactionInProgressException) ex); 305 } 306 if (ex instanceof javax.jms.TransactionRolledBackException) { 307 return new TransactionRolledBackException((javax.jms.TransactionRolledBackException) ex); 308 } 309 310 // fallback 311 return new UncategorizedJmsException(ex); 312 } 313 314}