alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Groovy example source code file (ServletBinding.java)

This example Groovy source code file (ServletBinding.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Groovy tags/keywords

http, httpservletrequest, httpservletresponse, httpservletresponse, io, ioexception, ioexception, map, methodclosure, object, printwriter, printwriter, request, response, servlet, servletoutput, servletoutputstream, string, string, util

The Groovy ServletBinding.java source code

/*
 * Copyright 2003-2011 the original author or authors.
 *
 * 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 groovy.servlet;

import groovy.lang.Binding;
import groovy.xml.MarkupBuilder;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.runtime.MethodClosure;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;

/**
 * Servlet-specific binding extension to lazy load the writer or the output
 * stream from the response.
 * <p/>
 * <h3>Eager variables
 * <ul>
 * <li>"request" : the HttpServletRequest object
 * <li>"response" : the HttpServletRequest object
 * <li>"context" : the ServletContext object
 * <li>"application" : same as context
 * <li>"session" : shorthand for request.getSession(false) - can be null!
 * <li>"params" : map of all form parameters - can be empty
 * <li>"headers" : map of all request header fields
 * </ul>
 * <p/>
 * <h3>Lazy variables
 * <ul>
 * <li>"out" : response.getWriter()
 * <li>"sout" : response.getOutputStream()
 * <li>"html" : new MarkupBuilder(response.getWriter()) - expandEmptyElements flag is set to true
 * </ul>
 * As per the Servlet specification, a call to <code>response.getWriter() should not be
 * done if a call to <code>response.getOutputStream() has already occurred or the other way
 * around. You may wonder then how the above lazy variables can possibly be provided - since
 * setting them up would involve calling both of the above methods. The trick is catered for
 * behind the scenes using lazy variables. Lazy bound variables can be requested without side
 * effects; under the covers the writer and stream are wrapped. That means
 * <code>response.getWriter() is never directly called until some output is done using
 * 'out' or 'html'. Once a write method call is done using either of these variable, then an attempt
 * to write using 'sout' will cause an <code>IllegalStateException. Similarly, if a write method
 * call on 'sout' has been done already, then any further write method call on 'out' or 'html' will cause an
 * <code>IllegalStateException.
 * <p/>
 * <h3>Reserved internal variable names (see "Methods" below)
 * <ul>
 * <li>"forward"
 * <li>"include"
 * <li>"redirect"
 * </ul>
 * </p>
 * If <code>response.getWriter() is called directly (without using out), then a write method
 * call on 'sout' will not cause the <code>IllegalStateException, but it will still be invalid.
 * It is the responsibility of the user of this class, to not to mix these different usage
 * styles. The same applies to calling <code>response.getOutputStream() and using 'out' or 'html'.
 * </p>
 * <h3>Methods
 * <ul>
 * <li>"forward(String path)" : request.getRequestDispatcher(path).forward(request, response)
 * <li>"include(String path)" : request.getRequestDispatcher(path).include(request, response)
 * <li>"redirect(String location)" : response.sendRedirect(location)
 * </ul>
 * </p>
 *
 * @author Guillaume Laforge
 * @author Christian Stein
 * @author Jochen Theodorou
 */
public class ServletBinding extends Binding {
    
    /**
     * A OutputStream dummy that will throw a GroovyBugError for any
     * write method call to it. 
     * 
     * @author Jochen Theodorou
     */
    private static class InvalidOutputStream extends OutputStream {
        /**
         * Will always throw a GroovyBugError
         * @see java.io.OutputStream#write(int)
         */
        public void write(int b) {
            throw new GroovyBugError("Any write calls to this stream are invalid!");
        }
    }
    /**
     * A class to manage the response output stream and writer.
     * If the stream have been 'used', then using the writer will cause
     * a IllegalStateException. If the writer have been 'used', then 
     * using the stream will cause a IllegalStateException. 'used' means
     * any write method has been called. Simply requesting the objects will
     * not cause an exception. 
     * 
     * @author Jochen Theodorou
     */
    private static class ServletOutput {
        private HttpServletResponse response;
        private ServletOutputStream outputStream;
        private PrintWriter writer;
        
        public ServletOutput(HttpServletResponse response) {
            this.response = response;
        }
        private ServletOutputStream getResponseStream() throws IOException {
            if (writer!=null) throw new IllegalStateException("The variable 'out' or 'html' have been used already. Use either out/html or sout, not both.");
            if (outputStream==null) outputStream = response.getOutputStream();
            return outputStream;
        }
        public ServletOutputStream getOutputStream() {
            return new ServletOutputStream() {
                public void write(int b) throws IOException {
                    getResponseStream().write(b);                    
                }
                public void close() throws IOException {
                    getResponseStream().close();
                }
                public void flush() throws IOException {
                    getResponseStream().flush();
                }
                public void write(byte[] b) throws IOException {
                    getResponseStream().write(b);
                }
                public void write(byte[] b, int off, int len) throws IOException {
                    getResponseStream().write(b, off, len);
                }
            };
        }
        private PrintWriter getResponseWriter() {
            if (outputStream!=null) throw new IllegalStateException("The variable 'sout' have been used already. Use either out/html or sout, not both.");
            if (writer==null) {
                try {
                    writer = response.getWriter();
                } catch (IOException ioe) {
                    writer = new PrintWriter(new ByteArrayOutputStream());
                    throw new IllegalStateException("unable to get response writer",ioe);
                }
            }
            return writer;
        }
        public PrintWriter getWriter() {
            return new PrintWriter(new InvalidOutputStream()) {
                public boolean checkError() {
                    return getResponseWriter().checkError();
                }
                public void close() {
                    getResponseWriter().close();
                }
                public void flush() {
                    getResponseWriter().flush();
                }
                public void write(char[] buf) {
                    getResponseWriter().write(buf);
                }
                public void write(char[] buf, int off, int len) {
                    getResponseWriter().write(buf, off, len);
                }
                public void write(int c) {
                    getResponseWriter().write(c);
                }
                public void write(String s, int off, int len) {
                    getResponseWriter().write(s, off, len);
                }
                public void println() {
                    getResponseWriter().println();
                }
                public PrintWriter format(String format, Object... args) {
                    getResponseWriter().format(format, args);
                    return this;
                }
                public PrintWriter format(Locale l, String format,  Object... args) {
                    getResponseWriter().format(l, format, args);
                    return this;
                }
            };
        }        
    }    
    
    private boolean initialized;

    /**
     * Initializes a servlet binding.
     *
     * @param request  the HttpServletRequest object
     * @param response the HttpServletRequest object
     * @param context  the ServletContext object
     */
    public ServletBinding(HttpServletRequest request, HttpServletResponse response, ServletContext context) {
        /*
         * Bind the default variables.
         */
        super.setVariable("request", request);
        super.setVariable("response", response);
        super.setVariable("context", context);
        super.setVariable("application", context);

        /*
         * Bind the HTTP session object - if there is one.
         * Note: we don't create one here!
         */
        super.setVariable("session", request.getSession(false));

        /*
         * Bind form parameter key-value hash map.
         *
         * If there are multiple, they are passed as an array.
         */
        Map params = collectParams(request);
        super.setVariable("params", params);

        /*
         * Bind request header key-value hash map.
         */
        Map<String, String> headers = new LinkedHashMap();
        for (Enumeration names = request.getHeaderNames(); names.hasMoreElements();) {
            String headerName = (String) names.nextElement();
            String headerValue = request.getHeader(headerName);
            headers.put(headerName, headerValue);
        }
        super.setVariable("headers", headers);
    }

    @SuppressWarnings("unchecked")
    private Map collectParams(HttpServletRequest request) {
        Map params = new LinkedHashMap();
        for (Enumeration names = request.getParameterNames(); names.hasMoreElements();) {
            String name = (String) names.nextElement();
            if (!super.getVariables().containsKey(name)) {
                String[] values = request.getParameterValues(name);
                if (values.length == 1) {
                    params.put(name, values[0]);
                } else {
                    params.put(name, values);
                }
            }
        }
        return params;
    }

    @Override
    public void setVariable(String name, Object value) {
        lazyInit();
        validateArgs(name, "Can't bind variable to");
        excludeReservedName(name, "out");
        excludeReservedName(name, "sout");
        excludeReservedName(name, "html");
        excludeReservedName(name, "forward");
        excludeReservedName(name, "include");
        excludeReservedName(name, "redirect");
        super.setVariable(name, value);
    }

    @Override
    public Map getVariables() {
        lazyInit();
        return super.getVariables();
    }

    /**
     * @return a writer, an output stream, a markup builder or another requested object
     */
    @Override
    public Object getVariable(String name) {
        lazyInit();
        validateArgs(name, "No variable with");
        return super.getVariable(name);
    }

    private void lazyInit() {
        if (initialized) return;
        initialized = true;
        HttpServletResponse response = (HttpServletResponse) super.getVariable("response");
        ServletOutput output = new ServletOutput(response);
        super.setVariable("out", output.getWriter());
        super.setVariable("sout", output.getOutputStream());
        MarkupBuilder builder = new MarkupBuilder(output.getWriter());
        builder.setExpandEmptyElements(true);
        super.setVariable("html", builder);
        
        // bind forward method
        MethodClosure c = new MethodClosure(this, "forward");
        super.setVariable("forward", c);
        
        // bind include method
        c = new MethodClosure(this, "include");
        super.setVariable("include", c);
        
        // bind redirect method
        c = new MethodClosure(this, "redirect");
        super.setVariable("redirect", c);
    }

    private void validateArgs(String name, String message) {
        if (name == null) {
            throw new IllegalArgumentException(message + " null key.");
        }
        if (name.length() == 0) {
            throw new IllegalArgumentException(message + " blank key name. [length=0]");
        }
    }

    private void excludeReservedName(String name, String reservedName) {
        if (reservedName.equals(name)) {
            throw new IllegalArgumentException("Can't bind variable to key named '" + name + "'.");
        }
    }
    
    public void forward(String path) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) super.getVariable("request");
        HttpServletResponse response = (HttpServletResponse) super.getVariable("response");
        RequestDispatcher dispatcher = request.getRequestDispatcher(path);
        dispatcher.forward(request, response);
    } 
    
    public void include(String path) throws ServletException, IOException {
        HttpServletRequest request = (HttpServletRequest) super.getVariable("request");
        HttpServletResponse response = (HttpServletResponse) super.getVariable("response");
        RequestDispatcher dispatcher = request.getRequestDispatcher(path);
        dispatcher.include(request, response);
    }

    public void redirect(String location) throws IOException {
        HttpServletResponse response = (HttpServletResponse) super.getVariable("response");
        response.sendRedirect(location);
    }    
}

Other Groovy examples (source code examples)

Here is a short list of links related to this Groovy ServletBinding.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.