All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.gwt.user.server.rpc.OpenRemoteServiceServlet Maven / Gradle / Ivy

There is a newer version: 7.0.0.pre5
Show newest version
/*
 * Copyright 2006 Google Inc.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package com.google.gwt.user.server.rpc;

import com.google.gwt.user.client.rpc.RemoteService;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.impl.ServerSerializableTypeOracle;
import com.google.gwt.user.server.rpc.impl.ServerSerializableTypeOracleImpl;
import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamReader;
import com.google.gwt.user.server.rpc.impl.ServerSerializationStreamWriter;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import java.util.zip.GZIPOutputStream;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * The servlet base class for your RPC service implementations that
 * automatically deserializes incoming requests from the client and serializes
 * outgoing responses for client/server RPCs.
 * 
 * This version is a modified version of RemoteServiceServlet. The only changes
 * have been to remove some final declarations and to convert some private
 * methods to protected to allow extension of this class.
 */
public class OpenRemoteServiceServlet extends HttpServlet
{
    /*
     * These members are used to get and set the different HttpServletResponse
     * and HttpServletRequest headers.
     */
    private static final String ACCEPT_ENCODING="Accept-Encoding";
    private static final String CHARSET_UTF8="UTF-8";
    private static final String CONTENT_ENCODING="Content-Encoding";
    private static final String CONTENT_ENCODING_GZIP="gzip";
    private static final String CONTENT_TYPE_TEXT_PLAIN_UTF8="text/plain; charset=utf-8";
    private static final String GENERIC_FAILURE_MSG="The call failed on the server; see server log for details";
    private static final HashMap TYPE_NAMES;

    /**
     * Controls the compression threshold at and below which no compression will
     * take place.
     */
    private static final int UNCOMPRESSED_BYTE_SIZE_LIMIT=256;

    /**
     * Return true if the response object accepts Gzip encoding. This is done by
     * checking that the accept-encoding header specifies gzip as a supported
     * encoding.
     */
    private static boolean acceptsGzipEncoding(HttpServletRequest request)
    {
        assert (request != null);

        String acceptEncoding=request.getHeader(ACCEPT_ENCODING);
        if (null==acceptEncoding)
        {
            return false;
        }

        return (acceptEncoding.indexOf(CONTENT_ENCODING_GZIP)!=-1);
    }

    /**
     * This method attempts to estimate the number of bytes that a string will
     * consume when it is sent out as part of an HttpServletResponse.
     * 
     * This really a hack since we are assuming that every character will
     * consume two bytes upon transmission. This is definitely not true since
     * some characters actually consume more than two bytes and some consume
     * less. This is even less accurate if the string is converted to UTF8.
     * However, it does save us from converting every string that we plan on
     * sending back to UTF8 just to determine that we should not compress it.
     */
    private static int estimateByteSize(final String buffer)
    {
        return (buffer.length()*2);
    }

    /**
     * Find the invoked method on either the specified interface or any super.
     */
    private static Method findInterfaceMethod(Class intf, String methodName, Class[] paramTypes, boolean includeInherited)
    {
        try
        {
            return intf.getDeclaredMethod(methodName,paramTypes);
        }
        catch (NoSuchMethodException e)
        {
            if (includeInherited)
            {
                Class[] superintfs=intf.getInterfaces();
                for (int i=0; iHttpServletRequest object for the current call.
     * It is stored thread-locally so that simultaneous invocations can have
     * different request objects.
     */
    protected final HttpServletRequest getThreadLocalRequest()
    {
        return (HttpServletRequest)perThreadRequest.get();
    }

    /**
     * Gets the HttpServletResponse object for the current call.
     * It is stored thread-locally so that simultaneous invocations can have
     * different response objects.
     */
    protected final HttpServletResponse getThreadLocalResponse()
    {
        return (HttpServletResponse)perThreadResponse.get();
    }

    /**
     * Override this method to examine the serialized response that will be
     * returned to the client. The default implementation does nothing and need
     * not be called by subclasses.
     */
    protected void onAfterResponseSerialized(String serializedResponse)
    {
    }

    /**
     * Override this method to examine the serialized version of the request
     * payload before it is deserialized into objects. The default
     * implementation does nothing and need not be called by subclasses.
     */
    protected void onBeforeRequestDeserialized(String serializedRequest)
    {
    }

    /**
     * Determines whether the response to a given servlet request should or
     * should not be GZIP compressed. This method is only called in cases where
     * the requestor accepts GZIP encoding.
     * 
     * 

* This implementation currently returns true if the response * string's estimated byte length is longer than 256 bytes. Subclasses can * override this logic. *

* * @param request * the request being served * @param response * the response that will be written into * @param responsePayload * the payload that is about to be sent to the client * @return true if responsePayload should be GZIP compressed, * otherwise false. */ protected boolean shouldCompressResponse(HttpServletRequest request, HttpServletResponse response, String responsePayload) { return estimateByteSize(responsePayload)>UNCOMPRESSED_BYTE_SIZE_LIMIT; } /** * @param stream * @param responseType * @param responseObj * @param isException * @return */ private String createResponse(ServerSerializationStreamWriter stream, Class responseType, Object responseObj, boolean isException) { stream.prepareToWrite(); if (responseType!=void.class) { try { stream.serializeValue(responseObj,responseType); } catch (SerializationException e) { responseObj=e; isException=true; } } String bufferStr=(isException?"{EX}":"{OK}")+stream.toString(); return bufferStr; } /** * Returns the {@link Class} instance for the named class or primitive type. * * @param name * the name of a class or primitive type * @return Class instance for the given type name * @throws ClassNotFoundException * if the named type was not found */ private Class getClassOrPrimitiveFromName(String name) throws ClassNotFoundException { Object value=TYPE_NAMES.get(name); if (value!=null) { return (Class)value; } return getClassFromName(name); } /** * Returns the {@link Class} instance for the named class. * * @param name * the name of a class or primitive type * @return Class instance for the given type name * @throws ClassNotFoundException * if the named type was not found */ private Class getClassFromName(String name) throws ClassNotFoundException { return Class.forName(name,false,this.getClass().getClassLoader()); } /** * Obtain the special package-prefixes we use to check for custom * serializers that would like to live in a package that they cannot. For * example, "java.util.ArrayList" is in a sealed package, so instead we use * this prefix to check for a custom serializer in * "com.google.gwt.user.client.rpc.core.java.util.ArrayList". Right now, * it's hard-coded because we don't have a pressing need for this mechanism * to be extensible, but it is imaginable, which is why it's implemented * this way. */ private String[] getPackagePaths() { return new String[] { "com.google.gwt.user.client.rpc.core" }; } /** * Returns true if the {@link java.lang.reflect.Method Method} definition on * the service is specified to throw the exception contained in the * InvocationTargetException or false otherwise. * * NOTE we do not check that the type is serializable here. We assume that * it must be otherwise the application would never have been allowed to * run. * * @param serviceIntfMethod * @param e * @return */ private boolean isExpectedException(Method serviceIntfMethod, Throwable cause) { assert (serviceIntfMethod != null); assert (cause != null); Class[] exceptionsThrown=serviceIntfMethod.getExceptionTypes(); if (exceptionsThrown.length<=0) { // The method is not specified to throw any exceptions // return false; } Class causeType=cause.getClass(); for (int index=0; index




© 2015 - 2024 Weber Informatics LLC | Privacy Policy