001/* 002 * Copyright 2002-2015 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.listener.endpoint; 018 019import javax.jms.MessageListener; 020import javax.resource.ResourceException; 021 022import org.springframework.beans.factory.BeanNameAware; 023import org.springframework.jca.endpoint.GenericMessageEndpointManager; 024import org.springframework.jms.listener.MessageListenerContainer; 025import org.springframework.jms.support.converter.MessageConverter; 026import org.springframework.jms.support.destination.DestinationResolver; 027 028/** 029 * Extension of the generic JCA 1.5 030 * {@link org.springframework.jca.endpoint.GenericMessageEndpointManager}, 031 * adding JMS-specific support for ActivationSpec configuration. 032 * 033 * <p>Allows for defining a common {@link JmsActivationSpecConfig} object 034 * that gets converted into a provider-specific JCA 1.5 ActivationSpec 035 * object for activating the endpoint. 036 * 037 * <p><b>NOTE:</b> This JCA-based endpoint manager supports standard JMS 038 * {@link javax.jms.MessageListener} endpoints only. It does <i>not</i> support 039 * Spring's {@link org.springframework.jms.listener.SessionAwareMessageListener} 040 * variant, simply because the JCA endpoint management contract does not allow 041 * for obtaining the current JMS {@link javax.jms.Session}. 042 * 043 * @author Juergen Hoeller 044 * @author Stephane Nicoll 045 * @since 2.5 046 * @see javax.jms.MessageListener 047 * @see #setActivationSpecConfig 048 * @see JmsActivationSpecConfig 049 * @see JmsActivationSpecFactory 050 * @see JmsMessageEndpointFactory 051 */ 052public class JmsMessageEndpointManager extends GenericMessageEndpointManager 053 implements BeanNameAware, MessageListenerContainer { 054 055 private final JmsMessageEndpointFactory endpointFactory = new JmsMessageEndpointFactory(); 056 057 private boolean messageListenerSet = false; 058 059 private JmsActivationSpecFactory activationSpecFactory = new DefaultJmsActivationSpecFactory(); 060 061 private JmsActivationSpecConfig activationSpecConfig; 062 063 064 /** 065 * Set the JMS MessageListener for this endpoint. 066 * <p>This is a shortcut for configuring a dedicated JmsMessageEndpointFactory. 067 * @see JmsMessageEndpointFactory#setMessageListener 068 */ 069 public void setMessageListener(MessageListener messageListener) { 070 this.endpointFactory.setMessageListener(messageListener); 071 this.messageListenerSet = true; 072 } 073 074 /** 075 * Return the JMS MessageListener for this endpoint. 076 */ 077 public MessageListener getMessageListener() { 078 return this.endpointFactory.getMessageListener(); 079 } 080 081 /** 082 * Set the XA transaction manager to use for wrapping endpoint 083 * invocations, enlisting the endpoint resource in each such transaction. 084 * <p>The passed-in object may be a transaction manager which implements 085 * Spring's {@link org.springframework.transaction.jta.TransactionFactory} 086 * interface, or a plain {@link javax.transaction.TransactionManager}. 087 * <p>If no transaction manager is specified, the endpoint invocation 088 * will simply not be wrapped in an XA transaction. Consult your 089 * resource provider's ActivationSpec documentation for the local 090 * transaction options of your particular provider. 091 * <p>This is a shortcut for configuring a dedicated JmsMessageEndpointFactory. 092 * @see JmsMessageEndpointFactory#setTransactionManager 093 */ 094 public void setTransactionManager(Object transactionManager) { 095 this.endpointFactory.setTransactionManager(transactionManager); 096 } 097 098 /** 099 * Set the factory for concrete JCA 1.5 ActivationSpec objects, 100 * creating JCA ActivationSpecs based on 101 * {@link #setActivationSpecConfig JmsActivationSpecConfig} objects. 102 * <p>This factory is dependent on the concrete JMS provider, e.g. on ActiveMQ. 103 * The default implementation simply guesses the ActivationSpec class name 104 * from the provider's class name (e.g. "ActiveMQResourceAdapter" -> 105 * "ActiveMQActivationSpec" in the same package), and populates the 106 * ActivationSpec properties as suggested by the JCA 1.5 specification 107 * (plus a couple of autodetected vendor-specific properties). 108 * @see DefaultJmsActivationSpecFactory 109 */ 110 public void setActivationSpecFactory(JmsActivationSpecFactory activationSpecFactory) { 111 this.activationSpecFactory = 112 (activationSpecFactory != null ? activationSpecFactory : new DefaultJmsActivationSpecFactory()); 113 } 114 115 /** 116 * Set the DestinationResolver to use for resolving destination names 117 * into the JCA 1.5 ActivationSpec "destination" property. 118 * <p>If not specified, destination names will simply be passed in as Strings. 119 * If specified, destination names will be resolved into Destination objects first. 120 * <p>Note that a DestinationResolver is usually specified on the JmsActivationSpecFactory 121 * (see {@link StandardJmsActivationSpecFactory#setDestinationResolver}). This is simply 122 * a shortcut for parameterizing the default JmsActivationSpecFactory; it will replace 123 * any custom JmsActivationSpecFactory that might have been set before. 124 * @see StandardJmsActivationSpecFactory#setDestinationResolver 125 */ 126 public void setDestinationResolver(DestinationResolver destinationResolver) { 127 DefaultJmsActivationSpecFactory factory = new DefaultJmsActivationSpecFactory(); 128 factory.setDestinationResolver(destinationResolver); 129 this.activationSpecFactory = factory; 130 } 131 132 /** 133 * Specify the {@link JmsActivationSpecConfig} object that this endpoint manager 134 * should use for activating its listener. 135 * <p>This config object will be turned into a concrete JCA 1.5 ActivationSpec 136 * object through a {@link #setActivationSpecFactory JmsActivationSpecFactory}. 137 */ 138 public void setActivationSpecConfig(JmsActivationSpecConfig activationSpecConfig) { 139 this.activationSpecConfig = activationSpecConfig; 140 } 141 142 /** 143 * Return the {@link JmsActivationSpecConfig} object that this endpoint manager 144 * should use for activating its listener. Return {@code null} if none is set. 145 */ 146 public JmsActivationSpecConfig getActivationSpecConfig() { 147 return this.activationSpecConfig; 148 } 149 150 /** 151 * Set the name of this message endpoint. Populated with the bean name 152 * automatically when defined within Spring's bean factory. 153 */ 154 @Override 155 public void setBeanName(String beanName) { 156 this.endpointFactory.setBeanName(beanName); 157 } 158 159 160 @Override 161 public void afterPropertiesSet() throws ResourceException { 162 if (this.messageListenerSet) { 163 setMessageEndpointFactory(this.endpointFactory); 164 } 165 if (this.activationSpecConfig != null) { 166 setActivationSpec( 167 this.activationSpecFactory.createActivationSpec(getResourceAdapter(), this.activationSpecConfig)); 168 } 169 super.afterPropertiesSet(); 170 } 171 172 173 @Override 174 public void setupMessageListener(Object messageListener) { 175 if (messageListener instanceof MessageListener) { 176 setMessageListener((MessageListener) messageListener); 177 } 178 else { 179 throw new IllegalArgumentException("Unsupported message listener '" + 180 messageListener.getClass().getName() + "': only '" + MessageListener.class.getName() + 181 "' type is supported"); 182 } 183 } 184 185 @Override 186 public MessageConverter getMessageConverter() { 187 JmsActivationSpecConfig config = getActivationSpecConfig(); 188 if (config != null) { 189 return config.getMessageConverter(); 190 } 191 return null; 192 } 193 194 @Override 195 public DestinationResolver getDestinationResolver() { 196 if (this.activationSpecFactory instanceof StandardJmsActivationSpecFactory) { 197 return ((StandardJmsActivationSpecFactory) this.activationSpecFactory).getDestinationResolver(); 198 } 199 return null; 200 } 201 202 @Override 203 public boolean isPubSubDomain() { 204 JmsActivationSpecConfig config = getActivationSpecConfig(); 205 if (config != null) { 206 return config.isPubSubDomain(); 207 } 208 throw new IllegalStateException("Could not determine pubSubDomain - no activation spec config is set"); 209 } 210 211 @Override 212 public boolean isReplyPubSubDomain() { 213 JmsActivationSpecConfig config = getActivationSpecConfig(); 214 if (config != null) { 215 return config.isReplyPubSubDomain(); 216 } 217 throw new IllegalStateException("Could not determine reply pubSubDomain - no activation spec config is set"); 218 } 219 220}