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.remoting.support;
018
019import java.lang.reflect.InvocationTargetException;
020
021/**
022 * Abstract base class for remote service exporters that are based
023 * on deserialization of {@link RemoteInvocation} objects.
024 *
025 * <p>Provides a "remoteInvocationExecutor" property, with a
026 * {@link DefaultRemoteInvocationExecutor} as default strategy.
027 *
028 * @author Juergen Hoeller
029 * @since 1.1
030 * @see RemoteInvocationExecutor
031 * @see DefaultRemoteInvocationExecutor
032 */
033public abstract class RemoteInvocationBasedExporter extends RemoteExporter {
034
035        private RemoteInvocationExecutor remoteInvocationExecutor = new DefaultRemoteInvocationExecutor();
036
037
038        /**
039         * Set the RemoteInvocationExecutor to use for this exporter.
040         * Default is a DefaultRemoteInvocationExecutor.
041         * <p>A custom invocation executor can extract further context information
042         * from the invocation, for example user credentials.
043         */
044        public void setRemoteInvocationExecutor(RemoteInvocationExecutor remoteInvocationExecutor) {
045                this.remoteInvocationExecutor = remoteInvocationExecutor;
046        }
047
048        /**
049         * Return the RemoteInvocationExecutor used by this exporter.
050         */
051        public RemoteInvocationExecutor getRemoteInvocationExecutor() {
052                return this.remoteInvocationExecutor;
053        }
054
055
056        /**
057         * Apply the given remote invocation to the given target object.
058         * The default implementation delegates to the RemoteInvocationExecutor.
059         * <p>Can be overridden in subclasses for custom invocation behavior,
060         * possibly for applying additional invocation parameters from a
061         * custom RemoteInvocation subclass. Note that it is preferable to use
062         * a custom RemoteInvocationExecutor which is a reusable strategy.
063         * @param invocation the remote invocation
064         * @param targetObject the target object to apply the invocation to
065         * @return the invocation result
066         * @throws NoSuchMethodException if the method name could not be resolved
067         * @throws IllegalAccessException if the method could not be accessed
068         * @throws InvocationTargetException if the method invocation resulted in an exception
069         * @see RemoteInvocationExecutor#invoke
070         */
071        protected Object invoke(RemoteInvocation invocation, Object targetObject)
072                        throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
073
074                if (logger.isTraceEnabled()) {
075                        logger.trace("Executing " + invocation);
076                }
077                try {
078                        return getRemoteInvocationExecutor().invoke(invocation, targetObject);
079                }
080                catch (NoSuchMethodException ex) {
081                        if (logger.isDebugEnabled()) {
082                                logger.debug("Could not find target method for " + invocation, ex);
083                        }
084                        throw ex;
085                }
086                catch (IllegalAccessException ex) {
087                        if (logger.isDebugEnabled()) {
088                                logger.debug("Could not access target method for " + invocation, ex);
089                        }
090                        throw ex;
091                }
092                catch (InvocationTargetException ex) {
093                        if (logger.isDebugEnabled()) {
094                                logger.debug("Target method failed for " + invocation, ex.getTargetException());
095                        }
096                        throw ex;
097                }
098        }
099
100        /**
101         * Apply the given remote invocation to the given target object, wrapping
102         * the invocation result in a serializable RemoteInvocationResult object.
103         * The default implementation creates a plain RemoteInvocationResult.
104         * <p>Can be overridden in subclasses for custom invocation behavior,
105         * for example to return additional context information. Note that this
106         * is not covered by the RemoteInvocationExecutor strategy!
107         * @param invocation the remote invocation
108         * @param targetObject the target object to apply the invocation to
109         * @return the invocation result
110         * @see #invoke
111         */
112        protected RemoteInvocationResult invokeAndCreateResult(RemoteInvocation invocation, Object targetObject) {
113                try {
114                        Object value = invoke(invocation, targetObject);
115                        return new RemoteInvocationResult(value);
116                }
117                catch (Throwable ex) {
118                        return new RemoteInvocationResult(ex);
119                }
120        }
121
122}