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