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.connection; 018 019import javax.jms.Connection; 020import javax.jms.ConnectionFactory; 021import javax.jms.JMSContext; 022import javax.jms.JMSException; 023import javax.jms.QueueConnection; 024import javax.jms.QueueConnectionFactory; 025import javax.jms.TopicConnection; 026import javax.jms.TopicConnectionFactory; 027 028import org.springframework.beans.factory.InitializingBean; 029import org.springframework.lang.Nullable; 030import org.springframework.util.Assert; 031 032/** 033 * {@link javax.jms.ConnectionFactory} implementation that delegates all calls 034 * to a given target {@link javax.jms.ConnectionFactory}, adapting specific 035 * {@code create(Queue/Topic)Connection} calls to the target ConnectionFactory 036 * if necessary (e.g. when running JMS 1.0.2 API based code against a generic 037 * JMS 1.1 ConnectionFactory, such as ActiveMQ's PooledConnectionFactory). 038 * 039 * <p>As of Spring Framework 5, this class supports JMS 2.0 {@code JMSContext} 040 * calls and therefore requires the JMS 2.0 API to be present at runtime. 041 * It may nevertheless run against a JMS 1.1 driver (bound to the JMS 2.0 API) 042 * as long as no actual JMS 2.0 calls are triggered by the application's setup. 043 * 044 * <p>This class allows for being subclassed, with subclasses overriding only 045 * those methods (such as {@link #createConnection()}) that should not simply 046 * delegate to the target ConnectionFactory. 047 * 048 * <p>Can also be defined as-is, wrapping a specific target ConnectionFactory, 049 * using the "shouldStopConnections" flag to indicate whether Connections 050 * obtained from the target factory are supposed to be stopped before closed. 051 * The latter may be necessary for some connection pools that simply return 052 * released connections to the pool, not stopping them while they sit in the pool. 053 * 054 * @author Juergen Hoeller 055 * @since 2.0.2 056 * @see #createConnection() 057 * @see #setShouldStopConnections 058 * @see ConnectionFactoryUtils#releaseConnection 059 */ 060public class DelegatingConnectionFactory 061 implements SmartConnectionFactory, QueueConnectionFactory, TopicConnectionFactory, InitializingBean { 062 063 @Nullable 064 private ConnectionFactory targetConnectionFactory; 065 066 private boolean shouldStopConnections = false; 067 068 069 /** 070 * Set the target ConnectionFactory that this ConnectionFactory should delegate to. 071 */ 072 public void setTargetConnectionFactory(@Nullable ConnectionFactory targetConnectionFactory) { 073 this.targetConnectionFactory = targetConnectionFactory; 074 } 075 076 /** 077 * Return the target ConnectionFactory that this ConnectionFactory delegates to. 078 */ 079 @Nullable 080 public ConnectionFactory getTargetConnectionFactory() { 081 return this.targetConnectionFactory; 082 } 083 084 private ConnectionFactory obtainTargetConnectionFactory() { 085 ConnectionFactory target = getTargetConnectionFactory(); 086 Assert.state(target != null, "No 'targetConnectionFactory' set"); 087 return target; 088 } 089 090 /** 091 * Indicate whether Connections obtained from the target factory are supposed 092 * to be stopped before closed ("true") or simply closed ("false"). 093 * An extra stop call may be necessary for some connection pools that simply return 094 * released connections to the pool, not stopping them while they sit in the pool. 095 * <p>Default is "false", simply closing Connections. 096 * @see ConnectionFactoryUtils#releaseConnection 097 */ 098 public void setShouldStopConnections(boolean shouldStopConnections) { 099 this.shouldStopConnections = shouldStopConnections; 100 } 101 102 @Override 103 public void afterPropertiesSet() { 104 if (getTargetConnectionFactory() == null) { 105 throw new IllegalArgumentException("'targetConnectionFactory' is required"); 106 } 107 } 108 109 110 @Override 111 public Connection createConnection() throws JMSException { 112 return obtainTargetConnectionFactory().createConnection(); 113 } 114 115 @Override 116 public Connection createConnection(String username, String password) throws JMSException { 117 return obtainTargetConnectionFactory().createConnection(username, password); 118 } 119 120 @Override 121 public QueueConnection createQueueConnection() throws JMSException { 122 ConnectionFactory target = obtainTargetConnectionFactory(); 123 if (target instanceof QueueConnectionFactory) { 124 return ((QueueConnectionFactory) target).createQueueConnection(); 125 } 126 else { 127 Connection con = target.createConnection(); 128 if (!(con instanceof QueueConnection)) { 129 throw new javax.jms.IllegalStateException("'targetConnectionFactory' is not a QueueConnectionFactory"); 130 } 131 return (QueueConnection) con; 132 } 133 } 134 135 @Override 136 public QueueConnection createQueueConnection(String username, String password) throws JMSException { 137 ConnectionFactory target = obtainTargetConnectionFactory(); 138 if (target instanceof QueueConnectionFactory) { 139 return ((QueueConnectionFactory) target).createQueueConnection(username, password); 140 } 141 else { 142 Connection con = target.createConnection(username, password); 143 if (!(con instanceof QueueConnection)) { 144 throw new javax.jms.IllegalStateException("'targetConnectionFactory' is not a QueueConnectionFactory"); 145 } 146 return (QueueConnection) con; 147 } 148 } 149 150 @Override 151 public TopicConnection createTopicConnection() throws JMSException { 152 ConnectionFactory target = obtainTargetConnectionFactory(); 153 if (target instanceof TopicConnectionFactory) { 154 return ((TopicConnectionFactory) target).createTopicConnection(); 155 } 156 else { 157 Connection con = target.createConnection(); 158 if (!(con instanceof TopicConnection)) { 159 throw new javax.jms.IllegalStateException("'targetConnectionFactory' is not a TopicConnectionFactory"); 160 } 161 return (TopicConnection) con; 162 } 163 } 164 165 @Override 166 public TopicConnection createTopicConnection(String username, String password) throws JMSException { 167 ConnectionFactory target = obtainTargetConnectionFactory(); 168 if (target instanceof TopicConnectionFactory) { 169 return ((TopicConnectionFactory) target).createTopicConnection(username, password); 170 } 171 else { 172 Connection con = target.createConnection(username, password); 173 if (!(con instanceof TopicConnection)) { 174 throw new javax.jms.IllegalStateException("'targetConnectionFactory' is not a TopicConnectionFactory"); 175 } 176 return (TopicConnection) con; 177 } 178 } 179 180 @Override 181 public JMSContext createContext() { 182 return obtainTargetConnectionFactory().createContext(); 183 } 184 185 @Override 186 public JMSContext createContext(String userName, String password) { 187 return obtainTargetConnectionFactory().createContext(userName, password); 188 } 189 190 @Override 191 public JMSContext createContext(String userName, String password, int sessionMode) { 192 return obtainTargetConnectionFactory().createContext(userName, password, sessionMode); 193 } 194 195 @Override 196 public JMSContext createContext(int sessionMode) { 197 return obtainTargetConnectionFactory().createContext(sessionMode); 198 } 199 200 @Override 201 public boolean shouldStop(Connection con) { 202 return this.shouldStopConnections; 203 } 204 205}