SLING-11486 - Added the support for a Check-for-Closed Test Writer
diff --git a/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponse.java b/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponse.java
index 2f6d9f7..d9fc329 100644
--- a/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponse.java
+++ b/src/main/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponse.java
@@ -39,6 +39,8 @@
static final String CHARSET_SEPARATOR = ";charset=";
+ private boolean enableCheckForClosedWriter = false;
+
private String contentType;
private String characterEncoding;
private int contentLength;
@@ -51,6 +53,10 @@
private final ResponseBodySupport bodySupport = new ResponseBodySupport();
private final CookieSupport cookieSupport = new CookieSupport();
+ public void setEnableCheckForClosedWriter(boolean enableCheckForClosedWriter) {
+ bodySupport.setEnableCheckForClosedWriter(enableCheckForClosedWriter);
+ }
+
@Override
public String getContentType() {
if (this.contentType == null) {
diff --git a/src/main/java/org/apache/sling/servlethelpers/ResponseBodySupport.java b/src/main/java/org/apache/sling/servlethelpers/ResponseBodySupport.java
index e40bdfe..aaf8eda 100644
--- a/src/main/java/org/apache/sling/servlethelpers/ResponseBodySupport.java
+++ b/src/main/java/org/apache/sling/servlethelpers/ResponseBodySupport.java
@@ -23,6 +23,7 @@
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
+import java.util.Locale;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
@@ -35,6 +36,7 @@
*/
class ResponseBodySupport {
+ private boolean enableCheckForClosedWriter = false;
private ByteArrayOutputStream outputStream;
private ServletOutputStream servletOutputStream;
private PrintWriter printWriter;
@@ -43,6 +45,12 @@
reset();
}
+ public void setEnableCheckForClosedWriter(boolean enableCheckForClosedWriter) {
+ this.enableCheckForClosedWriter = enableCheckForClosedWriter;
+ reset();
+ }
+
+
public void reset() {
outputStream = new ByteArrayOutputStream();
servletOutputStream = null;
@@ -72,7 +80,8 @@
public PrintWriter getWriter(String charset) {
if (printWriter == null) {
try {
- printWriter = new PrintWriter(new OutputStreamWriter(getOutputStream(), defaultCharset(charset)));
+ PrintWriter printWriter1 = new PrintWriter(new OutputStreamWriter(getOutputStream(), defaultCharset(charset)));
+ printWriter = enableCheckForClosedWriter ? new CheckForClosedPrintWriter(printWriter1) : printWriter1;
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException("Unsupported encoding: " + defaultCharset(charset), ex);
}
@@ -106,4 +115,232 @@
return StringUtils.defaultString(charset, CharEncoding.UTF_8);
}
+ private class CheckForClosedPrintWriter extends PrintWriter {
+
+ private final PrintWriter delegatee;
+
+ private boolean isClosed = false;
+
+ public CheckForClosedPrintWriter(PrintWriter delegatee) {
+ super(delegatee);
+ this.delegatee = delegatee;
+ }
+
+ private void checkClosed() {
+ if ( this.isClosed ) {
+ throw new WriterAlreadyClosedException();
+ }
+ }
+
+ @Override
+ public PrintWriter append(final char arg0) {
+ this.checkClosed();
+ return delegatee.append(arg0);
+ }
+
+ @Override
+ public PrintWriter append(final CharSequence arg0, final int arg1, final int arg2) {
+ this.checkClosed();
+ return delegatee.append(arg0, arg1, arg2);
+ }
+
+ @Override
+ public PrintWriter append(final CharSequence arg0) {
+ this.checkClosed();
+ return delegatee.append(arg0);
+ }
+
+ @Override
+ public boolean checkError() {
+ this.checkClosed();
+ return delegatee.checkError();
+ }
+
+ @Override
+ public void close() {
+ this.checkClosed();
+ this.isClosed = true;
+ delegatee.close();
+ }
+
+ @Override
+ public void flush() {
+ this.checkClosed();
+ delegatee.flush();
+ }
+
+ @Override
+ public PrintWriter format(final Locale arg0, final String arg1,
+ final Object... arg2) {
+ this.checkClosed();
+ return delegatee.format(arg0, arg1, arg2);
+ }
+
+ @Override
+ public PrintWriter format(final String arg0, final Object... arg1) {
+ this.checkClosed();
+ return delegatee.format(arg0, arg1);
+ }
+
+ @Override
+ public void print(final boolean arg0) {
+ this.checkClosed();
+ delegatee.print(arg0);
+ }
+
+ @Override
+ public void print(final char arg0) {
+ this.checkClosed();
+ delegatee.print(arg0);
+ }
+
+ @Override
+ public void print(final char[] arg0) {
+ this.checkClosed();
+ delegatee.print(arg0);
+ }
+
+ @Override
+ public void print(final double arg0) {
+ this.checkClosed();
+ delegatee.print(arg0);
+ }
+
+ @Override
+ public void print(final float arg0) {
+ this.checkClosed();
+ delegatee.print(arg0);
+ }
+
+ @Override
+ public void print(final int arg0) {
+ this.checkClosed();
+ delegatee.print(arg0);
+ }
+
+ @Override
+ public void print(final long arg0) {
+ this.checkClosed();
+ delegatee.print(arg0);
+ }
+
+ @Override
+ public void print(final Object arg0) {
+ this.checkClosed();
+ delegatee.print(arg0);
+ }
+
+ @Override
+ public void print(final String arg0) {
+ this.checkClosed();
+ delegatee.print(arg0);
+ }
+
+ @Override
+ public PrintWriter printf(final Locale arg0, final String arg1,
+ final Object... arg2) {
+ this.checkClosed();
+ return delegatee.printf(arg0, arg1, arg2);
+ }
+
+ @Override
+ public PrintWriter printf(final String arg0, final Object... arg1) {
+ this.checkClosed();
+ return delegatee.printf(arg0, arg1);
+ }
+
+ @Override
+ public void println() {
+ this.checkClosed();
+ delegatee.println();
+ }
+
+ @Override
+ public void println(final boolean arg0) {
+ this.checkClosed();
+ delegatee.println(arg0);
+ }
+
+ @Override
+ public void println(final char arg0) {
+ this.checkClosed();
+ delegatee.println(arg0);
+ }
+
+ @Override
+ public void println(final char[] arg0) {
+ this.checkClosed();
+ delegatee.println(arg0);
+ }
+
+ @Override
+ public void println(final double arg0) {
+ this.checkClosed();
+ delegatee.println(arg0);
+ }
+
+ @Override
+ public void println(final float arg0) {
+ this.checkClosed();
+ delegatee.println(arg0);
+ }
+
+ @Override
+ public void println(final int arg0) {
+ this.checkClosed();
+ delegatee.println(arg0);
+ }
+
+ @Override
+ public void println(final long arg0) {
+ this.checkClosed();
+ delegatee.println(arg0);
+ }
+
+ @Override
+ public void println(final Object arg0) {
+ this.checkClosed();
+ delegatee.println(arg0);
+ }
+
+ @Override
+ public void println(final String arg0) {
+ this.checkClosed();
+ delegatee.println(arg0);
+ }
+
+ @Override
+ public void write(final char[] arg0, final int arg1, final int arg2) {
+ this.checkClosed();
+ delegatee.write(arg0, arg1, arg2);
+ }
+
+ @Override
+ public void write(final char[] arg0) {
+ this.checkClosed();
+ delegatee.write(arg0);
+ }
+
+ @Override
+ public void write(final int arg0) {
+ this.checkClosed();
+ delegatee.write(arg0);
+ }
+
+ @Override
+ public void write(final String arg0, final int arg1, final int arg2) {
+ this.checkClosed();
+ delegatee.write(arg0, arg1, arg2);
+ }
+
+ @Override
+ public void write(final String arg0) {
+ this.checkClosed();
+ delegatee.write(arg0);
+ }
+
+ };
+
+ public class WriterAlreadyClosedException extends RuntimeException {
+ }
}
diff --git a/src/main/java/org/apache/sling/servlethelpers/package-info.java b/src/main/java/org/apache/sling/servlethelpers/package-info.java
index 1a22083..2bcdb37 100644
--- a/src/main/java/org/apache/sling/servlethelpers/package-info.java
+++ b/src/main/java/org/apache/sling/servlethelpers/package-info.java
@@ -19,5 +19,5 @@
/**
* Mock implementation of selected Servlet-related Sling APIs.
*/
-@org.osgi.annotation.versioning.Version("1.8")
+@org.osgi.annotation.versioning.Version("1.9")
package org.apache.sling.servlethelpers;
diff --git a/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponseTest.java b/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponseTest.java
index 1800b22..2ab0300 100644
--- a/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponseTest.java
+++ b/src/test/java/org/apache/sling/servlethelpers/MockSlingHttpServletResponseTest.java
@@ -25,8 +25,11 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.mockito.Mockito.when;
+import java.io.IOException;
+import java.io.Writer;
import java.util.Collection;
import java.util.Iterator;
import java.util.Locale;
@@ -38,6 +41,7 @@
import org.apache.commons.lang3.CharEncoding;
import org.apache.sling.api.adapter.AdapterManager;
import org.apache.sling.api.adapter.SlingAdaptable;
+import org.apache.sling.servlethelpers.ResponseBodySupport.WriterAlreadyClosedException;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -238,4 +242,17 @@
assertNotEquals(result1, result2);
}
+ @Test
+ public void testCheckForClosedWriter() throws IOException {
+ response.setEnableCheckForClosedWriter(true);
+ Writer writer = response.getWriter();
+ // Close it twice and make sure the second one fails
+ writer.close();
+ try {
+ writer.close();
+ fail("Subsequent Closing of a Check-for-Closed Writer was not failing");
+ } catch(WriterAlreadyClosedException e) {
+ // Expected
+ }
+ }
}