package net.contextfw.web.commons.minifier;
import java.io.IOException;
import java.net.URL;
import java.util.Iterator;
import java.util.List;
import net.contextfw.web.application.DocumentProcessor;
import net.contextfw.web.application.WebApplicationException;
import org.apache.commons.io.IOUtils;
import org.dom4j.Document;
import org.dom4j.Element;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.inject.Singleton;
import com.google.javascript.jscomp.Compiler;
import com.google.javascript.jscomp.CompilerOptions;
import com.google.javascript.jscomp.JSSourceFile;
@Singleton
public class JsMinifierServlet extends ContentServlet implements DocumentProcessor {
private static final long serialVersionUID = 1L;
private final MinifierFilter filter;
private static final Logger LOG = LoggerFactory.getLogger(JsMinifierServlet.class);
JsMinifierServlet(String host,
String minifiedPath,
MinifierFilter filter,
long started,
String version) {
super(host, minifiedPath, started, version);
this.filter = filter;
}
@Override
public void process(Document document) {
@SuppressWarnings("unchecked")
List<Element> scripts = document.selectNodes("//html/head//script[@src]");
StringBuilder sb = new StringBuilder();
Element firstMinified = null;
Iterator<Element> iter = scripts.iterator();
while (iter.hasNext()) {
Element script = iter.next();
String src = script.attributeValue("src");
LOG.info("Including JS: {}", src);
if (src.startsWith("{$contextPath}") && filter.include(src)) {
URL url = getUrl(src.replace("{$contextPath}",
this.getServletContext().getContextPath()));
if (filter.minify(src)) {
LOG.info("Minifying JS: {}", url.toString());
sb.append(compress(url)).append("\n");
} else {
try {
LOG.info("Not minifying JS: {}", url.toString());
sb.append(IOUtils.toString(url.openStream())).append("\n");
} catch (IOException e) {
throw new WebApplicationException(e);
}
}
if (firstMinified == null) {
firstMinified = script;
} else {
script.detach();
}
}
}
if (firstMinified != null) {
firstMinified.addAttribute("src", "{$contextPath}" + getMinifiedPath());
}
setContent(sb.toString());
}
private String compress(URL url) {
try {
CompilerOptions options = new CompilerOptions();
Compiler compiler = new Compiler();
JSSourceFile source = JSSourceFile.fromInputStream(url.getFile(), url.openStream());
compiler.compile(new JSSourceFile[] {}, new JSSourceFile[] { source }, options);
return compiler.toSource();
} catch (Exception e) {
throw new WebApplicationException(url.toString(), e);
}
}
@Override
protected String getContentType() {
return "application/javascript";
}
}