You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2016/12/07 16:00:09 UTC

[1/2] cxf git commit: [CXF-6882] Adding CXF UseNioWrite extension - supported for JAXRS only at the moment

Repository: cxf
Updated Branches:
  refs/heads/master 70317dafc -> 58b379bdf


[CXF-6882] Adding CXF UseNioWrite extension - supported for JAXRS only at the moment


Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/59436ead
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/59436ead
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/59436ead

Branch: refs/heads/master
Commit: 59436eadca147ba937a24a4f4fc6ced93cc0bc7f
Parents: 70317da
Author: Sergey Beryozkin <sb...@gmail.com>
Authored: Wed Dec 7 15:59:14 2016 +0000
Committer: Sergey Beryozkin <sb...@gmail.com>
Committed: Wed Dec 7 15:59:14 2016 +0000

----------------------------------------------------------------------
 .../cxf/jaxrs/nio/NioWriteListenerImpl.java     |  7 +-
 .../cxf/jaxrs/provider/BinaryDataProvider.java  | 81 +++++++++++++++++++-
 .../cxf/systest/jaxrs/nio/NioBookStore.java     | 13 +++-
 .../cxf/systest/jaxrs/nio/NioBookStoreTest.java | 14 ++++
 4 files changed, 108 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/59436ead/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/nio/NioWriteListenerImpl.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/nio/NioWriteListenerImpl.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/nio/NioWriteListenerImpl.java
index aed2cec..d35b4dd 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/nio/NioWriteListenerImpl.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/nio/NioWriteListenerImpl.java
@@ -34,7 +34,7 @@ public final class NioWriteListenerImpl implements WriteListener {
     private final NioWriteEntity entity;
     private final DelegatingNioOutputStream out;
 
-    NioWriteListenerImpl(Continuation cont, NioWriteEntity entity, OutputStream out) {
+    public NioWriteListenerImpl(Continuation cont, NioWriteEntity entity, OutputStream out) {
         this.cont = cont;
         this.entity = entity;
         this.out = new DelegatingNioOutputStream(out);
@@ -44,6 +44,11 @@ public final class NioWriteListenerImpl implements WriteListener {
     public void onWritePossible() throws IOException {
         while (cont.isReadyForWrite()) {
             if (!entity.getWriter().write(out)) {
+                // REVISIT:
+                // Immediately closing the async context with cont.resume() works better
+                // at the moment - with cont.resume() Jetty throws NPE in its internal code
+                // which is quite possibly a Jetty bug.
+                // Do we really need to complete the out chain after the response has been written out ?
                 cont.resume();
                 return;
             }

http://git-wip-us.apache.org/repos/asf/cxf/blob/59436ead/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/BinaryDataProvider.java
----------------------------------------------------------------------
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/BinaryDataProvider.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/BinaryDataProvider.java
index 980b076..f3e9353 100644
--- a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/BinaryDataProvider.java
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/provider/BinaryDataProvider.java
@@ -38,19 +38,31 @@ import java.security.DigestInputStream;
 import java.util.UUID;
 import java.util.logging.Logger;
 
+import javax.servlet.WriteListener;
+import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.NioOutputStream;
+import javax.ws.rs.core.NioWriterHandler;
 import javax.ws.rs.core.StreamingOutput;
 import javax.ws.rs.ext.MessageBodyReader;
 import javax.ws.rs.ext.MessageBodyWriter;
 
+import org.apache.cxf.annotations.UseNioWrite;
 import org.apache.cxf.common.logging.LogUtils;
 import org.apache.cxf.common.util.MessageDigestInputStream;
+import org.apache.cxf.continuations.Continuation;
+import org.apache.cxf.continuations.ContinuationProvider;
 import org.apache.cxf.helpers.FileUtils;
 import org.apache.cxf.helpers.IOUtils;
 import org.apache.cxf.jaxrs.impl.HttpHeadersImpl;
+import org.apache.cxf.jaxrs.nio.DelegatingNioOutputStream;
+import org.apache.cxf.jaxrs.nio.NioWriteEntity;
+import org.apache.cxf.jaxrs.nio.NioWriteListenerImpl;
+import org.apache.cxf.jaxrs.utils.AnnotationUtils;
 import org.apache.cxf.jaxrs.utils.ExceptionUtils;
+import org.apache.cxf.jaxrs.utils.JAXRSUtils;
 import org.apache.cxf.message.Message;
 import org.apache.cxf.message.MessageUtils;
 import org.apache.cxf.phase.PhaseInterceptorChain;
@@ -151,12 +163,12 @@ public class BinaryDataProvider<T> extends AbstractConfigurableProvider
         throws IOException {
         
         if (InputStream.class.isAssignableFrom(o.getClass())) {
-            copyInputToOutput((InputStream)o, os, headers);
+            copyInputToOutput((InputStream)o, os, annotations, headers);
         } else if (File.class.isAssignableFrom(o.getClass())) {
             copyInputToOutput(new BufferedInputStream(
-                    new FileInputStream((File)o)), os, headers);
+                    new FileInputStream((File)o)), os, annotations, headers);
         } else if (byte[].class.isAssignableFrom(o.getClass())) {
-            copyInputToOutput(new ByteArrayInputStream((byte[])o), os, headers);
+            copyInputToOutput(new ByteArrayInputStream((byte[])o), os, annotations, headers);
         } else if (Reader.class.isAssignableFrom(o.getClass())) {
             try {
                 Writer writer = new OutputStreamWriter(os, getEncoding(type));
@@ -185,19 +197,48 @@ public class BinaryDataProvider<T> extends AbstractConfigurableProvider
     }
     
     protected void copyInputToOutput(InputStream is, OutputStream os,
-            MultivaluedMap<String, Object> outHeaders) throws IOException {
+            Annotation[] anns, MultivaluedMap<String, Object> outHeaders) throws IOException {
         if (isRangeSupported()) {
             Message inMessage = PhaseInterceptorChain.getCurrentMessage().getExchange().getInMessage();
             handleRangeRequest(is, os, new HttpHeadersImpl(inMessage), outHeaders);
         } else {
+            boolean nioWrite = AnnotationUtils.getAnnotation(anns, UseNioWrite.class) != null;
+            if (nioWrite) {
+                ContinuationProvider provider = getContinuationProvider();
+                if (provider != null) {
+                    copyUsingNio(is, os, provider.getContinuation());
+                }
+                return;
+            } 
             if (closeResponseInputStream) {
                 IOUtils.copyAndCloseInput(is, os, bufferSize);
             } else {
                 IOUtils.copy(is, os, bufferSize);
             }
+            
         }
     }
     
+    protected void copyUsingNio(InputStream is, OutputStream os, Continuation cont) {
+        NioWriteListenerImpl listener = 
+            new NioWriteListenerImpl(cont, 
+                                     new NioWriteEntity(getNioHandler(is), null), 
+                                     new DelegatingNioOutputStream(os));
+        Message m = JAXRSUtils.getCurrentMessage();
+        m.put(WriteListener.class, listener);
+        // After this MBW registers the listener, JAXRSOutInterceptor is done, and the
+        // out chain will need to be resumed from the interceptor which follows it 
+        m.put("suspend.chain.on.current.interceptor", Boolean.TRUE);
+        cont.suspend(0);
+    }
+    
+    private ContinuationProvider getContinuationProvider() {
+        return (ContinuationProvider)JAXRSUtils.getCurrentMessage().getExchange()
+            .getInMessage().get(ContinuationProvider.class.getName());
+    }
+
+
+
     protected void handleRangeRequest(InputStream is, 
                                       OutputStream os,
                                       HttpHeaders inHeaders, 
@@ -231,4 +272,36 @@ public class BinaryDataProvider<T> extends AbstractConfigurableProvider
     public void setBufferSize(int bufferSize) {
         this.bufferSize = bufferSize;
     }
+    
+    protected NioWriterHandler getNioHandler(final InputStream in) {
+        
+        return new NioWriterHandler() {
+            final byte[] buffer = new byte[bufferSize];
+            @Override
+            public boolean write(NioOutputStream out) {
+                try {
+                    final int n = in.read(buffer);
+    
+                    if (n >= 0) {
+                        out.write(buffer, 0, n);
+                        return true;
+                    }
+                    if (closeResponseInputStream) {    
+                        try { 
+                            in.close(); 
+                        } catch (IOException ex) { 
+                            /* do nothing */ 
+                        }
+                    }
+                    
+                    return false;
+                } catch (IOException ex) {
+                    throw new WebApplicationException(ex);    
+                }
+                
+            } 
+        };
+            
+        
+    }
 }

http://git-wip-us.apache.org/repos/asf/cxf/blob/59436ead/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/nio/NioBookStore.java
----------------------------------------------------------------------
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/nio/NioBookStore.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/nio/NioBookStore.java
index bd885f5..ce2507a 100644
--- a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/nio/NioBookStore.java
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/nio/NioBookStore.java
@@ -20,22 +20,23 @@ package org.apache.cxf.systest.jaxrs.nio;
 
 import java.io.ByteArrayInputStream;
 import java.io.IOException;
+import java.io.InputStream;
 
 import javax.ws.rs.GET;
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
-import javax.ws.rs.QueryParam;
 import javax.ws.rs.WebApplicationException;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import org.apache.cxf.annotations.UseNioWrite;
 import org.apache.cxf.helpers.IOUtils;
 
 @Path("/bookstore")
 public class NioBookStore {
     @GET
     @Produces(MediaType.TEXT_PLAIN)
-    public Response readBooks(@QueryParam("path") String path) throws IOException {
+    public Response readBooks() throws IOException {
         final ByteArrayInputStream in = new ByteArrayInputStream(
             IOUtils.readBytesFromStream(getClass().getResourceAsStream("/files/books.txt")));
         final byte[] buffer = new byte[4096];
@@ -66,4 +67,12 @@ public class NioBookStore {
             }
         ).build();
     }
+    
+    @GET
+    @Produces(MediaType.TEXT_PLAIN)
+    @Path("/is")
+    @UseNioWrite
+    public InputStream readBooksFromInputStream() throws IOException {
+        return getClass().getResourceAsStream("/files/books.txt");
+    }
 }

http://git-wip-us.apache.org/repos/asf/cxf/blob/59436ead/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/nio/NioBookStoreTest.java
----------------------------------------------------------------------
diff --git a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/nio/NioBookStoreTest.java b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/nio/NioBookStoreTest.java
index 19b0830..c1743e3 100644
--- a/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/nio/NioBookStoreTest.java
+++ b/systests/jaxrs/src/test/java/org/apache/cxf/systest/jaxrs/nio/NioBookStoreTest.java
@@ -58,6 +58,20 @@ public class NioBookStoreTest extends AbstractBusClientServerTestBase {
         }
     }
     
+    @Test
+    public void testGetAllBooksIs() throws Exception {
+        final Response response = createWebClient("/bookstore/is", MediaType.TEXT_PLAIN).get();
+        
+        try {
+            assertEquals(200, response.getStatus());
+            
+            assertThat(response.readEntity(String.class), equalTo(IOUtils.readStringFromStream(
+                getClass().getResourceAsStream("/files/books.txt"))));
+        } finally {
+            response.close();
+        }
+    }
+    
     protected WebClient createWebClient(final String url, final String mediaType) {
         final List< ? > providers = Arrays.asList(new JacksonJsonProvider());
         


[2/2] cxf git commit: [CXF-6882] Adding the resource

Posted by se...@apache.org.
[CXF-6882] Adding the resource


Project: http://git-wip-us.apache.org/repos/asf/cxf/repo
Commit: http://git-wip-us.apache.org/repos/asf/cxf/commit/58b379bd
Tree: http://git-wip-us.apache.org/repos/asf/cxf/tree/58b379bd
Diff: http://git-wip-us.apache.org/repos/asf/cxf/diff/58b379bd

Branch: refs/heads/master
Commit: 58b379bdf8cce2434f6033e2d7adab944afff05b
Parents: 59436ea
Author: Sergey Beryozkin <sb...@gmail.com>
Authored: Wed Dec 7 15:59:50 2016 +0000
Committer: Sergey Beryozkin <sb...@gmail.com>
Committed: Wed Dec 7 15:59:50 2016 +0000

----------------------------------------------------------------------
 .../org/apache/cxf/annotations/UseNioWrite.java | 38 ++++++++++++++++++++
 1 file changed, 38 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cxf/blob/58b379bd/core/src/main/java/org/apache/cxf/annotations/UseNioWrite.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/cxf/annotations/UseNioWrite.java b/core/src/main/java/org/apache/cxf/annotations/UseNioWrite.java
new file mode 100644
index 0000000..a9c797d
--- /dev/null
+++ b/core/src/main/java/org/apache/cxf/annotations/UseNioWrite.java
@@ -0,0 +1,38 @@
+/**
+ * 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.cxf.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+/**
+ * Instructs the runtime to copy the input stream to the output stream using NIO.
+ * This annotation will have no effect if continuations are not available  
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.METHOD })
+@Inherited
+public @interface UseNioWrite {
+}
+