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.io.IOException;
020: import java.lang.reflect.Constructor;
021:
022: import javax.servlet.ServletException;
023: import javax.servlet.http.HttpServletRequest;
024: import javax.servlet.http.HttpServletResponse;
025:
026: import com.caucho.hessian.io.SerializerFactory;
027: import com.caucho.hessian.server.HessianSkeleton;
028:
029: import org.springframework.beans.factory.BeanInitializationException;
030: import org.springframework.beans.factory.InitializingBean;
031: import org.springframework.remoting.support.RemoteExporter;
032: import org.springframework.util.Assert;
033: import org.springframework.util.ClassUtils;
034: import org.springframework.web.HttpRequestHandler;
035: import org.springframework.web.HttpRequestMethodNotSupportedException;
036: import org.springframework.web.util.NestedServletException;
037:
038: /**
039: * HTTP request handler that exports the specified service bean as
040: * Hessian service endpoint, accessible via a Hessian proxy.
041: *
042: * <p>Hessian is a slim, binary RPC protocol.
043: * For information on Hessian, see the
044: * <a href="http://www.caucho.com/hessian">Hessian website</a>
045: *
046: * <p>This exporter will work with both Hessian 2.x and 3.x (respectively
047: * Resin 2.x and 3.x), autodetecting the corresponding skeleton class.
048: * As of Spring 2.0, it is also compatible with the new Hessian 2 protocol
049: * (a.k.a. Hessian 3.0.20+), while remaining compatible with older versions.
050: *
051: * <p>Note: Hessian services exported with this class can be accessed by
052: * any Hessian client, as there isn't any special handling involved.
053: *
054: * @author Juergen Hoeller
055: * @since 13.05.2003
056: * @see HessianClientInterceptor
057: * @see HessianProxyFactoryBean
058: * @see org.springframework.remoting.caucho.BurlapServiceExporter
059: * @see org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter
060: * @see org.springframework.remoting.rmi.RmiServiceExporter
061: */
062: public class HessianServiceExporter extends RemoteExporter implements
063: HttpRequestHandler, InitializingBean {
064:
065: private static final boolean hessian2Available = ClassUtils
066: .isPresent("com.caucho.hessian.io.Hessian2Input",
067: HessianServiceExporter.class.getClassLoader());
068:
069: private SerializerFactory serializerFactory = new SerializerFactory();
070:
071: private HessianSkeletonInvoker skeletonInvoker;
072:
073: /**
074: * Specify the Hessian SerializerFactory to use.
075: * <p>This will typically be passed in as an inner bean definition
076: * of type <code>com.caucho.hessian.io.SerializerFactory</code>,
077: * with custom bean property values applied.
078: */
079: public void setSerializerFactory(SerializerFactory serializerFactory) {
080: this .serializerFactory = (serializerFactory != null ? serializerFactory
081: : new SerializerFactory());
082: }
083:
084: /**
085: * Set whether to send the Java collection type for each serialized
086: * collection. Default is "true".
087: */
088: public void setSendCollectionType(boolean sendCollectionType) {
089: this .serializerFactory
090: .setSendCollectionType(sendCollectionType);
091: }
092:
093: public void afterPropertiesSet() {
094: prepare();
095: }
096:
097: /**
098: * Initialize this service exporter.
099: */
100: public void prepare() {
101: HessianSkeleton skeleton = null;
102:
103: try {
104: try {
105: // Try Hessian 3.x (with service interface argument).
106: Constructor ctor = HessianSkeleton.class
107: .getConstructor(new Class[] { Object.class,
108: Class.class });
109: checkService();
110: checkServiceInterface();
111: skeleton = (HessianSkeleton) ctor
112: .newInstance(new Object[] {
113: getProxyForService(),
114: getServiceInterface() });
115: } catch (NoSuchMethodException ex) {
116: // Fall back to Hessian 2.x (without service interface argument).
117: Constructor ctor = HessianSkeleton.class
118: .getConstructor(new Class[] { Object.class });
119: skeleton = (HessianSkeleton) ctor
120: .newInstance(new Object[] { getProxyForService() });
121: }
122: } catch (Throwable ex) {
123: throw new BeanInitializationException(
124: "Hessian skeleton initialization failed", ex);
125: }
126:
127: if (hessian2Available) {
128: // Hessian 2 (version 3.0.20+).
129: this .skeletonInvoker = new Hessian2SkeletonInvoker(
130: skeleton, this .serializerFactory);
131: } else {
132: // Hessian 1 (version 3.0.19-).
133: this .skeletonInvoker = new Hessian1SkeletonInvoker(
134: skeleton, this .serializerFactory);
135: }
136: }
137:
138: /**
139: * Processes the incoming Hessian request and creates a Hessian response.
140: */
141: public void handleRequest(HttpServletRequest request,
142: HttpServletResponse response) throws ServletException,
143: IOException {
144:
145: Assert.notNull(this .skeletonInvoker,
146: "HessianServiceExporter has not been initialized");
147:
148: if (!"POST".equals(request.getMethod())) {
149: throw new HttpRequestMethodNotSupportedException("POST",
150: "HessianServiceExporter only supports POST requests");
151: }
152:
153: try {
154: this .skeletonInvoker.invoke(request.getInputStream(),
155: response.getOutputStream());
156: } catch (Throwable ex) {
157: throw new NestedServletException(
158: "Hessian skeleton invocation failed", ex);
159: }
160: }
161:
162: }
|