/*******************************************************************************
* Copyright (c) 2007, 2014 compeople AG and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* compeople AG - initial API and implementation
*******************************************************************************/
package org.eclipse.riena.communication.publisher.hessian;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
import javax.servlet.GenericServlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.caucho.hessian.io.AbstractHessianOutput;
import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.caucho.hessian.io.HessianOutput;
import com.caucho.hessian.io.SerializerFactory;
import com.caucho.hessian.server.HessianSkeleton;
import org.osgi.service.log.LogService;
import org.eclipse.equinox.log.Logger;
import org.eclipse.riena.communication.core.RemoteServiceDescription;
import org.eclipse.riena.communication.core.zipsupport.ReusableBufferedInputStream;
import org.eclipse.riena.core.Log4r;
import org.eclipse.riena.core.exception.IExceptionHandlerManager;
import org.eclipse.riena.core.service.Service;
import org.eclipse.riena.internal.communication.factory.hessian.serializer.RienaSerializerFactory;
import org.eclipse.riena.internal.communication.publisher.hessian.Activator;
import org.eclipse.riena.internal.communication.publisher.hessian.HessianRemoteServicePublisher;
import org.eclipse.riena.internal.communication.publisher.hessian.MessageContext;
import org.eclipse.riena.internal.communication.publisher.hessian.MessageContextHolder;
/**
* TODO: JavaDoc
*/
@SuppressWarnings("serial")
public class RienaHessianDispatcherServlet extends GenericServlet {
private SerializerFactory serializerFactory = null;
private final static Logger LOGGER = Log4r.getLogger(Activator.getDefault(), RienaHessianDispatcherServlet.class);
@SuppressWarnings("restriction")
@Override
public void init(final ServletConfig config) throws ServletException {
super.init(config);
serializerFactory = new SerializerFactory();
serializerFactory.setAllowNonSerializable(true);
serializerFactory.addFactory(new RienaSerializerFactory());
LOGGER.log(LogService.LOG_DEBUG, "initialized"); //$NON-NLS-1$
}
@Override
public void service(final ServletRequest req, final ServletResponse res) throws ServletException, IOException {
final HttpServletRequest httpReq = (HttpServletRequest) req;
final HttpServletResponse httpRes = (HttpServletResponse) res;
// set the message context
MessageContextHolder.setMessageContext(new MessageContext(httpReq, httpRes));
final HessianRemoteServicePublisher publisher = getPublisher();
if (publisher == null) {
if (httpReq.getMethod().equals("GET")) { //$NON-NLS-1$
if (httpReq.getRemoteHost().equals("127.0.0.1")) { //$NON-NLS-1$
final PrintWriter pw = new PrintWriter(res.getOutputStream());
pw.write("no webservices available"); //$NON-NLS-1$
pw.flush();
pw.close();
return;
} else {
httpRes.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "Hessian requires POST"); //$NON-NLS-1$
return;
}
} else {
httpRes.sendError(HttpServletResponse.SC_NOT_FOUND, "webservice not found"); //$NON-NLS-1$
return;
}
}
String requestURI = httpReq.getRequestURI();
final String contextPath = httpReq.getContextPath();
if (contextPath.length() > 1) {
requestURI = requestURI.substring(contextPath.length());
}
final RemoteServiceDescription rsd = publisher.findService(requestURI);
log("call " + rsd); //$NON-NLS-1$
if (httpReq.getMethod().equals("GET")) { //$NON-NLS-1$
if (httpReq.getRemoteHost().equals("127.0.0.1")) { //$NON-NLS-1$
final PrintWriter pw = new PrintWriter(res.getOutputStream());
if (rsd == null) {
pw.write("call received from browser, no remote service registered with this URL"); //$NON-NLS-1$
} else {
pw.write("calls " + rsd); //$NON-NLS-1$
}
pw.flush();
pw.close();
return;
} else {
httpRes.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "Hessian requires POST"); //$NON-NLS-1$
return;
}
}
if (rsd == null) {
httpRes.sendError(HttpServletResponse.SC_NOT_FOUND, "unknown url :" + httpReq.getRequestURI()); //$NON-NLS-1$
return;
}
final String gzip = httpReq.getHeader("Content-Encoding"); //$NON-NLS-1$
final boolean gzipFlag = "x-hessian-gzip".equals(gzip); //$NON-NLS-1$
boolean inputWasGZIP = false;
InputStream requestInputStream = httpReq.getInputStream();
if (gzipFlag) {
final BufferedInputStream tempInput = new ReusableBufferedInputStream(requestInputStream);
if (tempInput.markSupported()) {
tempInput.mark(20);
final int readMAGIC = tempInput.read() + tempInput.read() * 256;
inputWasGZIP = (readMAGIC == GZIPInputStream.GZIP_MAGIC);
tempInput.reset();
}
requestInputStream = inputWasGZIP ? new GZIPInputStream(tempInput) : tempInput;
}
final Hessian2Input inp = new Hessian2Input(requestInputStream);
inp.setSerializerFactory(serializerFactory);
inp.setCloseStreamOnClose(true);
final int code = inp.read();
if (code != 'c') {
if (code == -1) {
LOGGER.log(LogService.LOG_WARNING, "CLIENT connected but did NOT send data for URL '" + httpReq.getRequestURI() + "'"); //$NON-NLS-1$ //$NON-NLS-2$
return;
}
throw new IOException("expected 'c' in hessian input at " + code); //$NON-NLS-1$
}
final int major = inp.read();
inp.read(); // read/skip the minor version - not used currently
//if (inputWasGZIP) {
if (gzipFlag) {
httpRes.setHeader("Content-Encoding", "x-hessian-gzip"); //$NON-NLS-1$//$NON-NLS-2$
}
OutputStream outputStream = httpRes.getOutputStream();
//if (inputWasGZIP) {
if (gzipFlag) {
outputStream = new GZIPOutputStream(outputStream);
}
AbstractHessianOutput out;
if (major >= 2) {
out = new Hessian2Output(outputStream);
((Hessian2Output) out).setCloseStreamOnClose(true);
} else {
out = new HessianOutput(outputStream);
}
out.setSerializerFactory(serializerFactory);
// TODO TCCL causes problems wit log4j: http://articles.qos.ch/classloader.html
// final ClassLoader original = Thread.currentThread().getContextClassLoader();
try {
// Thread.currentThread().setContextClassLoader(new ServiceClassLoader(original, rsd.getBundle()));
final HessianSkeleton sk = new HessianSkeleton(rsd.getService(), rsd.getServiceInterfaceClass());
sk.invoke(inp, out);
} catch (final Throwable t) {
Throwable t2 = t;
while (t2.getCause() != null) {
t2 = t2.getCause();
}
LOGGER.log(LogService.LOG_ERROR, t.getMessage() + " in service:" + rsd, t2);
Service.get(IExceptionHandlerManager.class).handleException(t2);
throw new ServletException(t);
} finally {
inp.close();
out.close(); // Hessian2Output forgets to close if the service throws an exception
// Thread.currentThread().setContextClassLoader(original);
}
}
/**
*
* @return the publisher
*/
protected HessianRemoteServicePublisher getPublisher() {
return Activator.getDefault().getPublisher();
}
}