All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.jms.remoting.JmsInvokerClientInterceptor Maven / Gradle / Ivy

There is a newer version: 5.3.34
Show newest version
/*
 * Copyright 2002-2007 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.remoting;

import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageFormatException;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueRequestor;
import javax.jms.QueueSession;
import javax.jms.Session;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.jms.connection.ConnectionFactoryUtils;
import org.springframework.jms.support.JmsUtils;
import org.springframework.jms.support.destination.DestinationResolver;
import org.springframework.jms.support.destination.DynamicDestinationResolver;
import org.springframework.remoting.RemoteAccessException;
import org.springframework.remoting.support.DefaultRemoteInvocationFactory;
import org.springframework.remoting.support.RemoteInvocation;
import org.springframework.remoting.support.RemoteInvocationFactory;
import org.springframework.remoting.support.RemoteInvocationResult;
import org.springframework.util.Assert;

/**
 * Interceptor for accessing a JMS-based remote service.
 *
 * 

To be configured with a {@link javax.jms.QueueConnectionFactory} and a * target queue (either as {@link javax.jms.Queue} reference or as queue name). * * @author Juergen Hoeller * @author James Strachan * @since 2.0 * @see #setConnectionFactory * @see #setQueue * @see #setQueueName * @see org.springframework.jms.remoting.JmsInvokerServiceExporter * @see org.springframework.jms.remoting.JmsInvokerProxyFactoryBean */ public class JmsInvokerClientInterceptor implements MethodInterceptor, InitializingBean { private QueueConnectionFactory connectionFactory; private Object queue; private DestinationResolver destinationResolver = new DynamicDestinationResolver(); private RemoteInvocationFactory remoteInvocationFactory = new DefaultRemoteInvocationFactory(); /** * Set the QueueConnectionFactory to use for obtaining JMS QueueConnections. */ public void setConnectionFactory(QueueConnectionFactory connectionFactory) { this.connectionFactory = connectionFactory; } /** * Return the QueueConnectionFactory to use for obtaining JMS QueueConnections. */ protected QueueConnectionFactory getConnectionFactory() { return this.connectionFactory; } /** * Set the target Queue to send invoker requests to. */ public void setQueue(Queue queue) { this.queue = queue; } /** * Set the name of target queue to send invoker requests to. */ public void setQueueName(String queueName) { this.queue = queueName; } /** * Set the DestinationResolver that is to be used to resolve Queue * references for this accessor. *

The default resolver is a DynamicDestinationResolver. Specify a * JndiDestinationResolver for resolving destination names as JNDI locations. * @param destinationResolver the DestinationResolver that is to be used * @see org.springframework.jms.support.destination.DynamicDestinationResolver * @see org.springframework.jms.support.destination.JndiDestinationResolver */ public void setDestinationResolver(DestinationResolver destinationResolver) { Assert.notNull(destinationResolver, "DestinationResolver must not be null"); this.destinationResolver = destinationResolver; } /** * Set the RemoteInvocationFactory to use for this accessor. * Default is a DefaultRemoteInvocationFactory. *

A custom invocation factory can add further context information * to the invocation, for example user credentials. */ public void setRemoteInvocationFactory(RemoteInvocationFactory remoteInvocationFactory) { this.remoteInvocationFactory = remoteInvocationFactory; } public void afterPropertiesSet() { if (getConnectionFactory() == null) { throw new IllegalArgumentException("Property 'connectionFactory' is required"); } if (this.queue == null) { throw new IllegalArgumentException("'queue' or 'queueName' is required"); } } public Object invoke(MethodInvocation methodInvocation) throws Throwable { if (AopUtils.isToStringMethod(methodInvocation.getMethod())) { return "JMS invoker proxy for queue [" + this.queue + "]"; } RemoteInvocation invocation = createRemoteInvocation(methodInvocation); RemoteInvocationResult result = null; try { result = executeRequest(invocation); } catch (JMSException ex) { throw new RemoteAccessException("Cannot access JMS invoker queue [" + this.queue + "]", ex); } return recreateRemoteInvocationResult(result); } /** * Create a new RemoteInvocation object for the given AOP method invocation. * The default implementation delegates to the RemoteInvocationFactory. *

Can be overridden in subclasses to provide custom RemoteInvocation * subclasses, containing additional invocation parameters like user credentials. * Note that it is preferable to use a custom RemoteInvocationFactory which * is a reusable strategy. * @param methodInvocation the current AOP method invocation * @return the RemoteInvocation object * @see RemoteInvocationFactory#createRemoteInvocation */ protected RemoteInvocation createRemoteInvocation(MethodInvocation methodInvocation) { return this.remoteInvocationFactory.createRemoteInvocation(methodInvocation); } /** * Execute the given remote invocation, sending an invoker request message * to this accessor's target queue and waiting for a corresponding response. *

The default implementation is based on a JMS QueueRequestor, * using a freshly obtained JMS Session. * @param invocation the RemoteInvocation to execute * @return the RemoteInvocationResult object * @throws JMSException in case of JMS failure */ protected RemoteInvocationResult executeRequest(RemoteInvocation invocation) throws JMSException { QueueConnection con = getConnectionFactory().createQueueConnection(); QueueSession session = null; QueueRequestor requestor = null; try { session = con.createQueueSession(false, Session.AUTO_ACKNOWLEDGE); Queue queueToUse = resolveQueue(session); Message requestMessage = createRequestMessage(session, invocation); requestor = new QueueRequestor(session, queueToUse); con.start(); Message responseMessage = requestor.request(requestMessage); return extractInvocationResult(responseMessage); } finally { JmsUtils.closeQueueRequestor(requestor); JmsUtils.closeSession(session); ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory(), true); } } /** * Resolve this accessor's target queue. * @param session the current JMS Session * @return the resolved target Queue * @throws JMSException if resolution failed */ protected Queue resolveQueue(Session session) throws JMSException { if (this.queue instanceof Queue) { return (Queue) this.queue; } else if (this.queue instanceof String) { return resolveQueueName(session, (String) this.queue); } else { throw new javax.jms.IllegalStateException( "Queue object [" + this.queue + "] is neither a [javax.jms.Queue] nor a queue name String"); } } /** * Resolve the given queue name into a JMS {@link javax.jms.Queue}, * via this accessor's {@link DestinationResolver}. * @param session the current JMS Session * @param queueName the name of the queue * @return the located Queue * @throws JMSException if resolution failed * @see #setDestinationResolver */ protected Queue resolveQueueName(Session session, String queueName) throws JMSException { return (Queue) this.destinationResolver.resolveDestinationName(session, queueName, false); } /** * Create the invoker request message. *

The default implementation creates a JMS ObjectMessage * for the given RemoteInvocation object. * @param session the current JMS Session * @param invocation the remote invocation to send * @throws JMSException if the message could not be created */ protected Message createRequestMessage(Session session, RemoteInvocation invocation) throws JMSException { return session.createObjectMessage(invocation); } /** * Extract the invocation result from the response message. *

The default implementation expects a JMS ObjectMessage carrying * a RemoteInvocationResult object. If an invalid response message is * encountered, the onInvalidResponse callback gets invoked. * @param responseMessage the response message * @return the invocation result * @throws JMSException is thrown if a JMS exception occurs * @see #onInvalidResponse */ protected RemoteInvocationResult extractInvocationResult(Message responseMessage) throws JMSException { if (responseMessage instanceof ObjectMessage) { ObjectMessage objectMessage = (ObjectMessage) responseMessage; Object body = objectMessage.getObject(); if (body instanceof RemoteInvocationResult) { return (RemoteInvocationResult) body; } } return onInvalidResponse(responseMessage); } /** * Callback that is invoked by extractInvocationResult * when it encounters an invalid response message. *

The default implementation throws a MessageFormatException. * @param responseMessage the invalid response message * @return an alternative invocation result that should be * returned to the caller (if desired) * @throws JMSException if the invalid response should lead * to an infrastructure exception propagated to the caller * @see #extractInvocationResult */ protected RemoteInvocationResult onInvalidResponse(Message responseMessage) throws JMSException { throw new MessageFormatException("Invalid response message: " + responseMessage); } /** * Recreate the invocation result contained in the given RemoteInvocationResult * object. The default implementation calls the default recreate method. *

Can be overridden in subclass to provide custom recreation, potentially * processing the returned result object. * @param result the RemoteInvocationResult to recreate * @return a return value if the invocation result is a successful return * @throws Throwable if the invocation result is an exception * @see org.springframework.remoting.support.RemoteInvocationResult#recreate() */ protected Object recreateRemoteInvocationResult(RemoteInvocationResult result) throws Throwable { return result.recreate(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy