Interesting idea, I would love to see some performance metrics.

regards Malcolm Edgar

On 3/24/07, yoursoft <[EMAIL PROTECTED]> wrote:
Ok, a new version is available. This is an extended WebappLoader class,
with in memory compression.
I would like to make a "general" class, that can use "any"
ResourceLoader, than Chris suggested (when will have more time to make it).
Thank to Chris and Nathan for suggest good programing tips. :-)

package com.ys.velocity;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;

import org.apache.commons.collections.ExtendedProperties;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.exception.VelocityException;
import org.apache.velocity.runtime.resource.util.StringResource;
import org.apache.velocity.tools.view.servlet.WebappLoader;

/**
* A compressor for templates before cached and parsed by any loader.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Lutischan Ferenc</a>
*/
public class HTMLCompressFilter extends WebappLoader {

   private static final String ALPHA =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_$\\";
   private static final String SPECIAL = "{};=*/+-%()[]<>"+(char) 10;
   private static final String END_LINE = "{};=*/+-%([<>"+(char) 10;
     /**
    * Get an InputStream so that the Runtime can build a
    * template with it.
    *
    * @param templateName name of template to get
    * @return InputStream containing the compressed template
    * @throws ResourceNotFoundException if template not found
    *         in the file template path.
    */
   public InputStream getResourceStream(String templateName)
   throws ResourceNotFoundException {
       InputStream in = super.getResourceStream(templateName);
       return getCompressedStream(in);
   }
     /**
    * Compress the html stream.
    * @param in The input stream of template.
    * @return A compressed bytestream.
    */
   private InputStream getCompressedStream(InputStream in){
byte [] origBytes = getBytesFromInputStream(in);
             byte newBytes[] = compressHTML(origBytes);
       rsvc.info("Compressed template. Original length:
"+origBytes.length+ " New length: " + newBytes.length);
       return new ByteArrayInputStream(newBytes);
   }
     /**
    * Compress input html byte array.
    * @param origBytes input byte array.
    * @return compressed byte array.
    */
   private byte[] compressHTML(byte[] origBytes) {
       byte newBytes[] = null;
       newBytes = new byte[origBytes.length];
       int i = 0;
       int j = 0;
       int end = 0;
             for (i = 0; i < origBytes.length; i++) {
           byte curByte = origBytes[i];
           switch (curByte) {
               case 32: case 9:// space
                   if (j > 0 && newBytes[j-1] != 32) { // only one space
                       if (origBytes[i+1] == '<') {
                           if (!checkTag(i, origBytes, "/div>")
                           && !checkTag(i, origBytes, "/body>")
                           && !checkTag(i, origBytes, "/tr>")
                           && !checkTag(i, origBytes, "option>")
                           && !checkTag(i, origBytes, "/html>")) {
                               newBytes[j] = 32;
                               j++;
                                                         }
                       } else {
                           newBytes[j] = 32;
                           j++;
                       }
                   }
                   break;
               case 10: case 13: // skip lf, cr
                   break;
               case '<': // tag begining
                   if ( checkTag(i, origBytes, "pre") ) {
                       end = getTagEnd(i, origBytes, "/pre>");
                       System.arraycopy(origBytes, i, newBytes, j,
end-i+1);
                       j+=end-i+1;
                       i = end;
                   } else if ( checkTag(i, origBytes, "textarea") ) {
                       end = getTagEnd(i, origBytes, "/textarea>");
                       System.arraycopy(origBytes, i, newBytes, j,
end-i+1);
                       j+=end-i+1;
                       i = end;
                   } else if (checkTag(i, origBytes, "script")){
                       end = getTagEnd(i, origBytes, "/script>");
                       byte newJs[] = getCompressedJs(origBytes, i, end);
                       System.arraycopy(newJs, 0, newBytes, j,
newJs.length);
                       j+=newJs.length;
                       i = end;
                   } else if (checkTag(i, origBytes, "style")) {
                       end = getTagEnd(i, origBytes, "/style>");
                       byte newCSS[] = getCompressedCSS(origBytes, i, end);
                       System.arraycopy(newCSS, 0, newBytes, j,
newCSS.length);
                       j+=newCSS.length;
                       i = end;
                   } else if (checkTag(i, origBytes, "<!--")) { // comment
                       i = skipComment(i, origBytes);
                   } else {
                       newBytes[j] = '<';
                       j++;
                   }
                   break;
               default:
                   newBytes[j] = origBytes[i];
                   j++;
                   break;
           }
       }
             byte result[] = new byte[j];
       System.arraycopy(newBytes, 0, result, 0, j);
       return result;
   }
     /**
    * Check from given position, in the given byte array, the given tag.
    * @param i from position
    * @param origBytes in the byte array
    * @param tag the tag (e.g. "/div>")
    * @return true if found, false if not found.
    */
   private boolean checkTag(int i, byte[] origBytes, String tag) {
       String upperTag = tag.toUpperCase();
             if (i + upperTag.length() >= origBytes.length) {
           return false;
       }
       String curTag = new String(origBytes, i+1, upperTag.length());
       return upperTag.equals(curTag.toUpperCase());
   }
     /**
    * Skip html comment from given position to end ("-->");
    * @param i from position
    * @param origBytes in the array
    * @return the position after end of comment.
    */
   private int skipComment(int i, byte[] origBytes) {
       int j = i;
       while (j < origBytes.length) {
           if (origBytes[j] == '-' && checkTag(j, origBytes, "->")) {
               j = j+3;
               break;
           }
           j++;
       }
       return j;
   }
     /**
    * Return the given tag end position in the byte array.
    * @param i from position
    * @param origBytes In the byte array
    * @param tag the end tag e.g. ("/span>")
    * @return the position of the end of tag.
    */
   private int getTagEnd(int i, byte[] origBytes, String tag) {
       int j = i;
       while (j < origBytes.length) {
           if (origBytes[j] == '<' && checkTag(j, origBytes, tag)) {
               j = j+tag.length();
               break;
           }
           j++;
       }
       return j;
   }
     /**
    * return the compressed javascript-byte array.
    * @param origBytes orig byte array
    * @param start from
    * @param end to end
    * @return The compressed javascript byte array
    */
   private byte[] getCompressedJs(byte[] origBytes, int start, int end) {
       boolean isHTMLComment = false;
       byte temp[] = new byte[end-start+1];
       int j= 0;
             for (int k = start; k<=end; k++) {
           byte curByte = origBytes[k];
           switch (curByte) {
               case 32: case 9:// space, tab
                   if (k<end && isAlpha(origBytes[k+1]) &&
!isSpecial(temp[j-1])) { // only one space
                       temp[j] = 32;
                       j++;
                   }
                   break;
               case 10: // lf
                   if (isHTMLComment || (j>0 && !isEndLine(temp[j-1])) ) {
                       temp[j] = 10;
                       j++;
                   }
                   break;
               case 13: // cr
                   break;
               case '/': // tag begining
                                     // if script is commented with
'<!--', '//' comment is not removed,
                   // because e.g.: '//--> </script>''
                   if ( origBytes[k+1] == '/' && !isHTMLComment ) {
                       while (k<=end && origBytes[k] != '\n') {k++;}
                   } else
                       if ( origBytes[k+1] == '*' ) {
                       k++;
                       while (k<=end && origBytes[k-1] != '*' &&
origBytes[k] != '/') {k++;}
                       } else {
                       temp[j] = origBytes[k];
                       j++;
                       }
                   break;
               case '"': // tag begining
                   while (k <= end) {
                       temp[j] = origBytes[k];
                       j++;
                       k++;
                       if (origBytes[k] == '"' ) {
                           temp[j] = origBytes[k];
                           j++;
                           break;
                       }
                   }
                   break;
               case '\'': // tag begining
                   while (k <= end) {
                       temp[j] = origBytes[k];
                       j++;
                       k++;
                       if (origBytes[k] == '\'' ) {
                           temp[j] = origBytes[k];
                           j++;
                           break;
                       }
                   }
                   break;
               case '<':
                   if (origBytes[k+1] == '!' && origBytes[k+2] == '-' &&
origBytes[k+3] == '-') {
                       isHTMLComment = true;
                   }
                   temp[j] = '<';
                   j++;
                   break;
               default:
                   temp[j] = origBytes[k];
                   j++;
                   break;
           }
       }
       byte result[] = new byte[j];
       System.arraycopy(temp, 0, result, 0, j);
       return result;
   }
     /**
    * return the compressed css-byte array.
    * @param origBytes orig byte array
    * @param start from
    * @param end to end
    * @return The compressed css-byte array
    */
   private byte[] getCompressedCSS(byte[] origBytes, int start, int end) {
       byte temp[] = new byte[end-start+1];
       int j= 0;
             for (int k = start; k<=end; k++) {
           byte curByte = origBytes[k];
           switch (curByte) {
               case 32: case 9: case 10: case 13:// space, tab
                   if (j <8) {
                       temp[j] = 32;
                       j++;
                   }
                   break;
               default:
                   temp[j] = origBytes[k];
                   j++;
                   break;
           }
       }
       byte result[] = new byte[j];
       System.arraycopy(temp, 0, result, 0, j);
       return result;
   }
     /**
    * Is the given byte is Alpha?
    * @param b The byte to check
    * @return true if is the given byte is an Alpha
    */
   private boolean isAlpha(byte b) {
       return ALPHA.indexOf((char) b)!=-1 || b > 126;
   }
     /**
    * Is the given byte is Special?
    * @param b The byte to check
    * @return true if is the given byte is a Special
    */
   private boolean isSpecial(byte b) {
       return SPECIAL.indexOf((char) b)!=-1;
   }
     /**
    * Is the given byte is a not useable end line?
    * @param b The byte to check
    * @return true if is the given byte is a not useable end line
    */
   private boolean isEndLine(byte b) {
       return END_LINE.indexOf((char) b)!=-1;
   }
     /**
    * Read from given InputStream into a byte array.
    * @param in The InputStream
    * @return The byte array
    */
   private byte[] getBytesFromInputStream(InputStream in) {
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
       byte buffer[] = new byte[4096];
       int length;
       try {                     while ( (length = in.read(buffer)) > 0 ) {
               baos.write(buffer, 0, length);
           }
       } catch (IOException ex) {
           rsvc.error(ex);
       }
             return baos.toByteArray();
   }
}


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to