com.asual.lesscss.LessEngine.java Source code

Java tutorial

Introduction

Here is the source code for com.asual.lesscss.LessEngine.java

Source

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.asual.lesscss;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.JavaScriptException;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.tools.shell.Global;

import com.asual.lesscss.loader.ChainedResourceLoader;
import com.asual.lesscss.loader.ClasspathResourceLoader;
import com.asual.lesscss.loader.CssProcessingResourceLoader;
import com.asual.lesscss.loader.FilesystemResourceLoader;
import com.asual.lesscss.loader.HTTPResourceLoader;
import com.asual.lesscss.loader.ResourceLoader;
import com.asual.lesscss.loader.UnixNewlinesResourceLoader;

/**
 * @author Rostislav Hristov
 * @author Uriah Carpenter
 * @author Noah Sloan
 */
public class LessEngine {

    private final Log logger = LogFactory.getLog(getClass());

    private final LessOptions options;
    private final ResourceLoader loader;

    private Scriptable scope;
    private Function compile;

    public LessEngine() {
        this(new LessOptions());
    }

    public LessEngine(LessOptions options) {
        this(options, defaultResourceLoader(options));
    }

    private static ResourceLoader defaultResourceLoader(LessOptions options) {
        ResourceLoader resourceLoader = new ChainedResourceLoader(new FilesystemResourceLoader(),
                new ClasspathResourceLoader(LessEngine.class.getClassLoader()), new HTTPResourceLoader());
        if (options.isCss()) {
            return new CssProcessingResourceLoader(resourceLoader);
        }
        resourceLoader = new UnixNewlinesResourceLoader(resourceLoader);
        return resourceLoader;
    }

    public LessEngine(LessOptions options, ResourceLoader loader) {
        this.options = options;
        this.loader = loader;
        try {
            logger.debug("Initializing LESS Engine.");
            ClassLoader classLoader = getClass().getClassLoader();
            URL less = options.getLess();
            URL env = classLoader.getResource("META-INF/env.js");
            URL engine = classLoader.getResource("META-INF/engine.js");
            URL cssmin = classLoader.getResource("META-INF/cssmin.js");
            Context cx = Context.enter();
            logger.debug("Using implementation version: " + cx.getImplementationVersion());
            cx.setOptimizationLevel(9);
            Global global = new Global();
            global.init(cx);
            scope = cx.initStandardObjects(global);
            cx.evaluateReader(scope, new InputStreamReader(env.openConnection().getInputStream()), env.getFile(), 1,
                    null);
            Scriptable lessEnv = (Scriptable) scope.get("lessenv", scope);
            lessEnv.put("charset", lessEnv, options.getCharset());
            lessEnv.put("css", lessEnv, options.isCss());
            lessEnv.put("loader", lessEnv, Context.javaToJS(loader, scope));
            cx.evaluateReader(scope, new InputStreamReader(less.openConnection().getInputStream()), less.getFile(),
                    1, null);
            cx.evaluateReader(scope, new InputStreamReader(cssmin.openConnection().getInputStream()),
                    cssmin.getFile(), 1, null);
            cx.evaluateReader(scope, new InputStreamReader(engine.openConnection().getInputStream()),
                    engine.getFile(), 1, null);
            compile = (Function) scope.get("compile", scope);
            Context.exit();
        } catch (Exception e) {
            logger.error("LESS Engine intialization failed.", e);
        }
    }

    public String compile(String input) throws LessException {
        return compile(input, null, false);
    }

    public String compile(String input, String location) throws LessException {
        return compile(input, location, false);
    }

    public String compile(String input, String location, boolean compress) throws LessException {
        try {
            long time = System.currentTimeMillis();
            String result = call(compile, new Object[] { input, location == null ? "" : location, compress });
            logger.debug("The compilation of '" + input + "' took " + (System.currentTimeMillis() - time) + " ms.");
            return result;
        } catch (Exception e) {
            throw parseLessException(e);
        }
    }

    public String compile(URL input) throws LessException {
        return compile(input, false);
    }

    public String compile(URL input, boolean compress) throws LessException {
        try {
            long time = System.currentTimeMillis();
            String location = input.toString();
            logger.debug("Compiling URL: " + location);
            String source = loader.load(location, options.getCharset());
            String result = call(compile, new Object[] { source, location, compress });
            logger.debug("The compilation of '" + input + "' took " + (System.currentTimeMillis() - time) + " ms.");
            return result;
        } catch (Exception e) {
            throw parseLessException(e);
        }
    }

    public String compile(File input) throws LessException {
        return compile(input, false);
    }

    public String compile(File input, boolean compress) throws LessException {
        try {
            long time = System.currentTimeMillis();
            String location = input.getAbsolutePath();
            logger.debug("Compiling File: " + "file:" + location);
            String source = loader.load(location, options.getCharset());
            String result = call(compile, new Object[] { source, location, compress });
            logger.debug("The compilation of '" + input + "' took " + (System.currentTimeMillis() - time) + " ms.");
            return result;
        } catch (Exception e) {
            throw parseLessException(e);
        }
    }

    public void compile(File input, File output) throws LessException, IOException {
        compile(input, output, false);
    }

    public void compile(File input, File output, boolean compress) throws LessException, IOException {
        try {
            String content = compile(input, compress);
            if (!output.exists()) {
                output.createNewFile();
            }
            BufferedWriter bw = new BufferedWriter(new FileWriter(output));
            bw.write(content);
            bw.close();
        } catch (Exception e) {
            throw parseLessException(e);
        }
    }

    private synchronized String call(Function fn, Object[] args) {
        return (String) Context.call(null, fn, scope, scope, args);
    }

    private LessException parseLessException(Exception root) throws LessException {
        logger.debug("Parsing LESS Exception", root);
        if (root instanceof JavaScriptException) {
            Scriptable value = (Scriptable) ((JavaScriptException) root).getValue();
            String type = ScriptableObject.getProperty(value, "type").toString() + " Error";
            String message = ScriptableObject.getProperty(value, "message").toString();
            String filename = "";
            if (ScriptableObject.getProperty(value, "filename") != null) {
                filename = ScriptableObject.getProperty(value, "filename").toString();
            }
            int line = -1;
            if (ScriptableObject.getProperty(value, "line") != null) {
                line = ((Double) ScriptableObject.getProperty(value, "line")).intValue();
            }
            int column = -1;
            if (ScriptableObject.getProperty(value, "column") != null) {
                column = ((Double) ScriptableObject.getProperty(value, "column")).intValue();
            }
            List<String> extractList = new ArrayList<String>();
            if (ScriptableObject.getProperty(value, "extract") != null) {
                NativeArray extract = (NativeArray) ScriptableObject.getProperty(value, "extract");
                for (int i = 0; i < extract.getLength(); i++) {
                    if (extract.get(i, extract) instanceof String) {
                        extractList.add(((String) extract.get(i, extract)).replace("\t", " "));
                    }
                }
            }
            throw new LessException(message, type, filename, line, column, extractList);
        }
        throw new LessException(root);
    }

}