001: /*
002: $Id: ServletBinding.java 2356 2005-06-18 07:53:58Z cstein $
003:
004: Copyright 2005 (C) Guillaume Laforge. All Rights Reserved.
005:
006: Redistribution and use of this software and associated documentation
007: ("Software"), with or without modification, are permitted provided
008: that the following conditions are met:
009:
010: 1. Redistributions of source code must retain copyright
011: statements and notices. Redistributions must also contain a
012: copy of this document.
013:
014: 2. Redistributions in binary form must reproduce the
015: above copyright notice, this list of conditions and the
016: following disclaimer in the documentation and/or other
017: materials provided with the distribution.
018:
019: 3. The name "groovy" must not be used to endorse or promote
020: products derived from this Software without prior written
021: permission of The Codehaus. For written permission,
022: please contact info@codehaus.org.
023:
024: 4. Products derived from this Software may not be called "groovy"
025: nor may "groovy" appear in their names without prior written
026: permission of The Codehaus. "groovy" is a registered
027: trademark of The Codehaus.
028:
029: 5. Due credit should be given to The Codehaus -
030: http://groovy.codehaus.org/
031:
032: THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
033: ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
034: NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
035: FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
036: THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
037: INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
038: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
039: SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
040: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
041: STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
042: ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
043: OF THE POSSIBILITY OF SUCH DAMAGE.
044:
045: */
046: package groovy.servlet;
047:
048: import groovy.lang.Binding;
049: import groovy.xml.MarkupBuilder;
050:
051: import java.io.IOException;
052: import java.util.Enumeration;
053: import java.util.HashMap;
054: import java.util.Map;
055:
056: import javax.servlet.ServletContext;
057: import javax.servlet.http.HttpServletRequest;
058: import javax.servlet.http.HttpServletResponse;
059:
060: /**
061: * Servlet-specific binding extension to lazy load the writer or the output
062: * stream from the response.
063: *
064: * <p>
065: * <h3>Default variables bound</h3>
066: * <ul>
067: * <li><tt>"request"</tt> : the HttpServletRequest object</li>
068: * <li><tt>"response"</tt> : the HttpServletResponse object</li>
069: * <li><tt>"context"</tt> : the ServletContext object </li>
070: * <li><tt>"application"</tt> : same as context</li>
071: * <li><tt>"session"</tt> : convenient for <code>request.getSession(<b>false</b>)</code> - can be null!</li>
072: * <li><tt>"params"</tt> : map of all form parameters - can be empty</li>
073: * <li><tt>"headers"</tt> : map of all <b>request</b> header fields</li>
074: * </ul>
075: *
076: * <p>
077: * <h3>Implicite bound variables</h3>
078: * <ul>
079: * <li><tt>"out"</tt> : response.getWriter() </li>
080: * <li><tt>"sout"</tt> : response.getOutputStream() </li>
081: * <li><tt>"html"</tt> : new MarkupBuilder(response.getWriter()) </li>
082: * </ul>
083: * </p>
084: *
085: * @author Guillaume Laforge
086: * @author Christian Stein
087: */
088: public class ServletBinding extends Binding {
089:
090: private final Binding binding;
091:
092: private final ServletContext context;
093:
094: private final HttpServletRequest request;
095:
096: private final HttpServletResponse response;
097:
098: private MarkupBuilder html;
099:
100: /**
101: * Initializes a servlet binding.
102: */
103: public ServletBinding(HttpServletRequest request,
104: HttpServletResponse response, ServletContext context) {
105: this .binding = new Binding();
106: this .request = request;
107: this .response = response;
108: this .context = context;
109:
110: /*
111: * Bind the default variables.
112: */
113: binding.setVariable("request", request);
114: binding.setVariable("response", response);
115: binding.setVariable("context", context);
116: binding.setVariable("application", context);
117:
118: /*
119: * Bind the HTTP session object - if there is one.
120: * Note: we don't create one here!
121: */
122: binding.setVariable("session", request.getSession(false));
123:
124: /*
125: * Bind form parameter key-value hash map.
126: *
127: * If there are multiple, they are passed as an array.
128: */
129: Map params = new HashMap();
130: for (Enumeration names = request.getParameterNames(); names
131: .hasMoreElements();) {
132: String name = (String) names.nextElement();
133: if (!binding.getVariables().containsKey(name)) {
134: String[] values = request.getParameterValues(name);
135: if (values.length == 1) {
136: params.put(name, values[0]);
137: } else {
138: params.put(name, values);
139: }
140: }
141: }
142: binding.setVariable("params", params);
143:
144: /*
145: * Bind request header key-value hash map.
146: */
147: Map headers = new HashMap();
148: for (Enumeration names = request.getHeaderNames(); names
149: .hasMoreElements();) {
150: String headerName = (String) names.nextElement();
151: String headerValue = request.getHeader(headerName);
152: headers.put(headerName, headerValue);
153: }
154: binding.setVariable("headers", headers);
155: }
156:
157: public void setVariable(String name, Object value) {
158: /*
159: * Check sanity.
160: */
161: if (name == null) {
162: throw new IllegalArgumentException(
163: "Can't bind variable to null key.");
164: }
165: if (name.length() == 0) {
166: throw new IllegalArgumentException(
167: "Can't bind variable to blank key name. [length=0]");
168: }
169: /*
170: * Check implicite key names. See getVariable(String)!
171: */
172: if ("out".equals(name)) {
173: throw new IllegalArgumentException(
174: "Can't bind variable to key named '" + name + "'.");
175: }
176: if ("sout".equals(name)) {
177: throw new IllegalArgumentException(
178: "Can't bind variable to key named '" + name + "'.");
179: }
180: if ("html".equals(name)) {
181: throw new IllegalArgumentException(
182: "Can't bind variable to key named '" + name + "'.");
183: }
184: /*
185: * TODO Check default key names. See constructor(s).
186: */
187:
188: /*
189: * All checks passed, set the variable.
190: */
191: binding.setVariable(name, value);
192: }
193:
194: public Map getVariables() {
195: return binding.getVariables();
196: }
197:
198: /**
199: * @return a writer, an output stream, a markup builder or another requested object
200: */
201: public Object getVariable(String name) {
202: /*
203: * Check sanity.
204: */
205: if (name == null) {
206: throw new IllegalArgumentException(
207: "No variable with null key name.");
208: }
209: if (name.length() == 0) {
210: throw new IllegalArgumentException(
211: "No variable with blank key name. [length=0]");
212: }
213: /*
214: * Check implicite key names. See setVariable(String, Object)!
215: */
216: try {
217: if ("out".equals(name)) {
218: return response.getWriter();
219: }
220: if ("sout".equals(name)) {
221: return response.getOutputStream();
222: }
223: if ("html".equals(name)) {
224: if (html == null) {
225: html = new MarkupBuilder(response.getWriter());
226: }
227: return html;
228: }
229: } catch (IOException e) {
230: String message = "Failed to get writer or output stream from response.";
231: context.log(message, e);
232: throw new RuntimeException(message, e);
233: }
234: /*
235: * Still here? Delegate to the binding object.
236: */
237: return binding.getVariable(name);
238: }
239: }
|