Adding JMCR-Stable version
[Benchmarks_CSolver.git] / JMCR-Stable / real-world application / jigsaw / src / org / w3c / jigsaw / filters / TEFilter.java
diff --git a/JMCR-Stable/real-world application/jigsaw/src/org/w3c/jigsaw/filters/TEFilter.java b/JMCR-Stable/real-world application/jigsaw/src/org/w3c/jigsaw/filters/TEFilter.java
new file mode 100644 (file)
index 0000000..376570c
--- /dev/null
@@ -0,0 +1,289 @@
+// TEFilter.java\r
+// $Id: TEFilter.java,v 1.2 2010/06/15 17:52:54 smhuang Exp $\r
+// (c) COPYRIGHT MIT and INRIA, 1996.\r
+// Please first read the full copyright statement in file COPYRIGHT.html\r
+\r
+package org.w3c.jigsaw.filters;\r
+\r
+import java.io.IOException;\r
+import java.io.InputStream;\r
+import java.io.OutputStream;\r
+import java.io.PipedInputStream;\r
+import java.io.PipedOutputStream;\r
+\r
+import java.util.zip.DeflaterOutputStream;\r
+import java.util.zip.GZIPOutputStream;\r
+\r
+import org.w3c.tools.resources.Attribute;\r
+import org.w3c.tools.resources.AttributeRegistry;\r
+import org.w3c.tools.resources.ProtocolException;\r
+import org.w3c.tools.resources.ReplyInterface;\r
+import org.w3c.tools.resources.RequestInterface;\r
+import org.w3c.tools.resources.Resource;\r
+import org.w3c.tools.resources.ResourceFilter;\r
+import org.w3c.tools.resources.ResourceFrame;\r
+import org.w3c.tools.resources.StringArrayAttribute;\r
+\r
+import org.w3c.www.mime.MimeType;\r
+\r
+import org.w3c.jigsaw.http.Reply;\r
+import org.w3c.jigsaw.http.Request;\r
+\r
+import org.w3c.www.http.HttpAcceptEncoding;\r
+import org.w3c.www.http.HttpEntityMessage;\r
+import org.w3c.www.http.HttpMessage;\r
+import org.w3c.www.http.HttpRequestMessage;\r
+\r
+/**\r
+ * This filter will compress the content of replies using GZIP or whatever\r
+ * encoding scheme requested in the TE: header of the request.\r
+ * Compression is done <em>on the fly</em>. This assumes that you're really\r
+ * on a slow link, where you have lots of CPU, but not much bandwidth.\r
+ * <p>A nifty usage for that filter, is to plug it on top of a\r
+ * <code>org.w3c.jigsaw.proxy.ProxyFrame</code>, in which case it\r
+ * will encode the data when it flies out of the proxy.\r
+ */\r
+\r
+public class TEFilter extends ResourceFilter {\r
+    /**\r
+     * Attribute index - List of MIME type that we can compress\r
+     */\r
+    protected static int ATTR_MIME_TYPES = -1;\r
+\r
+    static {\r
+       Class     c = null;\r
+       Attribute a = null;\r
+       try {\r
+           c = Class.forName("org.w3c.jigsaw.filters.TEFilter");\r
+           //Added by Jeff Huang\r
+           //TODO: FIXIT\r
+       } catch (Exception ex) {\r
+           ex.printStackTrace();\r
+           System.exit(1);\r
+       }\r
+       // Register the MIME types attribute:\r
+       a = new StringArrayAttribute("mime-types"\r
+                                    , null\r
+                                    , Attribute.EDITABLE);\r
+       ATTR_MIME_TYPES = AttributeRegistry.registerAttribute(c, a);\r
+    }\r
+\r
+    /**\r
+     * The set of MIME types we are allowed to compress.\r
+     */\r
+    protected MimeType types[] = null;\r
+\r
+    // grumble... DeflateInputStream with a compression/decompression\r
+    // flag would have been better in the core API ;)\r
+    private class DataMover extends Thread {\r
+       InputStream in = null;\r
+       OutputStream out = null;\r
+\r
+       public void run() {\r
+           try {\r
+               byte buf[] = new byte[1024];\r
+               int  got   = -1;\r
+               while ((got = in.read(buf)) >= 0) \r
+                   out.write(buf, 0, got);\r
+           } catch (IOException ex) {\r
+               ex.printStackTrace();\r
+           } finally {\r
+               try { in.close(); } catch (Exception ex) {};\r
+               try { out.close(); } catch (Exception ex) {} ;\r
+           }\r
+       }\r
+\r
+       DataMover(InputStream in, OutputStream out) {\r
+           this.in  = in;\r
+           this.out = out;\r
+           setName("DataMover");\r
+           start();\r
+       }\r
+    }\r
+\r
+    /**\r
+     * Catch the setting of mime types to compress.\r
+     * @param idx The attribute being set.\r
+     * @param val The new attribute value.\r
+     */\r
+\r
+    public void setValue(int idx, Object value) {\r
+       super.setValue(idx, value);\r
+       if ( idx == ATTR_MIME_TYPES ) {\r
+           synchronized (this) {\r
+               types = null;\r
+           }\r
+       }\r
+    }\r
+\r
+    \r
+    /**\r
+     * Get the set of MIME types to match:\r
+     * @return An array of MimeType instances.\r
+     */\r
+\r
+    public synchronized MimeType[] getMimeTypes() {\r
+       if ( types == null ) {\r
+           String strtypes[] = (String[]) getValue(ATTR_MIME_TYPES, null);\r
+           if ( strtypes == null )\r
+               return null;\r
+           types = new MimeType[strtypes.length];\r
+           for (int i = 0 ; i < types.length ; i++) {\r
+               try {\r
+                   types[i] = new MimeType(strtypes[i]);\r
+               } catch (Exception ex) {\r
+                   types[i] = null;\r
+               }\r
+           }\r
+       }\r
+       return types;\r
+    }\r
+\r
+    protected double getCompressibilityFactor(Reply reply) {\r
+        // Match possible mime types:\r
+       MimeType t[]     = getMimeTypes();\r
+       if ( t != null ) {\r
+           for (int i = 0 ; i < t.length ; i++) {\r
+               if ( t[i] == null )\r
+                   continue;\r
+               if ( t[i].match(reply.getContentType()) > 0 ) {\r
+                   String enc[] = reply.getContentEncoding();\r
+                   if (enc != null ) {\r
+                       for (int j=0; j< enc.length; j++) {\r
+                           if ((enc[j].indexOf("gzip") >= 0) ||\r
+                               (enc[j].indexOf("deflate") >= 0) ||\r
+                               (enc[j].indexOf("compress") >= 0)) {\r
+                               // no more compression\r
+                               return 0.001;\r
+                           }\r
+                       }\r
+                   }\r
+                   return 1.0;\r
+               }\r
+           }\r
+       }\r
+       return 0.001; // minimal value\r
+    }\r
+\r
+    protected void doEncoding(HttpAcceptEncoding enc, Reply reply) {\r
+        // Anything to compress ?\r
+       if ( ! reply.hasStream() )\r
+           return;\r
+       // Match possible mime types:\r
+       MimeType t[]     = getMimeTypes();\r
+       boolean  matched = false;\r
+       if ( t != null ) {\r
+           for (int i = 0 ; i < t.length ; i++) {\r
+               if ( t[i] == null )\r
+                   continue;\r
+               if ( t[i].match(reply.getContentType()) > 0 ) {\r
+                   matched = true;\r
+                   break;\r
+               }\r
+           }\r
+       }\r
+       if ( ! matched ) \r
+           return;     \r
+       InputStream orig_is = reply.openStream();\r
+       // do the gzip encoding\r
+       if (enc.getEncoding().equals("gzip")) {\r
+           try {\r
+               PipedOutputStream gzpout = new PipedOutputStream();\r
+               PipedInputStream  gzpin  = new PipedInputStream(gzpout);\r
+               new DataMover(reply.openStream()\r
+                             , new GZIPOutputStream(gzpout));\r
+               reply.setStream(gzpin);\r
+           } catch (IOException ex) {\r
+               ex.printStackTrace();\r
+               reply.setStream(orig_is);\r
+               return;\r
+           }\r
+           reply.addTransferEncoding("gzip");\r
+           reply.setContentLength(-1);\r
+       } else if (enc.getEncoding().equals("deflate")) {\r
+           // do the deflate encoding\r
+           try {\r
+               PipedOutputStream zpout = new PipedOutputStream();\r
+               PipedInputStream  zpin  = new PipedInputStream(zpout);\r
+               new DataMover(reply.openStream()\r
+                             , new DeflaterOutputStream(zpout));\r
+               reply.setStream(zpin);\r
+           } catch (IOException ex) {\r
+               ex.printStackTrace();\r
+               reply.setStream(orig_is);\r
+               return;\r
+           }\r
+           reply.addTransferEncoding("deflate");\r
+           reply.setContentLength(-1);\r
+       }\r
+       return;\r
+    }\r
+\r
+    /**\r
+     * @param request The original request.\r
+     * @param reply It's original reply. \r
+     * @return A Reply instance, or <strong>null</strong> if processing \r
+     * should continue normally. \r
+     * @exception ProtocolException If processing should be interrupted,  \r
+     * because an abnormal situation occured. \r
+     */\r
+    public ReplyInterface outgoingFilter(RequestInterface req,\r
+                                        ReplyInterface rep) \r
+       throws ProtocolException\r
+    {\r
+      Request request = (Request) req;\r
+      Reply   reply   = (Reply) rep;\r
+      HttpAcceptEncoding encs[] = request.getTE();\r
+      String trenc[] = reply.getTransferEncoding();\r
+      \r
+      // Anything to compress ?\r
+      if ( ! reply.hasStream() )\r
+         return null;\r
+      \r
+      if (trenc != null) {\r
+         // don't mess with already encoded stuff\r
+         // otherwise we have to dechunk/rechunk and it would be painful\r
+         return null;\r
+      }\r
+\r
+      if (encs != null) { // identity and chucked always ok\r
+         double max = -1.0;\r
+         double identity = 1.0; // some dummy default values\r
+         double chunked = 1.0;\r
+         double comp_factor = getCompressibilityFactor(reply);\r
+         HttpAcceptEncoding best = null;\r
+         for (int i = 0 ; i < encs.length ; i++) {\r
+             if (encs[i].getEncoding().equals("identity")) {\r
+                 identity = encs[i].getQuality();\r
+                 continue;\r
+             } else if (encs[i].getEncoding().equals("chunked")) {\r
+                 chunked = encs[i].getQuality();\r
+                 continue;\r
+             } else if (encs[i].getEncoding().equals("trailers")) {\r
+                 // means that the client understand trailers.. check \r
+                 // that with pending trailers impl\r
+                 // req.setTrailerOk();\r
+                 continue;\r
+             }\r
+             if (encs[i].getQuality() * comp_factor > max) {\r
+                 best = encs[i];\r
+                 max = encs[i].getQuality() * comp_factor;\r
+                 if (max == 1.0) // can't be better\r
+                     break;\r
+             }\r
+         }\r
+         if (best != null && (max >= identity)) {\r
+             doEncoding(best, reply);\r
+         } else {\r
+             if (identity > 0) {\r
+                 if (chunked > identity)\r
+                     reply.setContentLength(-1);\r
+             } else {\r
+                 // spec says: chunked always acceptable\r
+                 reply.setContentLength(-1);\r
+             }\r
+         }\r
+      }\r
+      return null;\r
+    }\r
+}\r