001: /*
002: * Copyright 2002-2007 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: * http://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:
017: package org.springframework.remoting.caucho;
018:
019: import java.lang.reflect.InvocationTargetException;
020: import java.lang.reflect.UndeclaredThrowableException;
021: import java.net.ConnectException;
022: import java.net.MalformedURLException;
023:
024: import com.caucho.burlap.client.BurlapProxyFactory;
025: import com.caucho.burlap.client.BurlapRuntimeException;
026: import org.aopalliance.intercept.MethodInterceptor;
027: import org.aopalliance.intercept.MethodInvocation;
028:
029: import org.springframework.remoting.RemoteAccessException;
030: import org.springframework.remoting.RemoteConnectFailureException;
031: import org.springframework.remoting.RemoteLookupFailureException;
032: import org.springframework.remoting.RemoteProxyFailureException;
033: import org.springframework.remoting.support.UrlBasedRemoteAccessor;
034: import org.springframework.util.Assert;
035:
036: /**
037: * Interceptor 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="http://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: */
061: public class BurlapClientInterceptor extends UrlBasedRemoteAccessor
062: implements MethodInterceptor {
063:
064: private BurlapProxyFactory proxyFactory = new BurlapProxyFactory();
065:
066: private Object burlapProxy;
067:
068: /**
069: * Set the BurlapProxyFactory instance to use.
070: * If not specified, a default BurlapProxyFactory will be created.
071: * <p>Allows to use an externally configured factory instance,
072: * in particular a custom BurlapProxyFactory subclass.
073: */
074: public void setProxyFactory(BurlapProxyFactory proxyFactory) {
075: this .proxyFactory = (proxyFactory != null ? proxyFactory
076: : new BurlapProxyFactory());
077: }
078:
079: /**
080: * Set the username that this factory should use to access the remote service.
081: * Default is none.
082: * <p>The username will be sent by Burlap via HTTP Basic Authentication.
083: * @see com.caucho.burlap.client.BurlapProxyFactory#setUser
084: */
085: public void setUsername(String username) {
086: this .proxyFactory.setUser(username);
087: }
088:
089: /**
090: * Set the password that this factory should use to access the remote service.
091: * Default is none.
092: * <p>The password will be sent by Burlap via HTTP Basic Authentication.
093: * @see com.caucho.burlap.client.BurlapProxyFactory#setPassword
094: */
095: public void setPassword(String password) {
096: this .proxyFactory.setPassword(password);
097: }
098:
099: /**
100: * Set whether overloaded methods should be enabled for remote invocations.
101: * Default is "false".
102: * @see com.caucho.burlap.client.BurlapProxyFactory#setOverloadEnabled
103: */
104: public void setOverloadEnabled(boolean overloadEnabled) {
105: this .proxyFactory.setOverloadEnabled(overloadEnabled);
106: }
107:
108: public void afterPropertiesSet() {
109: super .afterPropertiesSet();
110: prepare();
111: }
112:
113: /**
114: * Initialize the Burlap proxy for this interceptor.
115: * @throws RemoteLookupFailureException if the service URL is invalid
116: */
117: public void prepare() throws RemoteLookupFailureException {
118: try {
119: this .burlapProxy = createBurlapProxy(this .proxyFactory);
120: } catch (MalformedURLException ex) {
121: throw new RemoteLookupFailureException("Service URL ["
122: + getServiceUrl() + "] is invalid", ex);
123: }
124: }
125:
126: /**
127: * Create the Burlap proxy that is wrapped by this interceptor.
128: * @param proxyFactory the proxy factory to use
129: * @return the Burlap proxy
130: * @throws MalformedURLException if thrown by the proxy factory
131: * @see com.caucho.burlap.client.BurlapProxyFactory#create
132: */
133: protected Object createBurlapProxy(BurlapProxyFactory proxyFactory)
134: throws MalformedURLException {
135: Assert.notNull(getServiceInterface(),
136: "Property 'serviceInterface' is required");
137: return proxyFactory.create(getServiceInterface(),
138: getServiceUrl());
139: }
140:
141: public Object invoke(MethodInvocation invocation) throws Throwable {
142: if (this .burlapProxy == null) {
143: throw new IllegalStateException(
144: "BurlapClientInterceptor is not properly initialized - "
145: + "invoke 'prepare' before attempting any operations");
146: }
147:
148: try {
149: return invocation.getMethod().invoke(this .burlapProxy,
150: invocation.getArguments());
151: } catch (InvocationTargetException ex) {
152: if (ex.getTargetException() instanceof BurlapRuntimeException) {
153: BurlapRuntimeException bre = (BurlapRuntimeException) ex
154: .getTargetException();
155: Throwable rootCause = (bre.getRootCause() != null ? bre
156: .getRootCause() : bre);
157: throw convertBurlapAccessException(rootCause);
158: } else if (ex.getTargetException() instanceof UndeclaredThrowableException) {
159: UndeclaredThrowableException utex = (UndeclaredThrowableException) ex
160: .getTargetException();
161: throw convertBurlapAccessException(utex
162: .getUndeclaredThrowable());
163: }
164: throw ex.getTargetException();
165: } catch (Throwable ex) {
166: throw new RemoteProxyFailureException(
167: "Failed to invoke Burlap proxy for remote service ["
168: + getServiceUrl() + "]", ex);
169: }
170: }
171:
172: /**
173: * Convert the given Burlap access exception to an appropriate
174: * Spring RemoteAccessException.
175: * @param ex the exception to convert
176: * @return the RemoteAccessException to throw
177: */
178: protected RemoteAccessException convertBurlapAccessException(
179: Throwable ex) {
180: if (ex instanceof ConnectException) {
181: throw new RemoteConnectFailureException(
182: "Cannot connect to Burlap remote service at ["
183: + getServiceUrl() + "]", ex);
184: } else {
185: throw new RemoteAccessException(
186: "Cannot access Burlap remote service at ["
187: + getServiceUrl() + "]", ex);
188: }
189: }
190:
191: }
|