EL container integration; support for contextual objects; removal of deprecated Spring 2.0 functionality; Java 5 code style
This commit is contained in:
@@ -1,179 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jms.listener.serversession;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.ServerSession;
|
||||
import javax.jms.Session;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.jms.support.JmsUtils;
|
||||
import org.springframework.scheduling.timer.TimerTaskExecutor;
|
||||
|
||||
/**
|
||||
* Abstract base class for ServerSessionFactory implementations
|
||||
* that pool ServerSessionFactory instances.
|
||||
*
|
||||
* <p>Provides a factory method that creates a poolable ServerSession
|
||||
* (to be added as new instance to a pool), a callback method invoked
|
||||
* when a ServerSession finished an execution of its listener (to return
|
||||
* an instance to the pool), and a method to destroy a ServerSession instance
|
||||
* (after removing an instance from the pool).
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
|
||||
* and JmsMessageEndpointManager. To be removed in Spring 3.0.
|
||||
* @see org.springframework.jms.listener.serversession.CommonsPoolServerSessionFactory
|
||||
*/
|
||||
public abstract class AbstractPoolingServerSessionFactory implements ServerSessionFactory {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private TaskExecutor taskExecutor;
|
||||
|
||||
private int maxSize;
|
||||
|
||||
|
||||
/**
|
||||
* Specify the TaskExecutor to use for executing ServerSessions
|
||||
* (and consequently, the underlying MessageListener).
|
||||
* <p>Default is a {@link org.springframework.scheduling.timer.TimerTaskExecutor}
|
||||
* for each pooled ServerSession, using one Thread per pooled JMS Session.
|
||||
* Alternatives are a shared TimerTaskExecutor, sharing a single Thread
|
||||
* for the execution of all ServerSessions, or a TaskExecutor
|
||||
* implementation backed by a thread pool.
|
||||
*/
|
||||
public void setTaskExecutor(TaskExecutor taskExecutor) {
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TaskExecutor to use for executing ServerSessions.
|
||||
*/
|
||||
protected TaskExecutor getTaskExecutor() {
|
||||
return this.taskExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum size of the pool.
|
||||
*/
|
||||
public void setMaxSize(int maxSize) {
|
||||
this.maxSize = maxSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum size of the pool.
|
||||
*/
|
||||
public int getMaxSize() {
|
||||
return this.maxSize;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new poolable ServerSession.
|
||||
* To be called when a new instance should be added to the pool.
|
||||
* @param sessionManager the listener session manager to create the
|
||||
* poolable ServerSession for
|
||||
* @return the new poolable ServerSession
|
||||
* @throws JMSException if creation failed
|
||||
*/
|
||||
protected final ServerSession createServerSession(ListenerSessionManager sessionManager) throws JMSException {
|
||||
return new PoolableServerSession(sessionManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the given poolable ServerSession.
|
||||
* To be called when an instance got removed from the pool.
|
||||
* @param serverSession the poolable ServerSession to destroy
|
||||
*/
|
||||
protected final void destroyServerSession(ServerSession serverSession) {
|
||||
if (serverSession != null) {
|
||||
((PoolableServerSession) serverSession).close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Template method called by a ServerSession if it finished
|
||||
* execution of its listener and is ready to go back into the pool.
|
||||
* <p>Subclasses should implement the actual returning of the instance
|
||||
* to the pool.
|
||||
* @param serverSession the ServerSession that finished its execution
|
||||
* @param sessionManager the session manager that the ServerSession belongs to
|
||||
*/
|
||||
protected abstract void serverSessionFinished(
|
||||
ServerSession serverSession, ListenerSessionManager sessionManager);
|
||||
|
||||
|
||||
/**
|
||||
* ServerSession implementation designed to be pooled.
|
||||
* Creates a new JMS Session on instantiation, reuses it
|
||||
* for all executions, and closes it on <code>close</code>.
|
||||
* <p>Creates a TimerTaskExecutor (using a single Thread) per
|
||||
* ServerSession, unless given a specific TaskExecutor to use.
|
||||
*/
|
||||
private class PoolableServerSession implements ServerSession {
|
||||
|
||||
private final ListenerSessionManager sessionManager;
|
||||
|
||||
private final Session session;
|
||||
|
||||
private TaskExecutor taskExecutor;
|
||||
|
||||
private TimerTaskExecutor internalExecutor;
|
||||
|
||||
public PoolableServerSession(final ListenerSessionManager sessionManager) throws JMSException {
|
||||
this.sessionManager = sessionManager;
|
||||
this.session = sessionManager.createListenerSession();
|
||||
this.taskExecutor = getTaskExecutor();
|
||||
if (this.taskExecutor == null) {
|
||||
this.internalExecutor = new TimerTaskExecutor();
|
||||
this.internalExecutor.afterPropertiesSet();
|
||||
this.taskExecutor = this.internalExecutor;
|
||||
}
|
||||
}
|
||||
|
||||
public Session getSession() {
|
||||
return this.session;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
this.taskExecutor.execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
sessionManager.executeListenerSession(session);
|
||||
}
|
||||
finally {
|
||||
serverSessionFinished(PoolableServerSession.this, sessionManager);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (this.internalExecutor != null) {
|
||||
this.internalExecutor.destroy();
|
||||
}
|
||||
JmsUtils.closeSession(this.session);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,274 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jms.listener.serversession;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.ServerSession;
|
||||
|
||||
import org.apache.commons.pool.ObjectPool;
|
||||
import org.apache.commons.pool.PoolableObjectFactory;
|
||||
import org.apache.commons.pool.impl.GenericObjectPool;
|
||||
|
||||
/**
|
||||
* {@link ServerSessionFactory} implementation that holds JMS
|
||||
* <code>ServerSessions</code> in a configurable Jakarta Commons Pool.
|
||||
*
|
||||
* <p>By default, an instance of <code>GenericObjectPool</code> is created.
|
||||
* Subclasses may change the type of <code>ObjectPool</code> used by
|
||||
* overriding the <code>createObjectPool</code> method.
|
||||
*
|
||||
* <p>Provides many configuration properties mirroring those of the Commons Pool
|
||||
* <code>GenericObjectPool</code> class; these properties are passed to the
|
||||
* <code>GenericObjectPool</code> during construction. If creating a subclass of this
|
||||
* class to change the <code>ObjectPool</code> implementation type, pass in the values
|
||||
* of configuration properties that are relevant to your chosen implementation.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
|
||||
* and JmsMessageEndpointManager. To be removed in Spring 3.0.
|
||||
* @see GenericObjectPool
|
||||
* @see #createObjectPool
|
||||
* @see #setMaxSize
|
||||
* @see #setMaxIdle
|
||||
* @see #setMinIdle
|
||||
* @see #setMaxWait
|
||||
*/
|
||||
public class CommonsPoolServerSessionFactory extends AbstractPoolingServerSessionFactory {
|
||||
|
||||
private int maxIdle = GenericObjectPool.DEFAULT_MAX_IDLE;
|
||||
|
||||
private int minIdle = GenericObjectPool.DEFAULT_MIN_IDLE;
|
||||
|
||||
private long maxWait = GenericObjectPool.DEFAULT_MAX_WAIT;
|
||||
|
||||
private long timeBetweenEvictionRunsMillis = GenericObjectPool.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
|
||||
|
||||
private long minEvictableIdleTimeMillis = GenericObjectPool.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
|
||||
|
||||
private final Map serverSessionPools = Collections.synchronizedMap(new HashMap(1));
|
||||
|
||||
|
||||
/**
|
||||
* Create a CommonsPoolServerSessionFactory with default settings.
|
||||
* Default maximum size of the pool is 8.
|
||||
* @see #setMaxSize
|
||||
* @see GenericObjectPool#setMaxActive
|
||||
*/
|
||||
public CommonsPoolServerSessionFactory() {
|
||||
setMaxSize(GenericObjectPool.DEFAULT_MAX_ACTIVE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the maximum number of idle ServerSessions in the pool.
|
||||
* Default is 8.
|
||||
* @see GenericObjectPool#setMaxIdle
|
||||
*/
|
||||
public void setMaxIdle(int maxIdle) {
|
||||
this.maxIdle = maxIdle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of idle ServerSessions in the pool.
|
||||
*/
|
||||
public int getMaxIdle() {
|
||||
return this.maxIdle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum number of idle ServerSessions in the pool.
|
||||
* Default is 0.
|
||||
* @see GenericObjectPool#setMinIdle
|
||||
*/
|
||||
public void setMinIdle(int minIdle) {
|
||||
this.minIdle = minIdle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum number of idle ServerSessions in the pool.
|
||||
*/
|
||||
public int getMinIdle() {
|
||||
return this.minIdle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum waiting time for fetching an ServerSession from the pool.
|
||||
* Default is -1, waiting forever.
|
||||
* @see GenericObjectPool#setMaxWait
|
||||
*/
|
||||
public void setMaxWait(long maxWait) {
|
||||
this.maxWait = maxWait;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum waiting time for fetching a ServerSession from the pool.
|
||||
*/
|
||||
public long getMaxWait() {
|
||||
return this.maxWait;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the time between eviction runs that check idle ServerSessions
|
||||
* whether they have been idle for too long or have become invalid.
|
||||
* Default is -1, not performing any eviction.
|
||||
* @see GenericObjectPool#setTimeBetweenEvictionRunsMillis
|
||||
*/
|
||||
public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
|
||||
this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the time between eviction runs that check idle ServerSessions.
|
||||
*/
|
||||
public long getTimeBetweenEvictionRunsMillis() {
|
||||
return this.timeBetweenEvictionRunsMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the minimum time that an idle ServerSession can sit in the pool
|
||||
* before it becomes subject to eviction. Default is 1800000 (30 minutes).
|
||||
* <p>Note that eviction runs need to be performed to take this
|
||||
* setting into effect.
|
||||
* @see #setTimeBetweenEvictionRunsMillis
|
||||
* @see GenericObjectPool#setMinEvictableIdleTimeMillis
|
||||
*/
|
||||
public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
|
||||
this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the minimum time that an idle ServerSession can sit in the pool.
|
||||
*/
|
||||
public long getMinEvictableIdleTimeMillis() {
|
||||
return this.minEvictableIdleTimeMillis;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a ServerSession from the pool, creating a new pool for the given
|
||||
* session manager if necessary.
|
||||
* @see #createObjectPool
|
||||
*/
|
||||
public ServerSession getServerSession(ListenerSessionManager sessionManager) throws JMSException {
|
||||
ObjectPool pool = null;
|
||||
synchronized (this.serverSessionPools) {
|
||||
pool = (ObjectPool) this.serverSessionPools.get(sessionManager);
|
||||
if (pool == null) {
|
||||
if (logger.isInfoEnabled()) {
|
||||
logger.info("Creating Commons ServerSession pool for: " + sessionManager);
|
||||
}
|
||||
pool = createObjectPool(sessionManager);
|
||||
this.serverSessionPools.put(sessionManager, pool);
|
||||
}
|
||||
}
|
||||
try {
|
||||
return (ServerSession) pool.borrowObject();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
JMSException jmsEx = new JMSException("Failed to borrow ServerSession from pool");
|
||||
jmsEx.setLinkedException(ex);
|
||||
throw jmsEx;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses can override this if they want to return a specific Commons pool.
|
||||
* They should apply any configuration properties to the pool here.
|
||||
* <p>Default is a GenericObjectPool instance with the given pool size.
|
||||
* @param sessionManager the session manager to use for
|
||||
* creating and executing new listener sessions
|
||||
* @return an empty Commons <code>ObjectPool</code>.
|
||||
* @see org.apache.commons.pool.impl.GenericObjectPool
|
||||
* @see #setMaxSize
|
||||
*/
|
||||
protected ObjectPool createObjectPool(ListenerSessionManager sessionManager) {
|
||||
GenericObjectPool pool = new GenericObjectPool(createPoolableObjectFactory(sessionManager));
|
||||
pool.setMaxActive(getMaxSize());
|
||||
pool.setMaxIdle(getMaxIdle());
|
||||
pool.setMinIdle(getMinIdle());
|
||||
pool.setMaxWait(getMaxWait());
|
||||
pool.setTimeBetweenEvictionRunsMillis(getTimeBetweenEvictionRunsMillis());
|
||||
pool.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis());
|
||||
return pool;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a Commons PoolableObjectFactory adapter for the given session manager.
|
||||
* Calls <code>createServerSession</code> and <code>destroyServerSession</code>
|
||||
* as defined by the AbstractPoolingServerSessionFactory class.
|
||||
* @param sessionManager the session manager to use for
|
||||
* creating and executing new listener sessions
|
||||
* @return the Commons PoolableObjectFactory
|
||||
* @see #createServerSession
|
||||
* @see #destroyServerSession
|
||||
*/
|
||||
protected PoolableObjectFactory createPoolableObjectFactory(final ListenerSessionManager sessionManager) {
|
||||
return new PoolableObjectFactory() {
|
||||
public Object makeObject() throws JMSException {
|
||||
return createServerSession(sessionManager);
|
||||
}
|
||||
public void destroyObject(Object obj) {
|
||||
destroyServerSession((ServerSession) obj);
|
||||
}
|
||||
public boolean validateObject(Object obj) {
|
||||
return true;
|
||||
}
|
||||
public void activateObject(Object obj) {
|
||||
}
|
||||
public void passivateObject(Object obj) {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the given ServerSession, which just finished an execution
|
||||
* of its listener, back to the pool.
|
||||
*/
|
||||
protected void serverSessionFinished(ServerSession serverSession, ListenerSessionManager sessionManager) {
|
||||
ObjectPool pool = (ObjectPool) this.serverSessionPools.get(sessionManager);
|
||||
if (pool == null) {
|
||||
throw new IllegalStateException("No pool found for session manager [" + sessionManager + "]");
|
||||
}
|
||||
try {
|
||||
pool.returnObject(serverSession);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.error("Failed to return ServerSession to pool", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes and removes the pool for the given session manager.
|
||||
*/
|
||||
public void close(ListenerSessionManager sessionManager) {
|
||||
ObjectPool pool = (ObjectPool) this.serverSessionPools.remove(sessionManager);
|
||||
if (pool != null) {
|
||||
try {
|
||||
pool.close();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.error("Failed to close ServerSession pool", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jms.listener.serversession;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.Session;
|
||||
|
||||
/**
|
||||
* SPI interface for creating and executing JMS Sessions,
|
||||
* pre-populated with a specific MessageListener.
|
||||
* Implemented by ServerSessionMessageListenerContainer,
|
||||
* accessed by ServerSessionFactory implementations.
|
||||
*
|
||||
* <p>Effectively, an instance that implements this interface
|
||||
* represents a message listener container for a specific
|
||||
* listener and destination.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
|
||||
* and JmsMessageEndpointManager. To be removed in Spring 3.0.
|
||||
* @see ServerSessionFactory
|
||||
* @see ServerSessionMessageListenerContainer
|
||||
*/
|
||||
public interface ListenerSessionManager {
|
||||
|
||||
/**
|
||||
* Create a new JMS Session, pre-populated with this manager's
|
||||
* MessageListener.
|
||||
* @return the new JMS Session
|
||||
* @throws JMSException if Session creation failed
|
||||
* @see javax.jms.Session#setMessageListener(javax.jms.MessageListener)
|
||||
*/
|
||||
Session createListenerSession() throws JMSException;
|
||||
|
||||
/**
|
||||
* Execute the given JMS Session, triggering its MessageListener
|
||||
* with pre-loaded messages.
|
||||
* @param session the JMS Session to invoke
|
||||
* @see javax.jms.Session#run()
|
||||
*/
|
||||
void executeListenerSession(Session session);
|
||||
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jms.listener.serversession;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.ServerSession;
|
||||
|
||||
import org.springframework.jms.listener.serversession.ListenerSessionManager;
|
||||
|
||||
/**
|
||||
* SPI interface to be implemented by components that manage
|
||||
* JMS ServerSessions. Usually, but not necessarily, an implementation
|
||||
* of this interface will hold a pool of ServerSessions.
|
||||
*
|
||||
* <p>The passed-in ListenerSessionManager has to be used for creating
|
||||
* and executing JMS Sessions. This session manager is responsible for
|
||||
* registering a MessageListener with all Sessions that it creates.
|
||||
* Consequently, the ServerSessionFactory implementation has to
|
||||
* concentrate on the actual lifecycle (e.g. pooling) of JMS Sessions,
|
||||
* but is not concerned about Session creation or execution.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
|
||||
* and JmsMessageEndpointManager. To be removed in Spring 3.0.
|
||||
* @see org.springframework.jms.listener.serversession.ListenerSessionManager
|
||||
* @see org.springframework.jms.listener.serversession.ServerSessionMessageListenerContainer
|
||||
*/
|
||||
public interface ServerSessionFactory {
|
||||
|
||||
/**
|
||||
* Retrieve a JMS ServerSession for the given session manager.
|
||||
* @param sessionManager the session manager to use for
|
||||
* creating and executing new listener sessions
|
||||
* (implicitly indicating the target listener to invoke)
|
||||
* @return the JMS ServerSession
|
||||
* @throws JMSException if retrieval failed
|
||||
*/
|
||||
ServerSession getServerSession(ListenerSessionManager sessionManager) throws JMSException;
|
||||
|
||||
/**
|
||||
* Close all ServerSessions for the given session manager.
|
||||
* @param sessionManager the session manager used for
|
||||
* creating and executing new listener sessions
|
||||
* (implicitly indicating the target listener)
|
||||
*/
|
||||
void close(ListenerSessionManager sessionManager);
|
||||
|
||||
}
|
||||
@@ -1,256 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jms.listener.serversession;
|
||||
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.ConnectionConsumer;
|
||||
import javax.jms.Destination;
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.Message;
|
||||
import javax.jms.MessageListener;
|
||||
import javax.jms.ServerSession;
|
||||
import javax.jms.ServerSessionPool;
|
||||
import javax.jms.Session;
|
||||
import javax.jms.Topic;
|
||||
|
||||
import org.springframework.jms.listener.AbstractMessageListenerContainer;
|
||||
import org.springframework.jms.support.JmsUtils;
|
||||
|
||||
/**
|
||||
* Message listener container that builds on the {@link javax.jms.ServerSessionPool}
|
||||
* SPI, creating JMS ServerSession instances through a pluggable
|
||||
* {@link ServerSessionFactory}.
|
||||
*
|
||||
* <p><b>NOTE:</b> This class requires a JMS 1.1+ provider, because it builds on the
|
||||
* domain-independent API. <b>Use the {@link ServerSessionMessageListenerContainer102}
|
||||
* subclass for a JMS 1.0.2 provider, e.g. when running on a J2EE 1.3 server.</b>
|
||||
*
|
||||
* <p>The default ServerSessionFactory is a {@link SimpleServerSessionFactory},
|
||||
* which will create a new ServerSession for each listener execution.
|
||||
* Consider specifying a {@link CommonsPoolServerSessionFactory} to reuse JMS
|
||||
* Sessions and/or to limit the number of concurrent ServerSession executions.
|
||||
*
|
||||
* <p>See the {@link AbstractMessageListenerContainer} javadoc for details
|
||||
* on acknowledge modes and other configuration options.
|
||||
*
|
||||
* <p><b>This is an 'advanced' (special-purpose) message listener container.</b>
|
||||
* For a simpler message listener container, in particular when using
|
||||
* a JMS provider without ServerSessionPool support, consider using
|
||||
* {@link org.springframework.jms.listener.SimpleMessageListenerContainer}.
|
||||
* For a general one-stop shop that is nevertheless very flexible, consider
|
||||
* {@link org.springframework.jms.listener.DefaultMessageListenerContainer}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
|
||||
* and JmsMessageEndpointManager. To be removed in Spring 3.0.
|
||||
* @see org.springframework.jms.listener.SimpleMessageListenerContainer
|
||||
* @see org.springframework.jms.listener.endpoint.JmsMessageEndpointManager
|
||||
*/
|
||||
public class ServerSessionMessageListenerContainer extends AbstractMessageListenerContainer
|
||||
implements ListenerSessionManager {
|
||||
|
||||
private ServerSessionFactory serverSessionFactory = new SimpleServerSessionFactory();
|
||||
|
||||
private int maxMessagesPerTask = 1;
|
||||
|
||||
private ConnectionConsumer consumer;
|
||||
|
||||
|
||||
/**
|
||||
* Set the Spring ServerSessionFactory to use.
|
||||
* <p>Default is a plain SimpleServerSessionFactory.
|
||||
* Consider using a CommonsPoolServerSessionFactory to reuse JMS Sessions
|
||||
* and/or to limit the number of concurrent ServerSession executions.
|
||||
* @see SimpleServerSessionFactory
|
||||
* @see CommonsPoolServerSessionFactory
|
||||
*/
|
||||
public void setServerSessionFactory(ServerSessionFactory serverSessionFactory) {
|
||||
this.serverSessionFactory =
|
||||
(serverSessionFactory != null ? serverSessionFactory : new SimpleServerSessionFactory());
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Spring ServerSessionFactory to use.
|
||||
*/
|
||||
protected ServerSessionFactory getServerSessionFactory() {
|
||||
return this.serverSessionFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the maximum number of messages to load into a JMS Session.
|
||||
* Default is 1.
|
||||
* <p>See the corresponding JMS <code>createConnectionConsumer</code>
|
||||
* argument for details.
|
||||
* @see javax.jms.Connection#createConnectionConsumer
|
||||
*/
|
||||
public void setMaxMessagesPerTask(int maxMessagesPerTask) {
|
||||
this.maxMessagesPerTask = maxMessagesPerTask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the maximum number of messages to load into a JMS Session.
|
||||
*/
|
||||
protected int getMaxMessagesPerTask() {
|
||||
return this.maxMessagesPerTask;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Implementation of AbstractMessageListenerContainer's template methods
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Always use a shared JMS Connection.
|
||||
*/
|
||||
protected final boolean sharedConnectionEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a JMS ServerSessionPool for the specified listener and registers
|
||||
* it with a JMS ConnectionConsumer for the specified destination.
|
||||
* @see #createServerSessionPool
|
||||
* @see #createConsumer
|
||||
*/
|
||||
protected void doInitialize() throws JMSException {
|
||||
establishSharedConnection();
|
||||
|
||||
Connection con = getSharedConnection();
|
||||
Destination destination = getDestination();
|
||||
if (destination == null) {
|
||||
Session session = createSession(con);
|
||||
try {
|
||||
destination = resolveDestinationName(session, getDestinationName());
|
||||
}
|
||||
finally {
|
||||
JmsUtils.closeSession(session);
|
||||
}
|
||||
}
|
||||
ServerSessionPool pool = createServerSessionPool();
|
||||
this.consumer = createConsumer(con, destination, pool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a JMS ServerSessionPool for the specified message listener,
|
||||
* via this container's ServerSessionFactory.
|
||||
* <p>This message listener container implements the ListenerSessionManager
|
||||
* interface, hence can be passed to the ServerSessionFactory itself.
|
||||
* @return the ServerSessionPool
|
||||
* @throws JMSException if creation of the ServerSessionPool failed
|
||||
* @see #setServerSessionFactory
|
||||
* @see ServerSessionFactory#getServerSession(ListenerSessionManager)
|
||||
*/
|
||||
protected ServerSessionPool createServerSessionPool() throws JMSException {
|
||||
return new ServerSessionPool() {
|
||||
public ServerSession getServerSession() throws JMSException {
|
||||
logger.debug("JMS ConnectionConsumer requests ServerSession");
|
||||
return getServerSessionFactory().getServerSession(ServerSessionMessageListenerContainer.this);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the JMS ConnectionConsumer used by this message listener container.
|
||||
* Available after initialization.
|
||||
*/
|
||||
protected final ConnectionConsumer getConsumer() {
|
||||
return this.consumer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the JMS ServerSessionPool for the specified message listener,
|
||||
* via this container's ServerSessionFactory, and subsequently also
|
||||
* this container's JMS ConnectionConsumer.
|
||||
* <p>This message listener container implements the ListenerSessionManager
|
||||
* interface, hence can be passed to the ServerSessionFactory itself.
|
||||
* @see #setServerSessionFactory
|
||||
* @see ServerSessionFactory#getServerSession(ListenerSessionManager)
|
||||
*/
|
||||
protected void doShutdown() throws JMSException {
|
||||
logger.debug("Closing ServerSessionFactory");
|
||||
getServerSessionFactory().close(this);
|
||||
logger.debug("Closing JMS ConnectionConsumer");
|
||||
this.consumer.close();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Implementation of the ListenerSessionManager interface
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create a JMS Session with the specified listener registered.
|
||||
* Listener execution is delegated to the <code>executeListener</code> method.
|
||||
* <p>Default implementation simply calls <code>setMessageListener</code>
|
||||
* on a newly created JMS Session, according to the JMS specification's
|
||||
* ServerSessionPool section.
|
||||
* @return the JMS Session
|
||||
* @throws JMSException if thrown by JMS API methods
|
||||
* @see #executeListener
|
||||
*/
|
||||
public Session createListenerSession() throws JMSException {
|
||||
final Session session = createSession(getSharedConnection());
|
||||
|
||||
session.setMessageListener(new MessageListener() {
|
||||
public void onMessage(Message message) {
|
||||
executeListener(session, message);
|
||||
}
|
||||
});
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the given JMS Session, triggering invocation
|
||||
* of its listener.
|
||||
* <p>Default implementation simply calls <code>run()</code>
|
||||
* on the JMS Session, according to the JMS specification's
|
||||
* ServerSessionPool section.
|
||||
* @param session the JMS Session to execute
|
||||
*/
|
||||
public void executeListenerSession(Session session) {
|
||||
session.run();
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// JMS 1.1 factory methods, potentially overridden for JMS 1.0.2
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* Create a JMS ConnectionConsumer for the given Connection.
|
||||
* <p>This implementation uses JMS 1.1 API.
|
||||
* @param con the JMS Connection to create a Session for
|
||||
* @param destination the JMS Destination to listen to
|
||||
* @param pool the ServerSessionpool to use
|
||||
* @return the new JMS Session
|
||||
* @throws JMSException if thrown by JMS API methods
|
||||
*/
|
||||
protected ConnectionConsumer createConsumer(Connection con, Destination destination, ServerSessionPool pool)
|
||||
throws JMSException {
|
||||
|
||||
if (isSubscriptionDurable() && destination instanceof Topic) {
|
||||
return con.createDurableConnectionConsumer(
|
||||
(Topic) destination, getDurableSubscriptionName(), getMessageSelector(), pool, getMaxMessagesPerTask());
|
||||
}
|
||||
else {
|
||||
return con.createConnectionConsumer(destination, getMessageSelector(), pool, getMaxMessagesPerTask());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jms.listener.serversession;
|
||||
|
||||
import javax.jms.Connection;
|
||||
import javax.jms.ConnectionConsumer;
|
||||
import javax.jms.Destination;
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.Queue;
|
||||
import javax.jms.QueueConnection;
|
||||
import javax.jms.QueueConnectionFactory;
|
||||
import javax.jms.ServerSessionPool;
|
||||
import javax.jms.Session;
|
||||
import javax.jms.Topic;
|
||||
import javax.jms.TopicConnection;
|
||||
import javax.jms.TopicConnectionFactory;
|
||||
|
||||
/**
|
||||
* A subclass of {@link ServerSessionMessageListenerContainer} for the JMS 1.0.2 specification,
|
||||
* not relying on JMS 1.1 methods like ServerSessionMessageListenerContainer itself.
|
||||
*
|
||||
* <p>This class can be used for JMS 1.0.2 providers, offering the same facility as
|
||||
* ServerSessionMessageListenerContainer does for JMS 1.1 providers.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
|
||||
* and JmsMessageEndpointManager. To be removed in Spring 3.0.
|
||||
*/
|
||||
public class ServerSessionMessageListenerContainer102 extends ServerSessionMessageListenerContainer {
|
||||
|
||||
/**
|
||||
* This implementation overrides the superclass method to use JMS 1.0.2 API.
|
||||
*/
|
||||
protected Connection createConnection() throws JMSException {
|
||||
if (isPubSubDomain()) {
|
||||
return ((TopicConnectionFactory) getConnectionFactory()).createTopicConnection();
|
||||
}
|
||||
else {
|
||||
return ((QueueConnectionFactory) getConnectionFactory()).createQueueConnection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation overrides the superclass method to use JMS 1.0.2 API.
|
||||
*/
|
||||
protected ConnectionConsumer createConsumer(Connection con, Destination destination, ServerSessionPool pool)
|
||||
throws JMSException {
|
||||
|
||||
if (isPubSubDomain()) {
|
||||
if (isSubscriptionDurable()) {
|
||||
return ((TopicConnection) con).createDurableConnectionConsumer(
|
||||
(Topic) destination, getDurableSubscriptionName(), getMessageSelector(), pool, getMaxMessagesPerTask());
|
||||
}
|
||||
else {
|
||||
return ((TopicConnection) con).createConnectionConsumer(
|
||||
(Topic) destination, getMessageSelector(), pool, getMaxMessagesPerTask());
|
||||
}
|
||||
}
|
||||
else {
|
||||
return ((QueueConnection) con).createConnectionConsumer(
|
||||
(Queue) destination, getMessageSelector(), pool, getMaxMessagesPerTask());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation overrides the superclass method to use JMS 1.0.2 API.
|
||||
*/
|
||||
protected Session createSession(Connection con) throws JMSException {
|
||||
if (isPubSubDomain()) {
|
||||
return ((TopicConnection) con).createTopicSession(isSessionTransacted(), getSessionAcknowledgeMode());
|
||||
}
|
||||
else {
|
||||
return ((QueueConnection) con).createQueueSession(isSessionTransacted(), getSessionAcknowledgeMode());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation overrides the superclass method to avoid using
|
||||
* JMS 1.1's Session <code>getAcknowledgeMode()</code> method.
|
||||
* The best we can do here is to check the setting on the listener container.
|
||||
*/
|
||||
protected boolean isClientAcknowledge(Session session) throws JMSException {
|
||||
return (getSessionAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,138 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jms.listener.serversession;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.ServerSession;
|
||||
import javax.jms.Session;
|
||||
|
||||
import org.springframework.core.task.SimpleAsyncTaskExecutor;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.jms.support.JmsUtils;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* The simplest possible implementation of the ServerSessionFactory SPI:
|
||||
* creating a new ServerSession with a new JMS Session every time.
|
||||
* This is the default used by ServerSessionMessageListenerContainer.
|
||||
*
|
||||
* <p>The execution of a ServerSession (and its MessageListener) gets delegated
|
||||
* to a TaskExecutor. By default, a SimpleAsyncTaskExecutor will be used,
|
||||
* creating a new Thread for every execution attempt. Alternatives are a
|
||||
* TimerTaskExecutor, sharing a single Thread for the execution of all
|
||||
* ServerSessions, or a TaskExecutor implementation backed by a thread pool.
|
||||
*
|
||||
* <p>To reuse JMS Sessions and/or to limit the number of concurrent
|
||||
* ServerSession executions, consider using a pooling ServerSessionFactory:
|
||||
* for example, CommonsPoolServerSessionFactory.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @deprecated as of Spring 2.5, in favor of DefaultMessageListenerContainer
|
||||
* and JmsMessageEndpointManager. To be removed in Spring 3.0.
|
||||
* @see org.springframework.core.task.TaskExecutor
|
||||
* @see org.springframework.core.task.SimpleAsyncTaskExecutor
|
||||
* @see org.springframework.scheduling.timer.TimerTaskExecutor
|
||||
* @see CommonsPoolServerSessionFactory
|
||||
* @see ServerSessionMessageListenerContainer
|
||||
*/
|
||||
public class SimpleServerSessionFactory implements ServerSessionFactory {
|
||||
|
||||
/**
|
||||
* Default thread name prefix: "SimpleServerSessionFactory-".
|
||||
*/
|
||||
public static final String DEFAULT_THREAD_NAME_PREFIX =
|
||||
ClassUtils.getShortName(SimpleServerSessionFactory.class) + "-";
|
||||
|
||||
|
||||
private TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor(DEFAULT_THREAD_NAME_PREFIX);
|
||||
|
||||
|
||||
/**
|
||||
* Specify the TaskExecutor to use for executing ServerSessions
|
||||
* (and consequently, the underlying MessageListener).
|
||||
* <p>Default is a SimpleAsyncTaskExecutor, creating a new Thread for
|
||||
* every execution attempt. Alternatives are a TimerTaskExecutor,
|
||||
* sharing a single Thread for the execution of all ServerSessions,
|
||||
* or a TaskExecutor implementation backed by a thread pool.
|
||||
* @see org.springframework.core.task.SimpleAsyncTaskExecutor
|
||||
* @see org.springframework.scheduling.timer.TimerTaskExecutor
|
||||
*/
|
||||
public void setTaskExecutor(TaskExecutor taskExecutor) {
|
||||
Assert.notNull(taskExecutor, "taskExecutor is required");
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the TaskExecutor to use for executing ServerSessions.
|
||||
*/
|
||||
protected TaskExecutor getTaskExecutor() {
|
||||
return taskExecutor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new SimpleServerSession with a new JMS Session
|
||||
* for every call.
|
||||
*/
|
||||
public ServerSession getServerSession(ListenerSessionManager sessionManager) throws JMSException {
|
||||
return new SimpleServerSession(sessionManager);
|
||||
}
|
||||
|
||||
/**
|
||||
* This implementation is empty, as there is no state held for
|
||||
* each ListenerSessionManager.
|
||||
*/
|
||||
public void close(ListenerSessionManager sessionManager) {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* ServerSession implementation that simply creates a new
|
||||
* JMS Session and executes it via the specified TaskExecutor.
|
||||
*/
|
||||
private class SimpleServerSession implements ServerSession {
|
||||
|
||||
private final ListenerSessionManager sessionManager;
|
||||
|
||||
private final Session session;
|
||||
|
||||
public SimpleServerSession(ListenerSessionManager sessionManager) throws JMSException {
|
||||
this.sessionManager = sessionManager;
|
||||
this.session = sessionManager.createListenerSession();
|
||||
}
|
||||
|
||||
public Session getSession() {
|
||||
return session;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
getTaskExecutor().execute(new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
sessionManager.executeListenerSession(session);
|
||||
}
|
||||
finally {
|
||||
JmsUtils.closeSession(session);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<html>
|
||||
<body>
|
||||
|
||||
This package contains the ServerSessionMessageListenerContainer implementation,
|
||||
based on the standard JMS ServerSessionPool API.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,7 @@
|
||||
package org.springframework.jms.support.destination;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import javax.jms.Destination;
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.Queue;
|
||||
@@ -25,7 +25,6 @@ import javax.jms.Session;
|
||||
import javax.jms.Topic;
|
||||
import javax.naming.NamingException;
|
||||
|
||||
import org.springframework.core.CollectionFactory;
|
||||
import org.springframework.jndi.JndiLocatorSupport;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -61,7 +60,7 @@ public class JndiDestinationResolver extends JndiLocatorSupport implements Cachi
|
||||
|
||||
private DestinationResolver dynamicDestinationResolver = new DynamicDestinationResolver();
|
||||
|
||||
private final Map destinationCache = CollectionFactory.createConcurrentMapIfPossible(16);
|
||||
private final Map<String, Destination> destinationCache = new ConcurrentHashMap<String, Destination>();
|
||||
|
||||
|
||||
/**
|
||||
@@ -103,7 +102,7 @@ public class JndiDestinationResolver extends JndiLocatorSupport implements Cachi
|
||||
throws JMSException {
|
||||
|
||||
Assert.notNull(destinationName, "Destination name must not be null");
|
||||
Destination dest = (Destination) this.destinationCache.get(destinationName);
|
||||
Destination dest = this.destinationCache.get(destinationName);
|
||||
if (dest != null) {
|
||||
validateDestination(dest, destinationName, pubSubDomain);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user