Invocation avec compression sous JBoss 4

Cette page a été rédigée il y a fort fort longtemps, et n'a pas tellement été mise à jour.

 

Vous savez, moi je ne crois pas qu'il y ait de bonne ou de mauvaise page. Moi, si je devais résumer mon wiki aujourd'hui avec vous, je dirais que c'est d'abord des rencontres. Des gens qui m'ont tendu la main, peut-être à un moment où je ne pouvais pas, où j'étais seul chez moi. Et c'est assez curieux de se dire que les hasards, les rencontres forgent une destinée... Parce que quand on a le goût de la chose, quand on a le goût de la chose bien faite, le beau geste, parfois on ne trouve pas l'interlocuteur en face je dirais, le miroir qui vous aide à avancer. Alors ça n'est pas mon cas, comme je disais là, puisque moi au contraire, j'ai pu ; et je dis merci au wiki, je lui dis merci, je chante le wiki, je danse le wiki... je ne suis qu'amour ! Et finalement, quand des gens me disent « Mais comment fais-tu pour avoir cette humanité ? », je leur réponds très simplement que c'est ce goût de l'amour, ce goût donc qui m'a poussé aujourd'hui à entreprendre une construction logicielle... mais demain qui sait ? Peut-être simplement à me mettre au service de la communauté, à faire le don, le don de soi.

Cette page présente le code pour activer la compression GZip 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;
   }
}