Package com.greenscriptool

Source Code of com.greenscriptool.Minimizer

package com.greenscriptool;

import com.asual.lesscss.LessEngine;
import com.asual.lesscss.LessException;
import com.greenscriptool.utils.*;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jcoffeescript.JCoffeeScriptCompileException;
import org.jcoffeescript.JCoffeeScriptCompiler;

import javax.inject.Inject;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Minimizer implements IMinimizer {

    private static Log logger_ = LogFactory.getLog(Minimizer.class);

    private boolean minimize_;
    private boolean compress_;
    private boolean useCache_;
    private boolean inMemory_;
    private boolean processInline_;

    private FileCache cache_ = null;
    private String resourcePath_ = null;
    private String rootDir_ = null;

    private String ctxPath_ = null;
    private String resourceUrlRoot_ = null;
    private String resourceUrlPath_ = null;
    private String cacheUrlPath_ = null;
    private String resourcesParam_ = null;

    private ICompressor compressor_;
    private ResourceType type_;

    private LessEngine less_;
    private JCoffeeScriptCompiler coffee_;

    private void init_(ICompressor compressor, ResourceType type) {
        if (null == compressor)
            throw new NullPointerException();
        compressor_ = compressor;
        type_ = type;
        less_ = new LessEngine();
        coffee_ = new JCoffeeScriptCompiler();
    }

    public Minimizer(ResourceType type) {
        ICompressor compressor = type == ResourceType.CSS ? new YUICompressor(type) : new SimpleJSCompressor(type);
        init_(compressor, type);
    }

    @Inject
    public Minimizer(ICompressor compressor, ResourceType type) {
        init_(compressor, type);
    }

    @Override
    public void enableDisableMinimize(boolean enable) {
        minimize_ = enable || ResourceType.CSS == type_;
        if (logger_.isDebugEnabled())
            logger_.debug("minimize " + (enable ? "enabled" : "disabled"));
        clearCache();
    }

    @Override
    public void enableDisableCompress(boolean enable) {
        compress_ = enable;
        if (logger_.isDebugEnabled())
            logger_.debug("compress " + (enable ? "enabled" : "disabled"));
        clearCache();
    }

    @Override
    public void enableDisableCache(boolean enable) {
        useCache_ = enable;
        if (logger_.isDebugEnabled())
            logger_.debug("cache " + (enable ? "enabled" : "disabled"));
        clearCache();
    }

    @Override
    public void enableDisableInMemoryCache(boolean enable) {
        inMemory_ = enable;
        if (logger_.isDebugEnabled())
            logger_.debug("in memory cache "
                    + (enable ? "enabled" : "disabled"));
        clearCache();
    }

    @Override
    public void enableDisableProcessInline(boolean enable) {
        processInline_ = enable;
        if (logger_.isDebugEnabled())
            logger_.debug("inline processing "
                    + (enable ? "enabled" : "disabled"));
    }

    @Deprecated
    public void enableDisableVerifyResource(boolean verify) {
        // verifyResource_ = verify;
    }

    @Override
    public boolean isMinimizeEnabled() {
        // now css type resource is always minimized
        return minimize_ || ResourceType.CSS == type_;
    }

    @Override
    public boolean isCompressEnabled() {
        return compress_;
    }

    @Override
    public boolean isCacheEnabled() {
        return useCache_;
    }

    @Override
    public void setResourceDir(String dir) {
        checkInitialize_(false);
        if (rootDir_ == null) throw new IllegalStateException("rootDir need to be intialized first");
        if (dir.startsWith(rootDir_)) {
            resourcePath_ = dir;
        } else if (dir.startsWith("/")) {
            resourcePath_ = rootDir_ + dir;
        } else {
            resourcePath_ = rootDir_ + "/" + dir;
        }
        File f = fl_.locate(resourcePath_);
        if (!f.isDirectory()) throw new IllegalArgumentException("not a directory");
    }

    @Override
    public void setRootDir(String dir) {
        checkInitialize_(false);
        if (fl_ == null) throw new IllegalStateException("file locator need to initialized first");
        rootDir_ = dir.endsWith("/") ? dir.substring(0, dir.length() - 1) : dir;
        File f = fl_.locate(rootDir_);
        if (!f.isDirectory()) throw new IllegalArgumentException("not a directory");
        if (logger_.isDebugEnabled())
            logger_.debug(String.format("root dir set to %1$s", dir));
    }

    @Override
    public void setUrlContextPath(String ctxPath) {
        if (null == ctxPath) throw new NullPointerException();
        if (ctxPath.endsWith("/")) ctxPath = ctxPath.substring(0, ctxPath.length() - 1);
        ctxPath_ = ctxPath;
    }

    @Override
    public void setCacheDir(File dir) {
        // comment below as inmemory configuration does not require dir to be exists
        // this is relevant when deploy app on readonly file system like heroku and gae
//        if (!dir.isDirectory() && !dir.mkdir())
//            throw new IllegalArgumentException("not a dir");
        checkInitialize_(false);
        cache_ = new FileCache(dir);
    }

    @Override
    public void setResourceUrlRoot(String urlRoot) {
        if (ctxPath_ == null) throw new IllegalStateException("ctxPath must be intialized first");
        if (!urlRoot.startsWith("/"))
            throw new IllegalArgumentException("url root must start with /");
        // checkInitialize_(false);
        if (!urlRoot.endsWith("/"))
            urlRoot = urlRoot + "/";

        resourceUrlRoot_ = urlRoot.startsWith(ctxPath_) ? urlRoot : ctxPath_ + urlRoot;
        if (logger_.isDebugEnabled())
            logger_.debug(String.format("url root set to %1$s", urlRoot));
    }

    @Override
    public void setResourceUrlPath(String urlPath) {
        checkInitialize_(false);
        if (null == resourceUrlRoot_) {
            throw new IllegalStateException("resourceUrlRoot must be initiated first");
        }
        if (!urlPath.endsWith("/"))
            urlPath = urlPath + "/";
        if (urlPath.startsWith("/")) {
            resourceUrlPath_ = urlPath.startsWith(ctxPath_) ? urlPath : ctxPath_ + urlPath;
        } else {
            resourceUrlPath_ = resourceUrlRoot_ + urlPath;
        }
        if (logger_.isDebugEnabled())
            logger_.debug(String.format("url path set to %1$s", urlPath));
    }

    @Override
    public void setCacheUrlPath(String urlPath) {
        checkInitialize_(false);
        if (null == resourceUrlRoot_) {
            throw new IllegalStateException("resourceUrlRoot must be initiated first");
        }
        if (!urlPath.endsWith("/"))
            urlPath = urlPath + "/";
        if (urlPath.startsWith("/")) {
            cacheUrlPath_ = urlPath.startsWith(ctxPath_) ? urlPath : ctxPath_ + urlPath;
        } else {
            cacheUrlPath_ = resourceUrlRoot_ + urlPath;
        }
        if (logger_.isDebugEnabled())
            logger_.debug(String.format("cache url root set to %1$s", urlPath));
    }

    @Override
    public void clearCache() {
        cache_.clear();
        processCache2_.clear();
        processCache_.clear();
    }

    private IFileLocator fl_ = FileResource.defFileLocator;

    @Override
    public void setFileLocator(IFileLocator fileLocator) {
        if (null == fileLocator)
            throw new NullPointerException();
        fl_ = fileLocator;
    }

    private IBufferLocator bl_ = new BufferLocator();

    @Override
    public void setBufferLocator(IBufferLocator bufferLocator) {
        if (null == bufferLocator)
            throw new NullPointerException();
        bl_ = bufferLocator;
    }

    private IRouteMapper rm_ = null;

    @Override
    public void setRouteMapper(IRouteMapper routeMapper) {
        if (null == routeMapper)
            throw new NullPointerException();
        rm_ = routeMapper;
    }

    private static final Pattern P_IMPORT = Pattern.compile("^\\s*@import\\s*\"(.*?)\".*");
    private Map<String, Set<File>> importsCache_ = new HashMap<String, Set<File>>();

    private Set<File> imports_(File file) {
        String key = "less_imports_" + file.getPath() + file.lastModified();

        Set<File> files = importsCache_.get(key);
        if (null == files) {
            files = new HashSet<File>();
            try {
                List<String> lines = fileToLines_(file);
                for (String line : lines) {
                    Matcher m = P_IMPORT.matcher(line);
                    while (m.find()) {
                        File f = new File(file.getParentFile(), m.group(1));
                        if (f.canRead()) {
                            files.add(f);
                            files.addAll(imports_(f));
                        }
                    }
                }
            } catch (Exception e) {
                if (logger_.isErrorEnabled())
                    logger_.error(String.format("Error occurred getting @imports from resource: $s", file), e);
            }
        }
        return files;
    }

    @Override
    public long getLastModified(File file) {
        long l = file.lastModified();
        if (ResourceType.CSS == type_) {
            // try to get last modified of all @imported files
            for (File f : imports_(file)) {
                l = Math.max(l, f.lastModified());
            }
        }
        return l;
    }

    @Override
    public void checkCache() {
        for (List<String> l : processCache_.keySet()) {
            for (String s : l) {
                if (isCDN_(s)) continue;
                File f = getFileFromURL_(s);
                if (null != f && f.exists()) {
                    long ts1 = getLastModified(f);
                    long ts2 = lastModifiedCache_.get(f);
                    if (ts1 > ts2) {
                        processCache_.remove(l);
                        break;
                    }
                }
            }
        }
    }

    private ConcurrentMap<List<String>, List<String>> processCache_ = new ConcurrentHashMap<List<String>, List<String>>();

    /**
     * A convention used by this minimizer is resource name suffix with
     * "_bundle". For any resource with the name suffix with "_bundle"
     */
    @Override
    public List<String> process(List<String> resourceNames) {
        checkInitialize_(true);
        if (resourceNames.isEmpty())
            return Collections.emptyList();
        if (minimize_ || ResourceType.CSS == type_) {
            if (useCache_ && processCache_.containsKey(resourceNames)) {
                // !!! cache of the return list instead of minimized file
                List<String> l = processCache_.get(resourceNames);
                if (null != l) return new ArrayList<String>(l);
            }
            // CDN items will break the resource name list into
            // separate chunks in order to keep the dependency order
            List<String> retLst = new ArrayList<String>();
            List<String> tmpLst = new ArrayList<String>();
            for (String fn : resourceNames) {
                if (!isCDN_(fn)) {
                    tmpLst.add(fn);
                } else {
                    if (tmpLst.size() > 0) {
                        retLst.add(minimize_(tmpLst));
                        tmpLst.clear();
                    }
                    retLst.add(fn);
                }
            }
            if (tmpLst.size() > 0) {
                retLst.add(minimize_(tmpLst));
                tmpLst.clear();
            }

            // return minimize_(resourceNames);
            processCache_.put(resourceNames, retLst);
            return retLst;
        } else {
            List<String> retLst = processWithoutMinimize(resourceNames);
            return retLst;
        }
    }

    private final String getExtension_(String path) {
        int pos = path.lastIndexOf(".");
        return -1 == pos ? "" : path.substring(pos, path.length());
    }

    private ConcurrentMap<List<String>, List<String>> processCache2_ = new ConcurrentHashMap<List<String>, List<String>>();

    @Override
    public List<String> processWithoutMinimize(List<String> resourceNames) {
        checkInitialize_(true);
        if (resourceNames.isEmpty())
            return Collections.emptyList();
        if (useCache_ && processCache2_.containsKey(resourceNames)) {
            // !!! cache of the return list instead of minimized file
            List<String> l = processCache2_.get(resourceNames);
            if (null != l) return new ArrayList<String>(l);
        }
        List<String> l = new ArrayList<String>();
        for (String fn : resourceNames) {
            if (isCDN_(fn))
                l.add(fn); // CDN resource
            else {
                String s = fn.replace(type_.getExtension(), "");
                File f = null;
                if (s.equalsIgnoreCase("default")
                        || s.endsWith(IDependenceManager.BUNDLE_SUFFIX)) {
                    continue;
                }

                f = getFile_(fn);
                if (null == f || !f.isFile()) {
                    continue;
                }

                String ext = getExtension_(f.getName());
                fn = fn.endsWith(ext) ? fn : fn + ext;

                fn = getUrl_(fn);

                l.add(fn);
            }
        }
        if (l.isEmpty()) {
            logger_.warn("Empty resource list found when processing " + resourceNames);
        }
        processCache2_.put(resourceNames, l);
        return l;
    }

    private String compress(String content) {
        try {
            Reader r = new StringReader(content);
            StringWriter w = new StringWriter();
            compressor_.compress(r, w);
            return w.toString();
        } catch (Exception e) {
            logger_.warn("error compress resource", e);
            return content;
        }
    }

    private void compress(File file, Writer out) {
        try {
            Reader r = new BufferedReader(new FileReader(file));
            try {
                compressor_.compress(r, out);
            } catch (Exception e) {
                logger_.warn("error compress resource " + file.getPath(), e);
                copy_(file, out);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void compress(String content, Writer out) {
        Reader r = new StringReader(content);
        try {
            compressor_.compress(r, out);
        } catch (Exception e) {
            logger_.warn("error compress resource", e);
            copy_(content, out);
        }
    }

    @Override
    public String processInline(String content) {
        if (!processInline_)
            return content;
        try {
            content = preprocess_(content);
            if (this.compress_) {
                return compress(content);
            } else {
                return content;
            }
        } catch (StackOverflowError e) {
            logger_.error("fatal error compressing inline content:" + e.getMessage());
            return content;
        } catch (Exception e) {
            logger_.error("error processing inline content", e);
            return content;
        }
    }

    @Override
    public String processStatic(File file) {
        String content = null;
        try {
            content = preprocess_(file);
        } catch (IOException e2) {
            logger_.error("error preprocess static file: " + file.getPath());
            return "";
        }
        try {
            if (this.compress_) {
                return compress(content);
            } else {
                return content;
            }
        } catch (StackOverflowError e) {
            logger_.error("fatal error compressing static file: " + file.getName());
            return content;
        } catch (Exception e) {
            logger_.warn("error processing static file: " + file.getPath(), e);
            try {
                return fileToString_(file);
            } catch (IOException e1) {
                return "";
            }
        }
    }

    private static String dos2unix_(String s) {
        return s.replaceAll("\r\n", "\n");
    }

    private String compileLess_(String s) throws LessException {
        return less_.compile(dos2unix_(s)).replace("\\n", "\n");
    }

    private String compileLess_(File f) throws LessException {
        return less_.compile(f).replace("\\n", "\n");
    }

    private String compileCoffee_(String s) throws JCoffeeScriptCompileException {
        return coffee_.compile(s);
    }

    private String compileCoffee_(File f) throws JCoffeeScriptCompileException, IOException {
        return compileCoffee_(fileToString_(f));
    }

    public IResource minimize(String resourceNames) {
        return minimize(decodeResourceNames(resourceNames));
    }

    private IResource minimize(List<String> resourceNames) {
        IResource rsrc = newCache_(resourceNames);
        Writer out = rsrc.getWriter();
        StringWriter sw = new StringWriter();
        try {
            for (String s : resourceNames) {
                // if (s.startsWith("http:")) l.add(s);
                if (isCDN_(s)) {
                    throw new IllegalArgumentException(
                            "CDN resource not expected in miminize method");
                }

                File f = getFileFromURL_(s);
                if (null != f && f.exists()) {
                    merge_(f, sw, s);
                } else {
                    // possibly a pseudo or error resource name
                }
            }
            String s = sw.toString();
            if (lessEnabled_() && postMergeLessCompile_()) {
                try {
                    s = compileLess_(s);
                } catch (LessException e) {
                    logger_.warn("Error compile less content: " + e.getMessage(), e);
                }
                if (compress_) {
                    try {
                        compress(s, out);
                    } catch (StackOverflowError e) {
                        logger_.error("fatal error compressing resource: " + e.getMessage());
                    }
                } else {
                    copy_(s, out);
                }
            } else {
                copy_(s, out);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (null != out) {
                try {
                    out.close();
                } catch (IOException e) {
                    logger_.warn("cannot close output in minimizor", e);
                }
            }
        }

        return rsrc;
    }

    private String minimize_(List<String> resourceNames) {
        FileCache cache = cache_;

        if (useCache_) {
            String fn = cache.get(resourceNames);
            if (null != fn) {
                if (logger_.isDebugEnabled())
                    logger_.debug("cached file returned: " + fn);
                return cacheUrlPath_ + fn;
            }
        }

        IResource rsrc = minimize(resourceNames);

        String fn = rsrc.getKey();
        // filename always cached without regarding to cache setting
        // this is a good time to remove previous file
        // Note it's absolutely not a good idea to turn cache off
        // and minimize on in a production environment
        cache.put(resourceNames, fn);

        try {
            StringBuilder builder = new StringBuilder();
            builder.append(cacheUrlPath_);
            builder.append(fn);

            if (this.resourcesParam_ != null) {
                String resourcesParamValue = this.encodeResourceNames(resourceNames);
                if (resourcesParamValue != null) {
                    builder.append("?");
                    builder.append(this.resourcesParam_);
                    builder.append("=");
                    builder.append(URLEncoder.encode(resourcesParamValue, "utf8"));
                }
            }
            return builder.toString();
        } catch (UnsupportedEncodingException e) {
            throw new IllegalStateException(e);
        }
    }

    private String encodeResourceNames(List<String> resourceNames) {
        StringBuilder builder = new StringBuilder();
        for (String resourceName : resourceNames) {
            resourceName = StringUtils.stripToNull(resourceName);
            if (resourceName != null) {
                if (builder.length() > 0) {
                    builder.append(',');
                }
                if (resourceName.startsWith(resourceUrlPath_)) {
                    resourceName = resourceName.substring(resourceUrlPath_.length());
                }
                builder.append(resourceName);
            }
        }
        return (builder.length() > 0) ? builder.toString() : null;
    }

    private List<String> decodeResourceNames(String resourceNames) {
        String[] names = resourceNames.split("[,]");
        if (names.length == 0) {
            return Collections.emptyList();
        }

        List<String> l = new ArrayList<String>(names.length);

        for (String name : names) {
            name = StringUtils.stripToNull(name);
            if (name != null) {
                if (!name.startsWith("/")) {
                    name = resourceUrlPath_ + name;
                }
                if (!l.contains(name)) {
                    l.add(name);
                }
            }
        }

        return l;
    }

    public static final String SYS_PROP_LESS_ENABLED = "greenscript.less.enabled";

    private boolean lessEnabled_() {
        if (ResourceType.CSS != type_)
            return false;
        boolean b = Boolean.parseBoolean(System.getProperty(
                SYS_PROP_LESS_ENABLED, "false"));
        return b;
    }

    public static final String SYS_PROP_COFFEE_ENABLED = "greenscript.coffee.enabled";

    private boolean coffeeEnabled_() {
        if (ResourceType.JS != type_) return false;
        boolean b = Boolean.parseBoolean(System.getProperty(SYS_PROP_COFFEE_ENABLED, "false"));
        return b;
    }

    /*
     * replace relative url inside the file content with absolute url. This is
     * because the compressed version file will be put in another folder
     *
     * @param s the content
     *
     * @param fn the original file name
     */
    private static final Pattern P_URL = Pattern.compile("url\\(['\"]?([^/'\"][^'\"]*?)['\"]?\\)", Pattern.CASE_INSENSITIVE | Pattern.CANON_EQ | Pattern.UNICODE_CASE);

    private String processRelativeUrl_(String s, String fn) throws IOException {
        if (ResourceType.CSS != type_)
            throw new IllegalStateException("not a css minimizer");

        if (this.rm_ != null) {
            fn = this.rm_.route(fn);
        }

        /*
         * Process fn: .../a.* -> .../
         */
        int p = fn.lastIndexOf("/") + 1;
        fn = (0 == p) ? resourceUrlPath_ : fn.substring(0, p);

        String prefix;
        if (fn.startsWith("/")) {
            if (fn.startsWith(resourceUrlPath_)) prefix = fn;
            else if (fn.startsWith(resourceUrlRoot_)) prefix = fn;
            else prefix = resourceUrlRoot_ + fn.replaceFirst("/", "");
        } else {
            prefix = resourceUrlPath_ + fn;
        }

        if (this.rm_ != null) {
            prefix = this.rm_.reverse(prefix);
        }

        try {
            Matcher m = P_URL.matcher(s);
            s = m.replaceAll("url(" + prefix + "$1)");
            return s;
        } catch (Throwable e) {
            System.err.println("Error process relative URL: " + fn);
            e.printStackTrace(System.err);
            return s;
        }
    }

    private String fileToString_(File f) throws IOException {
        BufferedReader r = new BufferedReader(new FileReader(f));
        String l = null;
        StringBuilder sb = new StringBuilder();
        String ls = System.getProperty("line.separator");
        while ((l = r.readLine()) != null) {
            sb.append(l);
            sb.append(ls);
        }
        r.close();
        return sb.toString();
    }

    private List<String> fileToLines_(File f) throws IOException {
        BufferedReader r = new BufferedReader(new FileReader(f));
        String l = null;
        List<String> lines = new ArrayList<String>();
        while ((l = r.readLine()) != null) {
            lines.add(l);
        }
        r.close();
        return lines;
    }

    private ConcurrentMap<File, Long> lastModifiedCache_ = new ConcurrentHashMap<File, Long>();

    private void merge_(File file, Writer out, String originalFn) {
        if (logger_.isTraceEnabled())
            logger_.trace("starting to minimize resource: " + file.getName());

        lastModifiedCache_.put(file, getLastModified(file));
        // possibly due to error or pseudo resource name
        try {
            String s = preprocess_(file, originalFn);
            if (compress_ && (!lessEnabled_() || !postMergeLessCompile_())) {
                if (logger_.isTraceEnabled())
                    logger_.trace(String.format("compressing %1$s ...",
                            file.getName()));
                if (null != s) {
                    compress(s, out);
                } else {
                    compress(file, out);
                }
            } else {
                if (null != s) copy_(s, out);
                else copy_(file, out);
            }
        } catch (IOException e) {
            logger_.warn(
                    "error processing javascript file file " + file.getName(),
                    e);
        }
    }

    private String preprocess_(String s) {
        if (lessEnabled_()) {
            try {
                s = compileLess_(s);
            } catch (Exception e) {
                logger_.warn("process inline content: " + e.getMessage());
            }
        }
        return s;
    }

    private boolean postMergeLessCompile_() {
        return Boolean.valueOf(System.getProperty("greenscript.lessCompile.postMerge", "false"));
    }

    private String preprocess_(File file) throws IOException {
        String s = null;
        if (lessEnabled_() && !postMergeLessCompile_()) {
            try {
                s = compileLess_(file);
            } catch (LessException e) {
                logger_.warn("error compile less file: " + file.getName() + ", error: " + e.getMessage(), e);
            }
        } else {
            if (file.getName().endsWith(".coffee")) {
                try {
                    s = coffee_.compile(fileToString_(file));
                } catch (JCoffeeScriptCompileException e) {
                    logger_.error("error compile coffee script file", e);
                }
            }
        }
        if (null == s) s = fileToString_(file);
        return s;
    }

    private String preprocess_(File file, String originalFn) throws IOException {
        String s = null;
        if (lessEnabled_() && !postMergeLessCompile_()) {
            try {
                s = compileLess_(file);
            } catch (LessException e) {
                logger_.warn("error compile less file: " + originalFn + ", error: " + e.getMessage());
            }
        } else if (coffeeEnabled_() && file.getName().endsWith(".coffee")) {
            try {
                s = compileCoffee_(file);
            } catch (JCoffeeScriptCompileException e) {
                logger_.error("error compile coffee script file", e);
            }
        }
        if (null == s) s = fileToString_(file);
        if (ResourceType.CSS == type_) s = processRelativeUrl_(s, originalFn);
        return s;
    }

    private String getUrl_(String resourceName) {
        String url = null;

        if (!"".equals(ctxPath_) && resourceName.startsWith(ctxPath_)) {
            url = resourceName;
        } else if (resourceName.startsWith("/")) {
            String s = ctxPath_ + resourceName;
            if (s.startsWith(resourceUrlRoot_)) {
                url = s;
            } else {
                url = resourceUrlRoot_ + resourceName.substring(1, resourceName.length());
            }
        } else {
            url = resourceUrlPath_ + resourceName;
        }

        return (this.rm_ != null) ? this.rm_.reverse(url) : url;
    }

    private File getFileFromURL_(String url) {
        return this.getFile_((this.rm_ != null) ? this.rm_.route(url) : url);
    }

    private File getFile_(String resourceName) {
        if (resourceName.startsWith("/") && !resourceName.startsWith(ctxPath_)) {
            resourceName = ctxPath_ + resourceName;
        }
        if (resourceName.startsWith(resourceUrlPath_)) {
            resourceName = resourceName.replaceFirst(resourceUrlPath_, "");
        } else if (resourceName.startsWith(resourceUrlRoot_)) {
            resourceName = resourceName.replaceFirst(resourceUrlRoot_, "/");
        }
        String fn = resourceName;
        String path;
        if (fn.startsWith("/")) {
            path = (!fn.startsWith(rootDir_)) ? rootDir_ + "/"
                    + fn.replaceFirst("/", "") : fn;
        } else {
            path = resourcePath_ + "/" + fn;
        }
        for (String ext : type_.getAllExtensions()) {
            String p = fn.endsWith(ext) ? path : path + ext;
            File f = fl_.locate(p);
            if (null != f) return f;
        }
        return null;
    }

    private static void copy_(File file, Writer out) throws IOException {
        if (logger_.isTraceEnabled())
            logger_.trace(String.format("merging file %1$s ...", file.getName()));
        copy_(new FileReader(file), out);
    }

    public static void copy_(Reader in, Writer out) {
        String line = null;
        BufferedReader r = null;
        try {
            r = new BufferedReader(in);
            PrintWriter w = new PrintWriter(out);
            while ((line = r.readLine()) != null) {
                w.println(line);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            if (null != r)
                try {
                    r.close();
                } catch (IOException e) {/*ignore*/}
        }
    }

    private static void copy_(String s, Writer out) {
        copy_(new StringReader(s), out);
    }

    private IResource newCache_(List<String> resourceNames) {
        if (inMemory_) {
            return bl_.newBuffer(resourceNames, type_.getExtension());
        } else {
            return new FileResource(newCacheFile_(resourceNames));
        }
    }

    private File newCacheFile_(List<String> resourceNames) {
        String extension = type_.getExtension();
        return cache_.createTempFile(resourceNames, extension);
    }

    private void checkInitialize_(boolean initialized) {
        boolean notInited = (resourcePath_ == null || rootDir_ == null
                || resourceUrlPath_ == null || cache_ == null || cacheUrlPath_ == null);

        if (initialized == notInited) {
            throw new IllegalStateException(
                    initialized ? "minimizer not initialized"
                            : "minimizer already initialized");
        }
    }

    public ResourceType getType() {
        return type_;
    }

    private final static Pattern P_CDN_PREFIX = Pattern.compile("^https?:");

    private final boolean isCDN_(String resourceName) {
        if (null == resourceName) return false;
        Matcher m = P_CDN_PREFIX.matcher(resourceName);
        return m.find();
    }

    public void setResourcesParam(String resourcesParam_) {
        this.resourcesParam_ = resourcesParam_;
    }

}
TOP

Related Classes of com.greenscriptool.Minimizer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.