org.springframework.extensions.webscripts.processor.ClojureScriptProcessor.java Source code

Java tutorial

Introduction

Here is the source code for org.springframework.extensions.webscripts.processor.ClojureScriptProcessor.java

Source

/**
 * Copyright (c) 2011 Carlo Sciolla
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package org.springframework.extensions.webscripts.processor;

import java.io.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import clojure.lang.RT;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.extensions.surf.core.scripts.ScriptException;
import org.springframework.extensions.webscripts.ScriptContent;

import spring.surf.webscript.WebScript;

/**
 * Loads Clojure script controllers from an {@link InputStream} and memoizes
 * the compiled {@link WebScript} instance
 *
 * @author Carlo Sciolla <skuro@skuro.tk>
 */
public class ClojureScriptProcessor extends AbstractScriptProcessor {

    static {
        // needed as clojure.lang.Compiler needs RT to be fully loaded beforehand
        RT.list();
    }

    private static final Log log = LogFactory.getLog(ClojureScriptProcessor.class);

    private Map<String, WebScript> compiledWebScripts = Collections
            .synchronizedMap(new HashMap<String, WebScript>());

    /**
     * {@inheritDoc}
     * @return "clj"
     */
    public String getExtension() {
        return "clj";
    }

    /**
     * {@inheritDoc}
     * @return "clojure"
     */
    public String getName() {
        return "clojure";
    }

    /**
     * Executes the Clojure script
     *
     * @param is    the input stream
     * @param out   the writer.  This can be null if no output is required.
     * @param model the context model for the script
     * @return WebScript  a new instance of the requested Clojure backed web script
     */
    @SuppressWarnings(value = "unchecked")
    protected WebScript compileClojureScript(InputStream is, Writer out, Map<String, Object> model) {
        log.debug("Executing Clojure script");
        log.debug("This line is to get rid of an IDEA warning: " + out);

        this.addProcessorModelExtensions(model);

        try {
            return (WebScript) clojure.lang.Compiler.load(new InputStreamReader(is));
        } catch (Exception exception) {
            throw new ScriptException("Error executing Clojure script", exception);
        }
    }

    /**
     * {@inheritDoc}
     */
    public ScriptContent findScript(String path) {
        // TODO: maybe check path against (ns)?
        return getScriptLoader().getScript(path);
    }

    /**
     * {@inheritDoc}
     */
    public Object executeScript(String path, Map<String, Object> model) {
        ScriptContent scriptContent = findScript(path);
        if (scriptContent == null) {
            throw new ScriptException("Unable to locate: " + path);
        }

        return executeScript(scriptContent, model);
    }

    /**
     * {@inheritDoc}
     */
    public Object executeScript(ScriptContent scriptContent, Map<String, Object> model) {
        String path = scriptContent.getPath();
        WebScript webscript = this.compiledWebScripts.get(path);
        if (webscript == null) {
            if (log.isDebugEnabled()) {
                log.debug("Compiling new Clojure webscript at path " + path);
            }
            webscript = compileClojureScript(scriptContent.getInputStream(), null, model);
        }
        if (webscript == null) {
            throw new ScriptException("Cannot compile Clojure web script at path " + path);
        }

        synchronized (this) {
            if (log.isDebugEnabled()) {
                log.debug("Caching Clojure webscript at path " + path);
            }
            this.compiledWebScripts.put(path, webscript);
        }

        return webscript.run(scriptContent.getInputStream(), null, model);
    }

    /**
     * {@inheritDoc}
     */
    public Object unwrapValue(Object value) {
        return value;
    }

    /**
     * {@inheritDoc}
     */
    public void reset() {
        init();
        this.compiledWebScripts = Collections.synchronizedMap(new HashMap<String, WebScript>());
    }
}