001: /*
002: * This file is part of the Echo Web Application Framework (hereinafter "Echo").
003: * Copyright (C) 2002-2005 NextApp, Inc.
004: *
005: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
006: *
007: * The contents of this file are subject to the Mozilla Public License Version
008: * 1.1 (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: * http://www.mozilla.org/MPL/
011: *
012: * Software distributed under the License is distributed on an "AS IS" basis,
013: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
014: * for the specific language governing rights and limitations under the
015: * License.
016: *
017: * Alternatively, the contents of this file may be used under the terms of
018: * either the GNU General Public License Version 2 or later (the "GPL"), or
019: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
020: * in which case the provisions of the GPL or the LGPL are applicable instead
021: * of those above. If you wish to allow use of your version of this file only
022: * under the terms of either the GPL or the LGPL, and not to allow others to
023: * use your version of this file under the terms of the MPL, indicate your
024: * decision by deleting the provisions above and replace them with the notice
025: * and other provisions required by the GPL or the LGPL. If you do not delete
026: * the provisions above, a recipient may use your version of this file under
027: * the terms of any one of the MPL, the GPL or the LGPL.
028: */
029:
030: package nextapp.echo2.webrender;
031:
032: import java.io.IOException;
033: import java.io.OutputStream;
034: import java.io.PrintWriter;
035: import java.util.HashMap;
036: import java.util.Map;
037:
038: import javax.servlet.ServletException;
039: import javax.servlet.http.HttpServletRequest;
040: import javax.servlet.http.HttpServletResponse;
041: import javax.servlet.http.HttpSession;
042:
043: /**
044: * A representation of a connection to the server by the client, encapsulating
045: * the servlet request and response objects, and providing access to the
046: * relevant application instance.
047: * <code>Connection</code>s also manage the life-cycle of
048: * <code>UserInstance</code>s within the <code>HttpSession</code>.
049: */
050: public class Connection {
051:
052: /**
053: * Prefix to use for user instance <code>HttpSession</code> keys.
054: */
055: private static final String USER_INSTANCE_SESSION_KEY_PREFIX = "Echo2UserInstance";
056:
057: private HttpServletRequest request;
058: private HttpServletResponse response;
059: private WebRenderServlet servlet;
060: private UserInstance userInstance;
061: private Map propertyMap;
062:
063: /**
064: * Creates a <code>connection</code> object that will handle the given
065: * request and response. The <code>UserInstance</code> will be acquired from the session
066: * if one exists. A session will NOT be created if one does not exist.
067: *
068: * @param servlet the <code>WebRenderServlet</code> generating the connection
069: * @param request the HTTP request object that was passed to the servlet
070: * @param response the HTTP response object that was passed to the servlet
071: */
072: Connection(WebRenderServlet servlet, HttpServletRequest request,
073: HttpServletResponse response) throws IOException,
074: ServletException {
075: super ();
076:
077: this .servlet = servlet;
078: this .request = request;
079: this .response = response;
080:
081: // Configure connection for Multipart Request if required.
082: String contentType = request.getContentType();
083: if (contentType != null
084: && contentType
085: .startsWith(ContentType.MULTIPART_FORM_DATA
086: .getMimeType())) {
087: if (WebRenderServlet.getMultipartRequestWrapper() == null) {
088: throw new WebRenderServletException(
089: "MultipartRequestWrapper was never set and client made an HTTP request "
090: + "encoded as multipart/form-data.");
091: }
092: this .request = WebRenderServlet
093: .getMultipartRequestWrapper().getWrappedRequest(
094: request);
095: }
096:
097: HttpSession session = request.getSession(false);
098: if (session != null) {
099: userInstance = (UserInstance) session
100: .getAttribute(getSessionKey());
101: }
102: }
103:
104: /**
105: * Disposes of the <code>UserInstance</code> associated with this
106: * <code>Connection</code>.
107: */
108: void disposeUserInstance() {
109: HttpSession session = request.getSession(false);
110: if (session != null) {
111: getUserInstance().setServletUri(null);
112: session.removeAttribute(getSessionKey());
113: }
114: }
115:
116: /**
117: * Returns the <code>OutputStream</code> object that may be used to
118: * generate a response. This method may be called once. If it is called,
119: * the getPrintWriter() method may not be called. This method wraps a
120: * call to <code>HttpServletResponse.getOutputStream()</code>. The
121: * <code>OutputStream</code> will be closed by the servlet container.
122: *
123: * @return the <code>OutputStream</code> object that may be used to
124: * generate a response to the client
125: */
126: public OutputStream getOutputStream() {
127: try {
128: return response.getOutputStream();
129: } catch (IOException ex) {
130: throw new WebRenderServletException(
131: "Unable to get PrintWriter.", ex);
132: }
133: }
134:
135: /**
136: * Returns a property from the <code>Connection</code>-persistent
137: * property map. (Properties are disposed of when <code>Connection</code>
138: * has completed).
139: *
140: * @param key the property key (for namespacing purposes, keys should
141: * be prefaced with the full class name of the object setting the
142: * property)
143: * @return the property value
144: */
145: public Object getProperty(String key) {
146: return propertyMap == null ? null : propertyMap.get(key);
147: }
148:
149: /**
150: * Returns the <code>HttpServletRequest</code> wrapped by this
151: * <code>Connection</code>.
152: *
153: * @return the <code>HttpServletRequest</code> wrapped by this
154: * <code>Connection</code>
155: */
156: public HttpServletRequest getRequest() {
157: return request;
158: }
159:
160: /**
161: * Returns the <code>HttpServletResponse</code> wrapped by this
162: * <code>Connection</code>.
163: *
164: * @return the <code>HttpServletResponse</code> wrapped by this
165: * <code>Connection</code>
166: */
167: public HttpServletResponse getResponse() {
168: return response;
169: }
170:
171: /**
172: * Determines the <code>HttpSession</code> key value in which the
173: * associated <code>UserInstance</code> should be stored.
174: *
175: * @return the <code>HttpSession</code> key
176: */
177: private String getSessionKey() {
178: return USER_INSTANCE_SESSION_KEY_PREFIX + ":"
179: + servlet.getServletName();
180: }
181:
182: /**
183: * Returns the <code>WebRenderServlet</code> wrapped by this
184: * <code>Connection</code>.
185: *
186: * @return the <code>WebRenderServlet</code> wrapped by this
187: * <code>Connection</code>
188: */
189: public WebRenderServlet getServlet() {
190: return servlet;
191: }
192:
193: /**
194: * Returns the <code>UserInstance</code> associated with
195: * this connection. If the session has not been initialized, null is
196: * returned.
197: *
198: * @return the <code>UserInstance</code> associated with
199: * this connection
200: */
201: public UserInstance getUserInstance() {
202: return userInstance;
203: }
204:
205: /**
206: * Returns the <code>PrintWriter</code> object that may be used to
207: * generate a response. This method may be called once. If it is called,
208: * the getOuputStream() method may not be called. This method wraps a
209: * call to <code>HttpServletResponse.getWriter()</code>. The
210: * <code>PrintWriter</code> will be closed by the servlet container.
211: *
212: * @return the <code>PrintWriter</code> object that may be used to
213: * generate a response to the client
214: */
215: public PrintWriter getWriter() {
216: try {
217: return response.getWriter();
218: } catch (IOException ex) {
219: throw new WebRenderServletException(
220: "Unable to get PrintWriter.", ex);
221: }
222: }
223:
224: /**
225: * Initializes the state of a new <code>UserInstance</code> and associates
226: * it with this <code>Connection</code> and the underlying
227: * <code>HttpSession</code>
228: *
229: * @param userInstance the <code>UserInstance</code>
230: */
231: void initUserInstance(UserInstance userInstance) {
232: this .userInstance = userInstance;
233: userInstance.setServletUri(request.getRequestURI());
234: HttpSession session = request.getSession(true);
235: session.setAttribute(getSessionKey(), userInstance);
236: }
237:
238: /**
239: * Sets the content type of the response.
240: * This method will automatically append a character encoding to
241: * non-binary content types.
242: *
243: * @param contentType the content type of the response
244: */
245: public void setContentType(ContentType contentType) {
246: UserInstance userInstance = getUserInstance();
247: if (contentType.isBinary() || userInstance == null) {
248: response.setContentType(contentType.getMimeType());
249: } else {
250: response.setContentType(contentType.getMimeType()
251: + "; charset="
252: + userInstance.getCharacterEncoding());
253: }
254: }
255:
256: /**
257: * Sets a property inthe <code>Connection</code>-persistent
258: * property map. (Properties are disposed of when <code>Connection</code>
259: * has completed).
260: *
261: * @param key the property key (for namespacing purposes, keys should
262: * be prefaced with the full class name of the object setting the
263: * property)
264: * @param value the new property value
265: */
266: public void setProperty(String key, Object value) {
267: if (propertyMap == null) {
268: propertyMap = new HashMap();
269: }
270: propertyMap.put(key, value);
271: }
272: }
|