001: /**
002: * Copyright 2006 Webmedia Group Ltd.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: **/package org.araneaframework.http.util;
016:
017: import java.io.ByteArrayOutputStream;
018: import java.io.IOException;
019: import java.io.OutputStreamWriter;
020: import java.io.PrintWriter;
021: import javax.servlet.ServletOutputStream;
022: import javax.servlet.http.HttpServletResponse;
023: import javax.servlet.http.HttpServletResponseWrapper;
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026: import org.araneaframework.OutputData;
027: import org.araneaframework.core.AraneaRuntimeException;
028: import org.araneaframework.core.Assert;
029: import org.araneaframework.http.HttpOutputData;
030:
031: /**
032: * A helper class for providing rollback and commit functionality on an OutputData.
033: * If something has been written to the OutputData, <code>commit()</code> will flush
034: * it, forcing any buffered output to be written out. <code>rollback()</code> will
035: * discard the contents of the buffer.
036: *
037: * @author "Toomas Römer" <toomas@webmedia.ee>
038: * @author Jevgeni Kabanov (ekabanov <i>at</i> araneaframework <i>dot</i> org)
039: *
040: * TODO: rewrite as HttpOutputData wrapper
041: */
042: public class AtomicResponseHelper {
043: //*******************************************************************
044: // CONSTANTS
045: //*******************************************************************
046: private static final Log log = LogFactory
047: .getLog(AtomicResponseHelper.class);
048:
049: //*******************************************************************
050: // FIELDS
051: //*******************************************************************
052: private ResponseWrapper atomicWrapper;
053:
054: public AtomicResponseHelper(OutputData outputData) {
055: Assert.isInstanceOfParam(HttpOutputData.class, outputData,
056: "outputData");
057:
058: atomicWrapper = new ResponseWrapper(ServletUtil
059: .getResponse(outputData));
060: ServletUtil.setResponse(outputData, atomicWrapper);
061: }
062:
063: //*******************************************************************
064: // PRIVATE CLASSES
065: //*******************************************************************
066: /**
067: * Wraps a HttpServletResponse to make it possible of resetting and commiting it.
068: */
069: private static class ResponseWrapper extends
070: HttpServletResponseWrapper {
071: private ServletOutputStream out;
072: private PrintWriter writerOut;
073:
074: public ResponseWrapper(HttpServletResponse arg0) {
075: super (arg0);
076:
077: resetStream();
078: }
079:
080: private void resetStream() {
081: out = new AraneaServletOutputStream();
082: }
083:
084: public ServletOutputStream getOutputStream() throws IOException {
085: if (out == null)
086: return getResponse().getOutputStream();
087:
088: return out;
089: }
090:
091: public PrintWriter getWriter() throws IOException {
092: if (out == null)
093: return getResponse().getWriter();
094:
095: if (writerOut == null) {
096: if (getResponse().getCharacterEncoding() != null) {
097: writerOut = new PrintWriter(new OutputStreamWriter(
098: out, getResponse().getCharacterEncoding()));
099: } else {
100: writerOut = new PrintWriter(new OutputStreamWriter(
101: out));
102: }
103: }
104:
105: return writerOut;
106: }
107:
108: /**
109: * If the output has not been commited yet, commits it.
110: * @throws AraneaRuntimeException if output has been commited already.
111: */
112: public void commit() throws IOException {
113: if (out == null)
114: throw new IllegalStateException(
115: "Cannot commit buffer - response is already committed");
116:
117: if (writerOut != null)
118: writerOut.flush();
119: out.flush();
120:
121: byte[] data = ((AraneaServletOutputStream) out).getData();
122:
123: getResponse().getOutputStream().write(data);
124: getResponse().getOutputStream().flush();
125:
126: out = null;
127: }
128:
129: /**
130: * If the output has not been commited yet, clears the content of the underlying
131: * buffer in the response without clearing headers or status code.
132: */
133: public void rollback() {
134: if (out == null)
135: throw new IllegalStateException(
136: "Cannot reset buffer - response is already committed");
137:
138: resetStream();
139: writerOut = null;
140: }
141:
142: public byte[] getData() throws Exception {
143: return ((AraneaServletOutputStream) out).getData();
144: }
145: }
146:
147: private static class AraneaServletOutputStream extends
148: ServletOutputStream {
149: private ByteArrayOutputStream out;
150:
151: private AraneaServletOutputStream() {
152: out = new ByteArrayOutputStream(20480);
153: }
154:
155: public void write(int b) throws IOException {
156: out.write(b);
157: }
158:
159: public void write(byte[] b) throws IOException {
160: out.write(b);
161: }
162:
163: public void write(byte[] b, int offset, int len)
164: throws IOException {
165: out.write(b, offset, len);
166: }
167:
168: public void flush() throws IOException {
169: out.flush();
170: }
171:
172: public byte[] getData() {
173: return out.toByteArray();
174: }
175: }
176:
177: //*******************************************************************
178: // PUBLIC METHODS
179: //*******************************************************************
180:
181: public void commit() throws Exception {
182: atomicWrapper.commit();
183: }
184:
185: public void rollback() throws Exception {
186: atomicWrapper.rollback();
187: }
188:
189: public byte[] getData() throws Exception {
190: return atomicWrapper.getData();
191: }
192: }
|