001/*
002 * Copyright 2002-2013 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.caucho;
018
019import java.lang.reflect.InvocationTargetException;
020import java.lang.reflect.UndeclaredThrowableException;
021import java.net.ConnectException;
022import java.net.MalformedURLException;
023
024import com.caucho.burlap.client.BurlapProxyFactory;
025import com.caucho.burlap.client.BurlapRuntimeException;
026import org.aopalliance.intercept.MethodInterceptor;
027import org.aopalliance.intercept.MethodInvocation;
028
029import org.springframework.remoting.RemoteAccessException;
030import org.springframework.remoting.RemoteConnectFailureException;
031import org.springframework.remoting.RemoteLookupFailureException;
032import org.springframework.remoting.RemoteProxyFailureException;
033import org.springframework.remoting.support.UrlBasedRemoteAccessor;
034import org.springframework.util.Assert;
035
036/**
037 * {@link org.aopalliance.intercept.MethodInterceptor} for accessing a Burlap service.
038 * Supports authentication via username and password.
039 * The service URL must be an HTTP URL exposing a Burlap service.
040 *
041 * <p>Burlap is a slim, XML-based RPC protocol.
042 * For information on Burlap, see the
043 * <a href="https://www.caucho.com/burlap">Burlap website</a>
044 *
045 * <p>Note: There is no requirement for services accessed with this proxy factory
046 * to have been exported using Spring's {@link BurlapServiceExporter}, as there is
047 * no special handling involved. As a consequence, you can also access services that
048 * have been exported using Caucho's {@link com.caucho.burlap.server.BurlapServlet}.
049 *
050 * @author Juergen Hoeller
051 * @since 29.09.2003
052 * @see #setServiceInterface
053 * @see #setServiceUrl
054 * @see #setUsername
055 * @see #setPassword
056 * @see BurlapServiceExporter
057 * @see BurlapProxyFactoryBean
058 * @see com.caucho.burlap.client.BurlapProxyFactory
059 * @see com.caucho.burlap.server.BurlapServlet
060 * @deprecated as of Spring 4.0, since Burlap hasn't evolved in years
061 * and is effectively retired (in contrast to its sibling Hessian)
062 */
063@Deprecated
064public class BurlapClientInterceptor extends UrlBasedRemoteAccessor implements MethodInterceptor {
065
066        private BurlapProxyFactory proxyFactory = new BurlapProxyFactory();
067
068        private Object burlapProxy;
069
070
071        /**
072         * Set the BurlapProxyFactory instance to use.
073         * If not specified, a default BurlapProxyFactory will be created.
074         * <p>Allows to use an externally configured factory instance,
075         * in particular a custom BurlapProxyFactory subclass.
076         */
077        public void setProxyFactory(BurlapProxyFactory proxyFactory) {
078                this.proxyFactory = (proxyFactory != null ? proxyFactory : new BurlapProxyFactory());
079        }
080
081        /**
082         * Set the username that this factory should use to access the remote service.
083         * Default is none.
084         * <p>The username will be sent by Burlap via HTTP Basic Authentication.
085         * @see com.caucho.burlap.client.BurlapProxyFactory#setUser
086         */
087        public void setUsername(String username) {
088                this.proxyFactory.setUser(username);
089        }
090
091        /**
092         * Set the password that this factory should use to access the remote service.
093         * Default is none.
094         * <p>The password will be sent by Burlap via HTTP Basic Authentication.
095         * @see com.caucho.burlap.client.BurlapProxyFactory#setPassword
096         */
097        public void setPassword(String password) {
098                this.proxyFactory.setPassword(password);
099        }
100
101        /**
102         * Set whether overloaded methods should be enabled for remote invocations.
103         * Default is "false".
104         * @see com.caucho.burlap.client.BurlapProxyFactory#setOverloadEnabled
105         */
106        public void setOverloadEnabled(boolean overloadEnabled) {
107                this.proxyFactory.setOverloadEnabled(overloadEnabled);
108        }
109
110
111        @Override
112        public void afterPropertiesSet() {
113                super.afterPropertiesSet();
114                prepare();
115        }
116
117        /**
118         * Initialize the Burlap proxy for this interceptor.
119         * @throws RemoteLookupFailureException if the service URL is invalid
120         */
121        public void prepare() throws RemoteLookupFailureException {
122                try {
123                        this.burlapProxy = createBurlapProxy(this.proxyFactory);
124                }
125                catch (MalformedURLException ex) {
126                        throw new RemoteLookupFailureException("Service URL [" + getServiceUrl() + "] is invalid", ex);
127                }
128        }
129
130        /**
131         * Create the Burlap proxy that is wrapped by this interceptor.
132         * @param proxyFactory the proxy factory to use
133         * @return the Burlap proxy
134         * @throws MalformedURLException if thrown by the proxy factory
135         * @see com.caucho.burlap.client.BurlapProxyFactory#create
136         */
137        protected Object createBurlapProxy(BurlapProxyFactory proxyFactory) throws MalformedURLException {
138                Assert.notNull(getServiceInterface(), "Property 'serviceInterface' is required");
139                return proxyFactory.create(getServiceInterface(), getServiceUrl());
140        }
141
142
143        @Override
144        public Object invoke(MethodInvocation invocation) throws Throwable {
145                if (this.burlapProxy == null) {
146                        throw new IllegalStateException("BurlapClientInterceptor is not properly initialized - " +
147                                        "invoke 'prepare' before attempting any operations");
148                }
149
150                ClassLoader originalClassLoader = overrideThreadContextClassLoader();
151                try {
152                        return invocation.getMethod().invoke(this.burlapProxy, invocation.getArguments());
153                }
154                catch (InvocationTargetException ex) {
155                        Throwable targetEx = ex.getTargetException();
156                        if (targetEx instanceof BurlapRuntimeException) {
157                                Throwable cause = targetEx.getCause();
158                                throw convertBurlapAccessException(cause != null ? cause : targetEx);
159                        }
160                        else if (targetEx instanceof UndeclaredThrowableException) {
161                                UndeclaredThrowableException utex = (UndeclaredThrowableException) targetEx;
162                                throw convertBurlapAccessException(utex.getUndeclaredThrowable());
163                        }
164                        else {
165                                throw targetEx;
166                        }
167                }
168                catch (Throwable ex) {
169                        throw new RemoteProxyFailureException(
170                                        "Failed to invoke Burlap proxy for remote service [" + getServiceUrl() + "]", ex);
171                }
172                finally {
173                        resetThreadContextClassLoader(originalClassLoader);
174                }
175        }
176
177        /**
178         * Convert the given Burlap access exception to an appropriate
179         * Spring RemoteAccessException.
180         * @param ex the exception to convert
181         * @return the RemoteAccessException to throw
182         */
183        protected RemoteAccessException convertBurlapAccessException(Throwable ex) {
184                if (ex instanceof ConnectException) {
185                        return new RemoteConnectFailureException(
186                                        "Cannot connect to Burlap remote service at [" + getServiceUrl() + "]", ex);
187                }
188                else {
189                        return new RemoteAccessException(
190                                "Cannot access Burlap remote service at [" + getServiceUrl() + "]", ex);
191                }
192        }
193
194}