001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.servlet;
016    
017    import com.liferay.portal.kernel.io.RestrictedByteArrayCacheOutputStream;
018    import com.liferay.portal.kernel.io.RestrictedByteArrayCacheOutputStream.FlushPreAction;
019    import com.liferay.portal.kernel.util.UnsyncPrintWriterPool;
020    
021    import java.io.IOException;
022    import java.io.PrintWriter;
023    
024    import java.nio.ByteBuffer;
025    
026    import javax.servlet.ServletOutputStream;
027    import javax.servlet.ServletResponse;
028    import javax.servlet.http.HttpServletResponse;
029    
030    /**
031     * @author Shuyang Zhou
032     */
033    public class RestrictedByteBufferCacheServletResponse
034            extends MetaInfoCacheServletResponse {
035    
036            public RestrictedByteBufferCacheServletResponse(
037                    HttpServletResponse response, int cacheCapacity) {
038    
039                    super(response);
040    
041                    _cacheCapacity = cacheCapacity;
042            }
043    
044            public void flushCache() throws IOException {
045                    if (_restrictedByteArrayCacheOutputStream != null) {
046                            _restrictedByteArrayCacheOutputStream.flush();
047                    }
048            }
049    
050            @Override
051            public int getBufferSize() {
052                    if (_restrictedByteArrayCacheOutputStream == null) {
053                            return _cacheCapacity;
054                    }
055    
056                    if (_restrictedByteArrayCacheOutputStream.isOverflowed()) {
057                            return 0;
058                    }
059    
060                    return _restrictedByteArrayCacheOutputStream.getCacheCapacity();
061            }
062    
063            public ByteBuffer getByteBuffer() {
064                    if (_restrictedByteArrayCacheOutputStream == null) {
065                            return _emptyByteBuffer;
066                    }
067    
068                    return _restrictedByteArrayCacheOutputStream.unsafeGetByteBuffer();
069            }
070    
071            @Override
072            public ServletOutputStream getOutputStream() throws IOException {
073                    if (calledGetWriter) {
074                            throw new IllegalStateException(
075                                    "Unable to obtain OutputStream because Writer is already in " +
076                                            "use");
077                    }
078    
079                    if (_servletOutputStream != null) {
080                            return _servletOutputStream;
081                    }
082    
083                    _restrictedByteArrayCacheOutputStream =
084                            new RestrictedByteArrayCacheOutputStream(
085                                    super.getOutputStream(), _cacheCapacity,
086                                    new FinishResponseFlushPreAction());
087    
088                    _servletOutputStream = new ServletOutputStreamAdapter(
089                            _restrictedByteArrayCacheOutputStream);
090    
091                    calledGetOutputStream = true;
092    
093                    return _servletOutputStream;
094            }
095    
096            @Override
097            public PrintWriter getWriter() throws IOException {
098                    if (calledGetOutputStream) {
099                            throw new IllegalStateException(
100                                    "Unable to obtain Writer because OutputStream is already in " +
101                                            "use");
102                    }
103    
104                    if (_printWriter != null) {
105                            return _printWriter;
106                    }
107    
108                    ServletResponse servletResponse = getResponse();
109    
110                    _restrictedByteArrayCacheOutputStream =
111                            new RestrictedByteArrayCacheOutputStream(
112                                    servletResponse.getOutputStream(), _cacheCapacity,
113                                    new FinishResponseFlushPreAction());
114    
115                    _printWriter = UnsyncPrintWriterPool.borrow(
116                            _restrictedByteArrayCacheOutputStream, getCharacterEncoding());
117    
118                    calledGetWriter = true;
119    
120                    return _printWriter;
121            }
122    
123            public boolean isOverflowed() {
124                    if (_restrictedByteArrayCacheOutputStream == null) {
125                            return false;
126                    }
127    
128                    return _restrictedByteArrayCacheOutputStream.isOverflowed();
129            }
130    
131            @Override
132            public void setBufferSize(int bufferSize) {
133                    if (isCommitted()) {
134                            throw new IllegalStateException("Set buffer size after commit");
135                    }
136    
137                    // Restricted byte buffer cache response cannot accept buffer size
138                    // because it has an fixed size internal buffer.
139    
140            }
141    
142            @Override
143            protected void resetBuffer(boolean nullOutReferences) {
144                    if (nullOutReferences) {
145                            calledGetOutputStream = false;
146                            calledGetWriter = false;
147    
148                            _printWriter = null;
149                            _servletOutputStream = null;
150                            _restrictedByteArrayCacheOutputStream = null;
151                    }
152                    else if (_restrictedByteArrayCacheOutputStream != null) {
153                            _restrictedByteArrayCacheOutputStream.reset();
154                    }
155            }
156    
157            private static ByteBuffer _emptyByteBuffer = ByteBuffer.allocate(0);
158    
159            private int _cacheCapacity;
160            private PrintWriter _printWriter;
161            private RestrictedByteArrayCacheOutputStream
162                    _restrictedByteArrayCacheOutputStream;
163            private ServletOutputStream _servletOutputStream;
164    
165            private class FinishResponseFlushPreAction implements FlushPreAction {
166    
167                    @Override
168                    public void beforeFlush() throws IOException {
169                            finishResponse(false);
170                    }
171            }
172    
173    }