HtmlCompressorDirective.java

  1. /*
  2.  *    Copyright 2009-2022 the original author or authors.
  3.  *
  4.  *    Licensed under the Apache License, Version 2.0 (the "License");
  5.  *    you may not use this file except in compliance with the License.
  6.  *    You may obtain a copy of the License at
  7.  *
  8.  *       http://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  *    Unless required by applicable law or agreed to in writing, software
  11.  *    distributed under the License is distributed on an "AS IS" BASIS,
  12.  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  *    See the License for the specific language governing permissions and
  14.  *    limitations under the License.
  15.  */
  16. package com.googlecode.htmlcompressor.velocity;

  17. import com.google.javascript.jscomp.CompilationLevel;
  18. import com.googlecode.htmlcompressor.compressor.ClosureJavaScriptCompressor;
  19. import com.googlecode.htmlcompressor.compressor.HtmlCompressor;

  20. import java.io.IOException;
  21. import java.io.StringWriter;
  22. import java.io.Writer;

  23. import org.apache.velocity.context.InternalContextAdapter;
  24. import org.apache.velocity.exception.MethodInvocationException;
  25. import org.apache.velocity.exception.TemplateInitException;
  26. import org.apache.velocity.runtime.RuntimeServices;
  27. import org.apache.velocity.runtime.directive.Directive;
  28. import org.apache.velocity.runtime.parser.node.Node;

  29. /**
  30.  * Velocity directive that compresses an HTML content within #compressHtml ... #end block. Compression parameters are
  31.  * set by default (no JavaScript and CSS compression).
  32.  *
  33.  * @author <a href="mailto:serg472@gmail.com">Sergiy Kovalchuk</a>
  34.  *
  35.  * @see HtmlCompressor
  36.  */
  37. public class HtmlCompressorDirective extends Directive {

  38.     /** The Constant htmlCompressor. */
  39.     private static final HtmlCompressor htmlCompressor = new HtmlCompressor();

  40.     @Override
  41.     public String getName() {
  42.         return "compressHtml";
  43.     }

  44.     @Override
  45.     public int getType() {
  46.         return BLOCK;
  47.     }

  48.     @Override
  49.     public void init(RuntimeServices rs, InternalContextAdapter context, Node node) throws TemplateInitException {
  50.         super.init(rs, context, node);
  51.         log = rs.getLog();

  52.         boolean compressJavaScript = rs.getBoolean("userdirective.compressHtml.compressJavaScript", false);

  53.         // set compressor properties
  54.         htmlCompressor.setEnabled(rs.getBoolean("userdirective.compressHtml.enabled", true));
  55.         htmlCompressor.setRemoveComments(rs.getBoolean("userdirective.compressHtml.removeComments", true));
  56.         htmlCompressor.setRemoveMultiSpaces(rs.getBoolean("userdirective.compressHtml.removeMultiSpaces", true));
  57.         htmlCompressor.setRemoveIntertagSpaces(rs.getBoolean("userdirective.compressHtml.removeIntertagSpaces", false));
  58.         htmlCompressor.setRemoveQuotes(rs.getBoolean("userdirective.compressHtml.removeQuotes", false));
  59.         htmlCompressor.setPreserveLineBreaks(rs.getBoolean("userdirective.compressHtml.preserveLineBreaks", false));
  60.         htmlCompressor.setCompressJavaScript(compressJavaScript);
  61.         htmlCompressor.setCompressCss(rs.getBoolean("userdirective.compressHtml.compressCss", false));
  62.         htmlCompressor.setYuiJsNoMunge(rs.getBoolean("userdirective.compressHtml.yuiJsNoMunge", false));
  63.         htmlCompressor.setYuiJsPreserveAllSemiColons(
  64.                 rs.getBoolean("userdirective.compressHtml.yuiJsPreserveAllSemiColons", false));
  65.         htmlCompressor.setYuiJsLineBreak(rs.getInt("userdirective.compressHtml.yuiJsLineBreak", -1));
  66.         htmlCompressor.setYuiCssLineBreak(rs.getInt("userdirective.compressHtml.yuiCssLineBreak", -1));
  67.         htmlCompressor.setSimpleDoctype(rs.getBoolean("userdirective.compressHtml.simpleDoctype", false));
  68.         htmlCompressor
  69.                 .setRemoveScriptAttributes(rs.getBoolean("userdirective.compressHtml.removeScriptAttributes", false));
  70.         htmlCompressor
  71.                 .setRemoveStyleAttributes(rs.getBoolean("userdirective.compressHtml.removeStyleAttributes", false));
  72.         htmlCompressor.setRemoveLinkAttributes(rs.getBoolean("userdirective.compressHtml.removeLinkAttributes", false));
  73.         htmlCompressor.setRemoveFormAttributes(rs.getBoolean("userdirective.compressHtml.removeFormAttributes", false));
  74.         htmlCompressor
  75.                 .setRemoveInputAttributes(rs.getBoolean("userdirective.compressHtml.removeInputAttributes", false));
  76.         htmlCompressor
  77.                 .setSimpleBooleanAttributes(rs.getBoolean("userdirective.compressHtml.simpleBooleanAttributes", false));
  78.         htmlCompressor.setRemoveJavaScriptProtocol(
  79.                 rs.getBoolean("userdirective.compressHtml.removeJavaScriptProtocol", false));
  80.         htmlCompressor.setRemoveHttpProtocol(rs.getBoolean("userdirective.compressHtml.removeHttpProtocol", false));
  81.         htmlCompressor.setRemoveHttpsProtocol(rs.getBoolean("userdirective.compressHtml.removeHttpsProtocol", false));

  82.         if (compressJavaScript
  83.                 && rs.getString("userdirective.compressHtml.jsCompressor", HtmlCompressor.JS_COMPRESSOR_YUI)
  84.                         .equalsIgnoreCase(HtmlCompressor.JS_COMPRESSOR_CLOSURE)) {
  85.             String closureOptLevel = rs.getString("userdirective.compressHtml.closureOptLevel",
  86.                     ClosureJavaScriptCompressor.COMPILATION_LEVEL_SIMPLE);

  87.             ClosureJavaScriptCompressor closureCompressor = new ClosureJavaScriptCompressor();
  88.             if (closureOptLevel.equalsIgnoreCase(ClosureJavaScriptCompressor.COMPILATION_LEVEL_ADVANCED)) {
  89.                 closureCompressor.setCompilationLevel(CompilationLevel.ADVANCED_OPTIMIZATIONS);
  90.             } else if (closureOptLevel.equalsIgnoreCase(ClosureJavaScriptCompressor.COMPILATION_LEVEL_WHITESPACE)) {
  91.                 closureCompressor.setCompilationLevel(CompilationLevel.WHITESPACE_ONLY);
  92.             } else {
  93.                 closureCompressor.setCompilationLevel(CompilationLevel.SIMPLE_OPTIMIZATIONS);
  94.             }

  95.             htmlCompressor.setJavaScriptCompressor(closureCompressor);
  96.         }
  97.     }

  98.     @Override
  99.     public boolean render(InternalContextAdapter context, Writer writer, Node node)
  100.             throws IOException, MethodInvocationException {

  101.         // render content
  102.         StringWriter content = new StringWriter();
  103.         node.jjtGetChild(0).render(context, content);

  104.         // compress
  105.         try {
  106.             writer.write(htmlCompressor.compress(content.toString()));
  107.         } catch (Exception e) {
  108.             writer.write(content.toString());
  109.             String msg = "Failed to compress content: " + content.toString();
  110.             log.error(msg, e);
  111.             throw new RuntimeException(msg, e);

  112.         }
  113.         return true;

  114.     }

  115. }