Package io.pedestal.servlet

Source Code of io.pedestal.servlet.ClojureVarServlet

/* Copyright 2013 Relevance, Inc.
* Copyright 2014 Cognitect, Inc.

* The use and distribution terms for this software are covered by the
* Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0)
* which can be found in the file epl-v10.html at the root of this distribution.
*
* By using this software in any fashion, you are agreeing to be bound by
* the terms of this license.
*
* You must not remove this notice, or any other, from this software.
*/
package io.pedestal.servlet;

import clojure.lang.IFn;
import clojure.java.api.Clojure;
import javax.servlet.Servlet;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

/**
* Java Servlets implementation that dispatches via Clojure Vars (that map to IFn's).
*
* <p>ClojureVarServlet is a completely generic implementation of the
* javax.servlet.Servlet and ServletConfig interfaces. Its behavior is
* specified via Servlet initialization parameters.
*
* <p>The three parameters are 'init', 'service', and 'destroy'. Only
* 'service' is required; the others are optional. The value of each
* parameter must be the namespace-qualified name of a Clojure Var.
* The namespace will be loaded as with clojure.core/require, then the
* Var will be resolved.
*
* <p>The root binding of each Var must be a Clojure function taking the
* same arguments as the corresponding method in the Servlet interface:
*
* <pre>
* init(Servlet, ServletConfig)
* service(Servlet, ServletRequest, ServletResponse)
* destroy(Servlet)
* </pre>
*
* <p>The return value of any of these functions is ignored.
*
* <p>The Vars will be resolved and dereferenced only once, when the
* Servlet is initialized. Changing the root binding of a Var after
* the Servlet has been initialized will have no effect.
*/
public class ClojureVarServlet extends GenericServlet {
    private IFn serviceFn;
    private IFn destroyFn;
    private static IFn REQUIRE = Clojure.var("clojure.core", "require");
    private static IFn SYMBOL = Clojure.var("clojure.core", "symbol");

    /** Does nothing. Initialization happens in the init method. */
    public ClojureVarServlet() {;}

    /** Initializes the Servlet with Clojure functions resolved from
     * Vars named in the Servlet initialization parameters. If an init
     * function was provided, invokes it. */
    @Override
    public void init() throws ServletException {
        ServletConfig config = this.getServletConfig();
        IFn initFn = getVar(config, "init");
        IFn serviceFn = getVar(config, "service");
        IFn destroyFn = getVar(config, "destroy");

        if (serviceFn == null) {
            throw new ServletException("Missing required parameter 'service'");
        }

        if (initFn != null) { initFn.invoke(this, config); }
    }

    /** Invokes the service function with which this Servlet was
     * initialized. */
    @Override
    public void service(ServletRequest request, ServletResponse response) {
        serviceFn.invoke(this, request, response);
    }

    /** If a destroy function was provided when this Servlet was
     * initialized, invokes it. */
    @Override
    public void destroy() {
        if (destroyFn != null) {
            destroyFn.invoke(this);
        }
    }

    private static IFn getVar(ServletConfig config, String param)
        throws ServletException {

        String varName = config.getInitParameter(param);
        if (varName == null) { return null; }

        String[] parts = varName.split("/", 2);
        String namespace = parts[0];
        String name = parts[1];
        if (namespace == null || name == null) {
            throw new ServletException("Invalid namespace-qualified symbol '"
                                       + varName + "'");
        }

        try {
            REQUIRE.invoke(SYMBOL.invoke(namespace));
        } catch(Throwable t) {
            throw new ServletException("Failed to load namespace '"
                                       + namespace + "'", t);
        }

        IFn fn = Clojure.var(namespace, name);
        if (fn == null) {
            throw new ServletException("Var '" + varName + "' not found");
        }
        return fn;
    }
}
TOP

Related Classes of io.pedestal.servlet.ClojureVarServlet

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.