All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.nanocontainer.nanowar.nanoweb.NanoWebServlet Maven / Gradle / Ivy

The newest version!
package org.nanocontainer.nanowar.nanoweb;

import ognl.Ognl;
import ognl.OgnlException;
import org.nanocontainer.nanowar.ApplicationScopeObjectReference;
import org.nanocontainer.nanowar.KeyConstants;
import org.nanocontainer.nanowar.RequestScopeObjectReference;
import org.nanocontainer.nanowar.ServletRequestContainerLauncher;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.defaults.ObjectReference;

import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Enumeration;

/**
 * Dispatcher servlet for NanoWeb.
 * NanoWeb is an ultra simple MVC framework inspired from WebWork It is based on ScriptedContainerBuilderFactory,
 * PicoContainer, Ognl, Groovy and Velocity.
 * Design goals:
 * 
    *
  • One-file configuration (all in an embedded ScriptedContainerBuilderFactory script in web.xml)
  • *
  • Sensible defaults with the goal to reduce the need for complex configuration
  • *
  • Non intrusiveness. Actions are PicoComponents/POJOs that extend nothing
  • *
  • Actions can be written in a compilable scripting language like Groovy
  • *
  • Actions must implement a String execute() method
  • *
  • The result from execute will be used to determine the view path. Example: /something.nano + "success" -> /something_success.vm
  • *
* Other things: *
    *
  • Map action paths to action classes in nanocontainer servlet script (using groovy)
  • *
  • Views can set values in actions with Ognl expressions
  • *
* * @author Aslak Hellesøy * @author Kouhei Mori * @version $Revision: 2528 $ */ public class NanoWebServlet extends HttpServlet implements KeyConstants { private Dispatcher dispatcher; // TODO make this configurable from web.xml private final CachingScriptClassLoader cachingScriptClassLoader = new CachingScriptClassLoader(); public void init() throws ServletException { ServletContext servletContext = getServletContext(); MutablePicoContainer applicationContainer = getApplicationContainer(servletContext); initDispatcher(applicationContainer); } private void initDispatcher(MutablePicoContainer applicationContainer) { dispatcher = (Dispatcher) applicationContainer.getComponentInstanceOfType(Dispatcher.class); if (dispatcher == null) { dispatcher = new ChainingDispatcher(".vm"); } } protected void service(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws ServletException, IOException { ServletRequestContainerLauncher containerLauncher = new ServletRequestContainerLauncher(getServletContext(), httpServletRequest); try { containerLauncher.startContainer(); String servletPath = getServletPath(httpServletRequest); String scriptPathWithoutExtension = servletPath.substring(0, servletPath.lastIndexOf('/')); Object action = getActionObject(scriptPathWithoutExtension, httpServletRequest); setPropertiesWithOgnl(httpServletRequest, action); int dot = servletPath.lastIndexOf('.'); String actionMethod = servletPath.substring(servletPath.lastIndexOf('/') + 1, dot); String result = execute(action, actionMethod); httpServletRequest.setAttribute("action", action); ServletContext servletContext = getServletContext(); dispatcher.dispatch(servletContext, httpServletRequest, httpServletResponse, scriptPathWithoutExtension, actionMethod, result); } catch (ScriptException e) { handleServiceScriptException(e, httpServletResponse, httpServletRequest); } finally { containerLauncher.killContainer(); } } /** * This overridable method contains the default behavior for the catching of ScriptException during the * service call. Because different containers suck at handling exceptions, this default behavior displays * a simple page. Teams deploying NanoWebServlet may want to extend and replace this functionality. This * servlet may be participating with some larger model-2 design. * * @param e the script exception * @param httpServletResponse the servlet response * @param httpServletRequest the servlet request * @throws IOException if for some bizarre reason the outgoing page cannot be written to. */ protected void handleServiceScriptException(ScriptException e, HttpServletResponse httpServletResponse, HttpServletRequest httpServletRequest) throws IOException { e.printStackTrace(); // Print the stack trace and the script (for debugging) PrintWriter writer = httpServletResponse.getWriter(); writer.println(""); writer.println("
");
        e.printStackTrace(writer);
        writer.println(httpServletRequest.getRequestURI());
        URL scriptURL = e.getScriptURL();
        InputStream in = scriptURL.openStream();
        int c;
        while ((c = in.read()) != -1) {
            writer.write(c);
        }
        writer.println("
"); writer.println(""); } private Object getActionObject(String path, HttpServletRequest request) throws ServletException, ScriptException { MutablePicoContainer requestContainer = getRequestContainer(request); // Try to get an action as specified in the configuration Object action = requestContainer.getComponentInstance(path); if (action == null) { // Try to get an action from a script (groovy) try { action = getScriptAction(path + ".groovy", requestContainer); } catch (IOException e) { log("Failed to load action class", e); throw new ServletException(e); } } if (action == null) { String msg = "No action found for '" + path + "'"; throw new ServletException(msg); } return action; } private Object getScriptAction(String scriptPath, MutablePicoContainer requestContainer) throws IOException, ScriptException { URL scriptURL = getServletContext().getResource(scriptPath); Object result = null; if (scriptURL != null) { Class scriptClass = cachingScriptClassLoader.getClass(scriptURL); requestContainer.registerComponentImplementation(scriptPath, scriptClass); result = requestContainer.getComponentInstance(scriptPath); } return result; } private void setPropertiesWithOgnl(HttpServletRequest servletRequest, Object action) throws ServletException { Enumeration parameterNames = servletRequest.getParameterNames(); while (parameterNames.hasMoreElements()) { String parameterName = (String) parameterNames.nextElement(); String parameterValue = servletRequest.getParameter(parameterName); try { Ognl.setValue(parameterName, action, parameterValue); } catch (OgnlException e) { log("Failed to set property with OGNL ('" + parameterName +"', '" + action + "', '" + parameterValue + "')", e); throw new ServletException(e); } } } private String execute(Object actionObject, String actionMethodName) throws ServletException { Method actionMethod = null; try { actionMethod = actionObject.getClass().getMethod(actionMethodName, (Class[])null); } catch (NoSuchMethodException e) { String message = "The " + actionObject.getClass().getName() + " doesn't have the method " + actionMethodName + "()"; log(message, e); throw new ServletException(message, e); } try { String view = (String) actionMethod.invoke(actionObject, (Object[])null); return view; } catch (IllegalAccessException e) { String message = actionObject.getClass().getName() + "." + actionMethodName + "() isn't public"; log(message, e); throw new ServletException(message, e); } catch (InvocationTargetException e) { String message = "Failed to actionMethod " + actionObject.getClass().getName() + "." + actionMethodName + "()"; log(message, e); throw new ServletException(message, e); } } static String getServletPath(HttpServletRequest httpServletRequest) { String servletPath = (String) httpServletRequest.getAttribute("javax.servlet.include.servlet_path"); if (servletPath == null) { servletPath = httpServletRequest.getServletPath(); } return servletPath; } private MutablePicoContainer getApplicationContainer(ServletContext context) { ObjectReference ref = new ApplicationScopeObjectReference(context, APPLICATION_CONTAINER); return (MutablePicoContainer) ref.get(); } private MutablePicoContainer getRequestContainer(ServletRequest request) { ObjectReference ref = new RequestScopeObjectReference(request, REQUEST_CONTAINER); return (MutablePicoContainer) ref.get(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy