View Javadoc
1   /*
2    * Copyright 2002-2014 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.jms.listener.endpoint;
18  
19  import javax.jms.Message;
20  import javax.jms.MessageListener;
21  import javax.resource.ResourceException;
22  import javax.resource.spi.UnavailableException;
23  
24  import org.springframework.jca.endpoint.AbstractMessageEndpointFactory;
25  
26  /**
27   * JMS-specific implementation of the JCA 1.5
28   * {@link javax.resource.spi.endpoint.MessageEndpointFactory} interface,
29   * providing transaction management capabilities for a JMS listener object
30   * (e.g. a {@link javax.jms.MessageListener} object).
31   *
32   * <p>Uses a static endpoint implementation, simply wrapping the
33   * specified message listener object and exposing all of its implemented
34   * interfaces on the endpoint instance.
35   *
36   * <p>Typically used with Spring's {@link JmsMessageEndpointManager},
37   * but not tied to it. As a consequence, this endpoint factory could
38   * also be used with programmatic endpoint management on a native
39   * {@link javax.resource.spi.ResourceAdapter} instance.
40   *
41   * @author Juergen Hoeller
42   * @author Stephane Nicoll
43   * @since 2.5
44   * @see #setMessageListener
45   * @see #setTransactionManager
46   * @see JmsMessageEndpointManager
47   */
48  public class JmsMessageEndpointFactory extends AbstractMessageEndpointFactory  {
49  
50  	private MessageListener messageListener;
51  
52  
53  	/**
54  	 * Set the JMS MessageListener for this endpoint.
55  	 */
56  	public void setMessageListener(MessageListener messageListener) {
57  		this.messageListener = messageListener;
58  	}
59  
60  	/**
61  	 * Return the JMS MessageListener for this endpoint.
62  	 */
63  	protected MessageListener getMessageListener() {
64  		return messageListener;
65  	}
66  
67  	/**
68  	 * Creates a concrete JMS message endpoint, internal to this factory.
69  	 */
70  	@Override
71  	protected AbstractMessageEndpoint createEndpointInternal() throws UnavailableException {
72  		return new JmsMessageEndpoint();
73  	}
74  
75  
76  	/**
77  	 * Private inner class that implements the concrete JMS message endpoint.
78  	 */
79  	private class JmsMessageEndpoint extends AbstractMessageEndpoint implements MessageListener {
80  
81  		@Override
82  		public void onMessage(Message message) {
83  			boolean applyDeliveryCalls = !hasBeforeDeliveryBeenCalled();
84  			if (applyDeliveryCalls) {
85  				try {
86  					beforeDelivery(null);
87  				}
88  				catch (ResourceException ex) {
89  					throw new JmsResourceException(ex);
90  				}
91  			}
92  			try {
93  				messageListener.onMessage(message);
94  			}
95  			catch (RuntimeException ex) {
96  				onEndpointException(ex);
97  				throw ex;
98  			}
99  			catch (Error err) {
100 				onEndpointException(err);
101 				throw err;
102 			}
103 			finally {
104 				if (applyDeliveryCalls) {
105 					try {
106 						afterDelivery();
107 					}
108 					catch (ResourceException ex) {
109 						throw new JmsResourceException(ex);
110 					}
111 				}
112 			}
113 		}
114 
115 		@Override
116 		protected ClassLoader getEndpointClassLoader() {
117 			return messageListener.getClass().getClassLoader();
118 		}
119 	}
120 
121 
122 	/**
123 	 * Internal exception thrown when a ResourceException has been encountered
124 	 * during the endpoint invocation.
125 	 * <p>Will only be used if the ResourceAdapter does not invoke the
126 	 * endpoint's {@code beforeDelivery} and {@code afterDelivery}
127 	 * directly, leaving it up to the concrete endpoint to apply those -
128 	 * and to handle any ResourceExceptions thrown from them.
129 	 */
130 	@SuppressWarnings("serial")
131 	public static class JmsResourceException extends RuntimeException {
132 
133 		public JmsResourceException(ResourceException cause) {
134 			super(cause);
135 		}
136 	}
137 
138 }