Invocation avec compression sous JBoss 4


Classe info.jtips.jboss.GzHttpInvoker

package info.jtips.jboss;

import javax.management.ObjectName;

import org.jboss.invocation.Invoker;
import org.jboss.system.Registry;

public class GzHttpInvoker extends org.jboss.invocation.http.server.HttpInvoker {

   protected void startService() throws Exception {
       checkInvokerURL();
        // AH Modification Alexis Hassler 
       //    => instantiation de GzHttpInvokerProxy
       Invoker delegateInvoker = new GzHttpInvokerProxy(getInvokerURL());

       // Export the Invoker interface
       ObjectName name = super.getServiceName();
       Registry.bind(name, delegateInvoker);
       log.debug("Bound Http invoker for JMX node");
   }
}

Classe info.jtips.jboss.GzHttpInvokerProxy

package info.jtips.jboss;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.HttpURLConnection;
import java.rmi.ServerException;

import org.jboss.invocation.Invocation;
import org.jboss.invocation.InvocationException;
import org.jboss.invocation.MarshalledInvocation;
import org.jboss.invocation.http.interfaces.Util;

public class GzHttpInvokerProxy 
      extends org.jboss.invocation.http.interfaces.HttpInvokerProxy {

   public GzHttpInvokerProxy() {
       super();
   }

   public GzHttpInvokerProxy(String externalURLValue) {
       super(externalURLValue);
   }

   public Object invoke(Invocation invocation) throws Exception {
       // We are going to go through a Remote invocation, switch to a
       // Marshalled Invocation
       MarshalledInvocation mi = new MarshalledInvocation(invocation);

       if (externalURL == null)
           externalURL = Util.resolveURL(externalURLValue);
       try {
           // AH Modification Alexis Hassler => utilisation de GzHttpUtil
           Object value = GzHttpUtil.invoke(externalURL, mi);
           return value;
       } catch (InvocationException e) {
           // Unwrap the invoker servlet InvocationExceptions
           Throwable t = e.getTargetException();
           if (t instanceof Exception)
               throw (Exception) t;
           else if (t instanceof Error)
               throw (Error) t;
           throw new InvocationTargetException(t);
       } catch (IOException e) {
           throw new ServerException("IOE", e);
       }
   }
}

Classe info.jtips.jboss.GzHttpUtil

package info.jtips.jboss;

import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectStreamException;
import java.io.OutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.Authenticator;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.PrivilegedAction;
import java.security.AccessController;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLSocketFactory;

import org.jboss.invocation.Invocation;
import org.jboss.invocation.InvocationException;
import org.jboss.invocation.MarshalledValue;
import org.jboss.invocation.http.interfaces.AnyhostVerifier;
import org.jboss.invocation.http.interfaces.Util;
import org.jboss.logging.Logger;
import org.jboss.security.SecurityAssociationAuthenticator;
import org.jboss.net.ssl.SSLSocketFactoryBuilder;

public class GzHttpUtil {
   private static String REQUEST_CONTENT_TYPE = 
                          "application/x-java-serialized-object;" +       
                          "class=org.jboss.invocation.MarshalledInvocation";

   // AH Ajout Alexis Hassler => autoriser le compression
   private static String REQUEST_ACCEPT_ENCODING = "multipart/x-gzip";

   private static Logger log = Logger.getLogger(GzHttpUtil.class);

   /** A custom SSLSocketFactory builder to use for https connections */
   private static SSLSocketFactoryBuilder sslSocketFactoryBuilder;

   static class SetAuthenticator implements PrivilegedAction {
       public Object run() {
           Authenticator.setDefault(new SecurityAssociationAuthenticator());
           return null;
       }
   }

   static class ReadSSLBuilder implements PrivilegedAction {
       public Object run() {
           String value = System.getProperty(Util.SSL_FACTORY_BUILDER);
           return value;
       }
   }

   static {
       // Install the java.net.Authenticator to use
       try {
           SetAuthenticator action = new SetAuthenticator();
           AccessController.doPrivileged(action);
       } catch (Exception e) {
           log.warn("Failed to install SecurityAssociationAuthenticator", e);
       }
       ClassLoader loader = Thread.currentThread().getContextClassLoader();

       String factoryFactoryFQCN = null;
       try {
           ReadSSLBuilder action = new ReadSSLBuilder();
           factoryFactoryFQCN = 
                             (String) AccessController.doPrivileged(action);
       } catch (Exception e) {
           log.warn("Failed to read " + Util.SSL_FACTORY_BUILDER, e);
       }

       if (factoryFactoryFQCN != null) {
           try {
               Class clazz = loader.loadClass(factoryFactoryFQCN);
               sslSocketFactoryBuilder = (SSLSocketFactoryBuilder) clazz
                       .newInstance();
           } catch (Exception e) {
               log.warn("Could not instantiate SSLSocketFactoryFactory", e);
           }
       }
   }

   /**
    * Post the Invocation as a serialized MarshalledInvocation object. 
    * This is using the URL class for now but this should be improved to 
    * a cluster aware layer with full usage of HTTP 1.1 features, pooling,
    * etc.
    */
   public static Object invoke(URL externalURL, Invocation mi)
           throws Exception {
       if (log.isTraceEnabled())
           log.trace("invoke, externalURL=" + externalURL);
       /*
        * Post the MarshalledInvocation data. This is using the URL class for
        * now but this should be improved to a cluster aware layer with full
        * usage of HTTP 1.1 features, pooling, etc.
        */
       HttpURLConnection conn = (HttpURLConnection) externalURL
               .openConnection();
       Util.configureHttpsHostVerifier(conn);
       conn.setDoInput(true);
       conn.setDoOutput(true);
       conn.setRequestProperty("ContentType", REQUEST_CONTENT_TYPE);

       // AH Ajout Alexis Hassler => autoriser le compression
       conn.setRequestProperty("Accept-Encoding", REQUEST_ACCEPT_ENCODING);
       conn.setRequestMethod("POST");
       OutputStream os = conn.getOutputStream();

       ObjectOutputStream oos = new ObjectOutputStream(os);
       // Fin Ajout Alexis Hassler
       try {
           oos.writeObject(mi);
           oos.flush();
       } catch (ObjectStreamException e) {
           // This generally represents a programming/deployment error,
           // not a communication problem
           throw new InvocationException(e);
       }

       // Get the response MarshalledValue object
       InputStream is = conn.getInputStream();

       // AH Ajout Alexis Hassler => Stream de décompression
       GZIPInputStream gzis = new GZIPInputStream(is);
       ObjectInputStream ois = new ObjectInputStream(gzis);
       // ObjectInputStream ois = new ObjectInputStream(is);
       // Fin Ajout Alexis Hassler

       MarshalledValue mv = (MarshalledValue) ois.readObject();
       // A hack for jsse connection pooling (see patch ).
       ois.read();
       ois.close();
       oos.close();

       // If the encoded value is an exception throw it
       Object value = mv.get();
       if (value instanceof Exception) {
           throw (Exception) value;
       }

       return value;
   }
}