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.listener.endpoint; 018 019import javax.jms.Message; 020import javax.jms.MessageListener; 021import javax.resource.ResourceException; 022import javax.resource.spi.UnavailableException; 023 024import org.springframework.jca.endpoint.AbstractMessageEndpointFactory; 025 026/** 027 * JMS-specific implementation of the JCA 1.5 028 * {@link javax.resource.spi.endpoint.MessageEndpointFactory} interface, 029 * providing transaction management capabilities for a JMS listener object 030 * (e.g. a {@link javax.jms.MessageListener} object). 031 * 032 * <p>Uses a static endpoint implementation, simply wrapping the 033 * specified message listener object and exposing all of its implemented 034 * interfaces on the endpoint instance. 035 * 036 * <p>Typically used with Spring's {@link JmsMessageEndpointManager}, 037 * but not tied to it. As a consequence, this endpoint factory could 038 * also be used with programmatic endpoint management on a native 039 * {@link javax.resource.spi.ResourceAdapter} instance. 040 * 041 * @author Juergen Hoeller 042 * @author Stephane Nicoll 043 * @since 2.5 044 * @see #setMessageListener 045 * @see #setTransactionManager 046 * @see JmsMessageEndpointManager 047 */ 048public class JmsMessageEndpointFactory extends AbstractMessageEndpointFactory { 049 050 private MessageListener messageListener; 051 052 053 /** 054 * Set the JMS MessageListener for this endpoint. 055 */ 056 public void setMessageListener(MessageListener messageListener) { 057 this.messageListener = messageListener; 058 } 059 060 /** 061 * Return the JMS MessageListener for this endpoint. 062 */ 063 protected MessageListener getMessageListener() { 064 return this.messageListener; 065 } 066 067 /** 068 * Creates a concrete JMS message endpoint, internal to this factory. 069 */ 070 @Override 071 protected AbstractMessageEndpoint createEndpointInternal() throws UnavailableException { 072 return new JmsMessageEndpoint(); 073 } 074 075 076 /** 077 * Private inner class that implements the concrete JMS message endpoint. 078 */ 079 private class JmsMessageEndpoint extends AbstractMessageEndpoint implements MessageListener { 080 081 @Override 082 public void onMessage(Message message) { 083 Throwable endpointEx = null; 084 boolean applyDeliveryCalls = !hasBeforeDeliveryBeenCalled(); 085 if (applyDeliveryCalls) { 086 try { 087 beforeDelivery(null); 088 } 089 catch (ResourceException ex) { 090 throw new JmsResourceException(ex); 091 } 092 } 093 try { 094 messageListener.onMessage(message); 095 } 096 catch (RuntimeException ex) { 097 endpointEx = ex; 098 onEndpointException(ex); 099 throw ex; 100 } 101 catch (Error err) { 102 endpointEx = err; 103 onEndpointException(err); 104 throw err; 105 } 106 finally { 107 if (applyDeliveryCalls) { 108 try { 109 afterDelivery(); 110 } 111 catch (ResourceException ex) { 112 if (endpointEx == null) { 113 throw new JmsResourceException(ex); 114 } 115 } 116 } 117 } 118 } 119 120 @Override 121 protected ClassLoader getEndpointClassLoader() { 122 return getMessageListener().getClass().getClassLoader(); 123 } 124 } 125 126 127 /** 128 * Internal exception thrown when a ResourceException has been encountered 129 * during the endpoint invocation. 130 * <p>Will only be used if the ResourceAdapter does not invoke the 131 * endpoint's {@code beforeDelivery} and {@code afterDelivery} 132 * directly, leaving it up to the concrete endpoint to apply those - 133 * and to handle any ResourceExceptions thrown from them. 134 */ 135 @SuppressWarnings("serial") 136 public static class JmsResourceException extends RuntimeException { 137 138 public JmsResourceException(ResourceException cause) { 139 super(cause); 140 } 141 } 142 143}