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]

Reply via email to