This is an automated email from the ASF dual-hosted git repository.

jamesbognar pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/juneau.git


The following commit(s) were added to refs/heads/master by this push:
     new f3dcd74  JUNEAU-80 - DefaultHandler should not close the underlying 
output stream.
f3dcd74 is described below

commit f3dcd74120494348f6e3c1f3264751a0e9048833
Author: JamesBognar <[email protected]>
AuthorDate: Sat Feb 3 15:28:46 2018 -0500

    JUNEAU-80 - DefaultHandler should not close the underlying output
    stream.
---
 .../encoders/{GzipEncoder.java => Finishable.java} | 77 ++++++++-----------
 .../org/apache/juneau/encoders/GzipEncoder.java    | 14 ++--
 juneau-doc/src/main/javadoc/overview.html          |  7 ++
 .../apache/juneau/rest/FinishablePrintWriter.java  | 89 +++++++++++-----------
 .../juneau/rest/FinishableServletOutputStream.java | 78 +++++++++++++++++++
 .../java/org/apache/juneau/rest/RestResponse.java  | 56 ++++----------
 .../org/apache/juneau/rest/StreamResource.java     |  1 +
 .../juneau/rest/response/DefaultHandler.java       | 15 ++--
 8 files changed, 191 insertions(+), 146 deletions(-)

diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/GzipEncoder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/Finishable.java
similarity index 66%
copy from 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/GzipEncoder.java
copy to 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/Finishable.java
index 8ebad4c..c86c116 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/GzipEncoder.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/Finishable.java
@@ -1,46 +1,31 @@
-// 
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                
                                              *
-// *                                                                           
                                              *
-// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
-// *                                                                           
                                              *
-// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the 
License.                                              *
-// 
***************************************************************************************************************************
-package org.apache.juneau.encoders;
-
-import java.io.*;
-import java.util.zip.*;
-
-/**
- * Encoder for handling <js>"gzip"</js> encoding and decoding.
- */
-public class GzipEncoder extends Encoder {
-
-       @Override /* Encoder */
-       public OutputStream getOutputStream(OutputStream os) throws IOException 
{
-               return new GZIPOutputStream(os) {
-                       @Override /* OutputStream */
-                       public final void close() throws IOException {
-                               finish();
-                               super.close();
-                       }
-               };
-       }
-
-       @Override /* Encoder */
-       public InputStream getInputStream(InputStream is) throws IOException {
-               return new GZIPInputStream(is);
-       }
-
-       /**
-        * Returns <code>[<js>"gzip"</js>]</code>.
-        */
-       @Override /* Encoder */
-       public String[] getCodings() {
-               return new String[]{"gzip"};
-       }
-}
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              * 
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.encoders;
+
+import java.io.*;
+
+/**
+ * Interface that identifies an output stream has having a 
<code>finish()</code> method.
+ */
+public interface Finishable {
+
+       /**
+        * Finishes writing compressed data to the output stream without 
closing the underlying stream. 
+        * 
+        * <p>
+        * Use this method when applying multiple filters in succession to the 
same output stream.
+        * 
+        * @throws IOException
+        */
+       void finish() throws IOException;
+}
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/GzipEncoder.java
 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/GzipEncoder.java
index 8ebad4c..1596af5 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/GzipEncoder.java
+++ 
b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/GzipEncoder.java
@@ -22,13 +22,7 @@ public class GzipEncoder extends Encoder {
 
        @Override /* Encoder */
        public OutputStream getOutputStream(OutputStream os) throws IOException 
{
-               return new GZIPOutputStream(os) {
-                       @Override /* OutputStream */
-                       public final void close() throws IOException {
-                               finish();
-                               super.close();
-                       }
-               };
+               return new FinishableGZIPOutputStream(os);
        }
 
        @Override /* Encoder */
@@ -43,4 +37,10 @@ public class GzipEncoder extends Encoder {
        public String[] getCodings() {
                return new String[]{"gzip"};
        }
+       
+       private static class FinishableGZIPOutputStream extends 
GZIPOutputStream implements Finishable {
+               FinishableGZIPOutputStream(OutputStream out) throws IOException 
{
+                       super(out);
+               }
+       }
 }
diff --git a/juneau-doc/src/main/javadoc/overview.html 
b/juneau-doc/src/main/javadoc/overview.html
index 9ed4114..18d8491 100644
--- a/juneau-doc/src/main/javadoc/overview.html
+++ b/juneau-doc/src/main/javadoc/overview.html
@@ -13356,6 +13356,13 @@
                                        <li>{@link 
org.apache.juneau.rest.ReaderResourceBuilder}
                                        <li>{@link 
org.apache.juneau.rest.StreamResourceBuilder}
                                </ul>
+                       <li>
+                               {@link 
org.apache.juneau.rest.RestResponse#getNegotiatedOutputStream()} now returns a 
+                               {@link 
org.apache.juneau.rest.FinishableServletOutputStream} and {@link 
org.apache.juneau.rest.RestResponse#getNegotiatedWriter()}
+                               now returns a {@link 
org.apache.juneau.rest.FinishablePrintWriter} that allows you to finish the 
output
+                               without closing the stream.
+                               <br>The {@link 
org.apache.juneau.rest.response.DefaultHandler} class now calls 
<code>finish()</code>
+                               instead of <code>close()</code> on the stream.
                </ul>
 
                <h5 class='topic'>juneau-rest-client</h5>
diff --git 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/GzipEncoder.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/FinishablePrintWriter.java
similarity index 65%
copy from 
juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/GzipEncoder.java
copy to 
juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/FinishablePrintWriter.java
index 8ebad4c..4af84f4 100644
--- 
a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/encoders/GzipEncoder.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/FinishablePrintWriter.java
@@ -1,46 +1,43 @@
-// 
***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
-// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
-// * with the License.  You may obtain a copy of the License at                
                                              *
-// *                                                                           
                                              *
-// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
-// *                                                                           
                                              *
-// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
-// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
-// * specific language governing permissions and limitations under the 
License.                                              *
-// 
***************************************************************************************************************************
-package org.apache.juneau.encoders;
-
-import java.io.*;
-import java.util.zip.*;
-
-/**
- * Encoder for handling <js>"gzip"</js> encoding and decoding.
- */
-public class GzipEncoder extends Encoder {
-
-       @Override /* Encoder */
-       public OutputStream getOutputStream(OutputStream os) throws IOException 
{
-               return new GZIPOutputStream(os) {
-                       @Override /* OutputStream */
-                       public final void close() throws IOException {
-                               finish();
-                               super.close();
-                       }
-               };
-       }
-
-       @Override /* Encoder */
-       public InputStream getInputStream(InputStream is) throws IOException {
-               return new GZIPInputStream(is);
-       }
-
-       /**
-        * Returns <code>[<js>"gzip"</js>]</code>.
-        */
-       @Override /* Encoder */
-       public String[] getCodings() {
-               return new String[]{"gzip"};
-       }
-}
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              * 
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.rest;
+
+import java.io.*;
+
+import org.apache.juneau.encoders.*;
+
+/**
+ * A wrapped {@link PrintWriter} with an added <code>finish()</code> method.
+ */
+public class FinishablePrintWriter extends PrintWriter implements Finishable {
+
+       final Finishable f;
+
+       FinishablePrintWriter(OutputStream out, String characterEncoding) 
throws IOException {
+               super(new OutputStreamWriter(out, characterEncoding));
+               f = (out instanceof Finishable ? (Finishable)out : null);
+       }
+
+
+       /**
+        * Calls {@link Finishable#finish()} on the underlying output stream.
+        * 
+        * <p>
+        * A no-op if the underlying output stream does not implement the 
{@link Finishable} interface.
+        */
+       @Override /* Finishable */
+       public void finish() throws IOException {
+               if (f != null)
+                       f.finish();
+       }
+}
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/FinishableServletOutputStream.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/FinishableServletOutputStream.java
new file mode 100644
index 0000000..87e2044
--- /dev/null
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/FinishableServletOutputStream.java
@@ -0,0 +1,78 @@
+// 
***************************************************************************************************************************
+// * Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.  See the NOTICE file *
+// * distributed with this work for additional information regarding copyright 
ownership.  The ASF licenses this file        *
+// * to you under the Apache License, Version 2.0 (the "License"); you may not 
use this file except in compliance            *
+// * with the License.  You may obtain a copy of the License at                
                                              * 
+// *                                                                           
                                              *
+// *  http://www.apache.org/licenses/LICENSE-2.0                               
                                              *
+// *                                                                           
                                              *
+// * Unless required by applicable law or agreed to in writing, software 
distributed under the License is distributed on an  *
+// * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 
express or implied.  See the License for the        *
+// * specific language governing permissions and limitations under the 
License.                                              *
+// 
***************************************************************************************************************************
+package org.apache.juneau.rest;
+
+import java.io.*;
+
+import javax.servlet.*;
+
+import org.apache.juneau.encoders.*;
+
+/**
+ * A wrapped {@link ServletOutputStream} with an added <code>finish()</code> 
method.
+ */
+public class FinishableServletOutputStream extends ServletOutputStream 
implements Finishable {
+
+       final OutputStream os;
+       final ServletOutputStream sos;
+       final Finishable f;
+       
+       FinishableServletOutputStream(OutputStream os) {
+               this.os = os;
+               this.sos = (os instanceof ServletOutputStream ? 
(ServletOutputStream)os : null);
+               this.f = (os instanceof Finishable ? (Finishable)os : null);
+       }
+       
+       @Override /* OutputStream */
+       public final void write(byte[] b, int off, int len) throws IOException {
+               os.write(b, off, len);
+       }
+       
+       @Override /* OutputStream */
+       public final void write(int b) throws IOException {
+               os.write(b);
+       }
+       
+       @Override /* OutputStream */
+       public final void flush() throws IOException {
+               os.flush();
+       }
+       
+       @Override /* OutputStream */
+       public final void close() throws IOException {
+               os.close();
+       }
+       
+       @Override /* ServletOutputStream */
+       public boolean isReady() {
+               return sos == null ? true : sos.isReady();
+       }
+       
+       @Override /* ServletOutputStream */
+       public void setWriteListener(WriteListener arg0) {
+               if (sos != null)
+                       sos.setWriteListener(arg0);
+       }
+
+       /**
+        * Calls {@link Finishable#finish()} on the underlying output stream.
+        * 
+        * <p>
+        * A no-op if the underlying output stream does not implement the 
{@link Finishable} interface.
+        */
+       @Override /* Finishable */
+       public void finish() throws IOException {
+               if (f != null)
+                       f.finish();
+       }
+}
\ No newline at end of file
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
index 21f196b..1228145 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/RestResponse.java
@@ -58,8 +58,9 @@ public final class RestResponse extends 
HttpServletResponseWrapper {
        private Object output;                       // The POJO being sent to 
the output.
        private boolean isNullOutput;                // The output is null (as 
opposed to not being set at all)
        private RequestProperties properties;                // Response 
properties
-       private ServletOutputStream os;
-       private PrintWriter w;
+       private ServletOutputStream sos;
+       private FinishableServletOutputStream os;
+       private FinishablePrintWriter w;
        private HtmlDocBuilder htmlDocBuilder;
 
        /**
@@ -347,7 +348,7 @@ public final class RestResponse extends 
HttpServletResponseWrapper {
         * @return A negotiated output stream.
         * @throws IOException
         */
-       public ServletOutputStream getNegotiatedOutputStream() throws 
IOException {
+       public FinishableServletOutputStream getNegotiatedOutputStream() throws 
IOException {
                if (os == null) {
                        Encoder encoder = null;
                        EncoderGroup encoders = restJavaMethod.encoders;
@@ -372,46 +373,18 @@ public final class RestResponse extends 
HttpServletResponseWrapper {
                                                setHeader("content-encoding", 
encoding);
                                }
                        }
-                       os = getOutputStream();
-                       if (encoder != null) {
-                               @SuppressWarnings("resource")
-                               final OutputStream os2 = 
encoder.getOutputStream(os);
-                               os = new ServletOutputStream(){
-                                       @Override /* OutputStream */
-                                       public final void write(byte[] b, int 
off, int len) throws IOException {
-                                               os2.write(b, off, len);
-                                       }
-                                       @Override /* OutputStream */
-                                       public final void write(int b) throws 
IOException {
-                                               os2.write(b);
-                                       }
-                                       @Override /* OutputStream */
-                                       public final void flush() throws 
IOException {
-                                               os2.flush();
-                                       }
-                                       @Override /* OutputStream */
-                                       public final void close() throws 
IOException {
-                                               os2.close();
-                                       }
-                                       @Override /* ServletOutputStream */
-                                       public boolean isReady() {
-                                               return true;
-                                       }
-                                       @Override /* ServletOutputStream */
-                                       public void 
setWriteListener(WriteListener arg0) {
-                                               throw new NoSuchMethodError();
-                                       }
-                               };
-                       }
+                       @SuppressWarnings("resource")
+                       ServletOutputStream sos = getOutputStream();
+                       os = new FinishableServletOutputStream(encoder == null 
? sos : encoder.getOutputStream(sos)); 
                }
                return os;
        }
 
        @Override /* ServletResponse */
        public ServletOutputStream getOutputStream() throws IOException {
-               if (os == null)
-                       os = super.getOutputStream();
-               return os;
+               if (sos == null)
+                       sos = super.getOutputStream();
+               return sos;
        }
 
        /**
@@ -420,7 +393,7 @@ public final class RestResponse extends 
HttpServletResponseWrapper {
         * @return <jk>true</jk> if {@link #getOutputStream()} has been called.
         */
        public boolean getOutputStreamCalled() {
-               return os != null;
+               return sos != null;
        }
 
        /**
@@ -463,11 +436,12 @@ public final class RestResponse extends 
HttpServletResponseWrapper {
         * @return The negotiated writer.
         * @throws IOException
         */
-       public PrintWriter getNegotiatedWriter() throws IOException {
+       public FinishablePrintWriter getNegotiatedWriter() throws IOException {
                return getWriter(false);
        }
 
-       private PrintWriter getWriter(boolean raw) throws IOException {
+       @SuppressWarnings("resource")
+       private FinishablePrintWriter getWriter(boolean raw) throws IOException 
{
                if (w != null)
                        return w;
 
@@ -477,7 +451,7 @@ public final class RestResponse extends 
HttpServletResponseWrapper {
 
                try {
                        OutputStream out = (raw ? getOutputStream() : 
getNegotiatedOutputStream());
-                       w = new PrintWriter(new OutputStreamWriter(out, 
getCharacterEncoding()));
+                       w = new FinishablePrintWriter(out, 
getCharacterEncoding());
                        return w;
                } catch (UnsupportedEncodingException e) {
                        String ce = getCharacterEncoding();
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/StreamResource.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/StreamResource.java
index e8ba790..a62cb17 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/StreamResource.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/StreamResource.java
@@ -114,6 +114,7 @@ public class StreamResource implements Streamable {
        public void streamTo(OutputStream os) throws IOException {
                for (byte[] b : contents)
                        os.write(b);
+               os.flush();
        }
 
        @Override /* Streamable */
diff --git 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
index 609a862..96a5ba1 100644
--- 
a/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
+++ 
b/juneau-rest/juneau-rest-server/src/main/java/org/apache/juneau/rest/response/DefaultHandler.java
@@ -69,20 +69,23 @@ public class DefaultHandler implements ResponseHandler {
 
                                if (! session.isWriterSerializer()) {
                                        if (req.isPlainText()) {
-                                               Writer w = 
res.getNegotiatedWriter();
+                                               FinishablePrintWriter w = 
res.getNegotiatedWriter();
                                                ByteArrayOutputStream baos = 
new ByteArrayOutputStream();
                                                session.serialize(output, baos);
                                                
w.write(StringUtils.toSpacedHex(baos.toByteArray()));
-                                               w.close();  // Leave open if 
exception occurs.
+                                               w.flush();
+                                               w.finish();
                                        } else {
-                                               OutputStream os = 
res.getNegotiatedOutputStream();
+                                               FinishableServletOutputStream 
os = res.getNegotiatedOutputStream();
                                                session.serialize(output, os);
-                                               os.close();  // Leave open if 
exception occurs.
+                                               os.flush();
+                                               os.finish();
                                        }
                                } else {
-                                       Writer w = res.getNegotiatedWriter();
+                                       FinishablePrintWriter w = 
res.getNegotiatedWriter();
                                        session.serialize(output, w);
-                                       w.close();  // Leave open if exception 
occurs.
+                                       w.flush();
+                                       w.finish();
                                }
                        } catch (SerializeException e) {
                                throw new 
RestException(SC_INTERNAL_SERVER_ERROR, e);

-- 
To stop receiving notification emails like this one, please contact
[email protected].

Reply via email to