cxf-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From dk...@apache.org
Subject svn commit: r1310009 - in /cxf/trunk: api/src/main/java/org/apache/cxf/annotations/ api/src/main/java/org/apache/cxf/service/invoker/ rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/ systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/
Date Thu, 05 Apr 2012 18:53:13 GMT
Author: dkulp
Date: Thu Apr  5 18:53:12 2012
New Revision: 1310009

URL: http://svn.apache.org/viewvc?rev=1310009&view=rev
Log:
Introduce a new @UseAsyncMethod to allow selecting the usage of the
async variants on the server side when using JAX-WS.

Added:
    cxf/trunk/api/src/main/java/org/apache/cxf/annotations/UseAsyncMethod.java   (with props)
    cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/ServerAsyncResponse.java
  (with props)
Modified:
    cxf/trunk/api/src/main/java/org/apache/cxf/service/invoker/AbstractInvoker.java
    cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/AbstractJAXWSMethodInvoker.java
    cxf/trunk/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/ClientServerTest.java
    cxf/trunk/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/Server.java

Added: cxf/trunk/api/src/main/java/org/apache/cxf/annotations/UseAsyncMethod.java
URL: http://svn.apache.org/viewvc/cxf/trunk/api/src/main/java/org/apache/cxf/annotations/UseAsyncMethod.java?rev=1310009&view=auto
==============================================================================
--- cxf/trunk/api/src/main/java/org/apache/cxf/annotations/UseAsyncMethod.java (added)
+++ cxf/trunk/api/src/main/java/org/apache/cxf/annotations/UseAsyncMethod.java Thu Apr  5
18:53:12 2012
@@ -0,0 +1,71 @@
+/**
+ * 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.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+/**
+ * Instructs the runtime to dispatch using the async method
+ * on service if continuations are available.  This only applies
+ * to the JAX-WS frontend at this time.
+ * 
+ * Instead of calling the "X methodName(Y, Z...) method, it will
+ * call the "Future<?> methodName(Y, Z, ... AsyncHandler<MethodResponse>)"
+ * method passing in an AsyncHandler that you will need to call when
+ * the response is ready.   An example would be:
+ * 
+ * <pre>
+ * public Future<?> greetMeAsync(final String requestType,
+ *                               final AsyncHandler<GreetMeResponse> asyncHandler)
{
+ *     final ServerAsyncResponse<GreetMeResponse> r = new ServerAsyncResponse<GreetMeResponse>();
+ *     new Thread() {
+ *         public void run() {
+ *            //do some work on a backgound thread to generate the response...
+ *            GreetMeResponse resp = new GreetMeResponse();
+ *            resp.setResponseType("Hello " + requestType);
+ *            r.set(resp);
+ *            asyncHandler.handleResponse(r);                    
+ *         }
+ *    } .start();
+ *    return r;
+ * }
+ * </pre>
+ * 
+ * The use of the org.apache.cxf.jaxws.ServerAsyncResponse class for the response
+ * as shown above can simplify things and is recommended.
+ */
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ ElementType.METHOD })
+public @interface UseAsyncMethod {
+    
+    /**
+     * By default, if continuations are not available, 
+     * it will use the non-async method.  If you ALWAYS 
+     * want the async method called, set this to true.  However,
+     * that can cause threads to block.
+     * @return
+     */
+    boolean always() default false;
+}
+

Propchange: cxf/trunk/api/src/main/java/org/apache/cxf/annotations/UseAsyncMethod.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/api/src/main/java/org/apache/cxf/annotations/UseAsyncMethod.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: cxf/trunk/api/src/main/java/org/apache/cxf/service/invoker/AbstractInvoker.java
URL: http://svn.apache.org/viewvc/cxf/trunk/api/src/main/java/org/apache/cxf/service/invoker/AbstractInvoker.java?rev=1310009&r1=1310008&r2=1310009&view=diff
==============================================================================
--- cxf/trunk/api/src/main/java/org/apache/cxf/service/invoker/AbstractInvoker.java (original)
+++ cxf/trunk/api/src/main/java/org/apache/cxf/service/invoker/AbstractInvoker.java Thu Apr
 5 18:53:12 2012
@@ -59,11 +59,6 @@ public abstract class AbstractInvoker im
                 throw new Fault(new Message("EXCEPTION_INVOKING_OBJECT", LOG, 
                                              "No binding operation info", "unknown method",
"unknown"));
             }
-            
-            
-            //Method m = (Method)bop.getOperationInfo().getProperty(Method.class.getName());
-            m = matchMethod(m, serviceObject);
-            
             List<Object> params = null;
             if (o instanceof List) {
                 params = CastUtils.cast((List<?>)o);
@@ -71,12 +66,25 @@ public abstract class AbstractInvoker im
                 params = new MessageContentsList(o);
             }
             
+            m = adjustMethodAndParams(m, exchange, params);
+            
+            //Method m = (Method)bop.getOperationInfo().getProperty(Method.class.getName());
+            m = matchMethod(m, serviceObject);
+            
+            
             return invoke(exchange, serviceObject, m, params);
         } finally {
             releaseServiceObject(exchange, serviceObject);
         }
     }
 
+    protected Method adjustMethodAndParams(Method m,
+                                           Exchange ex,
+                                           List<Object> params) {
+        //nothing to do
+        return m;
+    }
+
     protected Object invoke(Exchange exchange, final Object serviceObject, Method m, List<Object>
params) {
         Object res;
         try {

Modified: cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/AbstractJAXWSMethodInvoker.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/AbstractJAXWSMethodInvoker.java?rev=1310009&r1=1310008&r2=1310009&view=diff
==============================================================================
--- cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/AbstractJAXWSMethodInvoker.java
(original)
+++ cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/AbstractJAXWSMethodInvoker.java
Thu Apr  5 18:53:12 2012
@@ -28,13 +28,18 @@ import java.util.List;
 import java.util.Map;
 
 import javax.activation.DataHandler;
+import javax.xml.ws.AsyncHandler;
+import javax.xml.ws.Response;
 import javax.xml.ws.handler.MessageContext;
 import javax.xml.ws.handler.MessageContext.Scope;
 import javax.xml.ws.soap.SOAPFaultException;
 
+import org.apache.cxf.annotations.UseAsyncMethod;
 import org.apache.cxf.attachment.AttachmentImpl;
 import org.apache.cxf.binding.soap.SoapFault;
 import org.apache.cxf.binding.soap.SoapMessage;
+import org.apache.cxf.continuations.Continuation;
+import org.apache.cxf.continuations.ContinuationProvider;
 import org.apache.cxf.endpoint.Endpoint;
 import org.apache.cxf.headers.Header;
 import org.apache.cxf.helpers.CastUtils;
@@ -43,12 +48,15 @@ import org.apache.cxf.jaxws.context.Wrap
 import org.apache.cxf.message.Attachment;
 import org.apache.cxf.message.Exchange;
 import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageContentsList;
 import org.apache.cxf.message.MessageImpl;
 import org.apache.cxf.service.invoker.Factory;
 import org.apache.cxf.service.invoker.FactoryInvoker;
 import org.apache.cxf.service.invoker.SingletonFactory;
+import org.apache.cxf.service.model.BindingOperationInfo;
 
 public abstract class AbstractJAXWSMethodInvoker extends FactoryInvoker {
+    private static final String ASYNC_METHOD = "org.apache.cxf.jaxws.async.method";
 
     public AbstractJAXWSMethodInvoker(final Object bean) {
         super(new SingletonFactory(bean));
@@ -67,6 +75,111 @@ public abstract class AbstractJAXWSMetho
         }
         return null;
     }
+    protected Method adjustMethodAndParams(Method m, Exchange ex, List<Object> params)
{
+        
+        UseAsyncMethod uam = m.getAnnotation(UseAsyncMethod.class);
+        if (uam != null) {
+            BindingOperationInfo bop = ex.getBindingOperationInfo();
+            Method ret = bop.getProperty(ASYNC_METHOD, Method.class);
+            if (ret == null) {
+                Class<?> ptypes[] = new Class<?>[m.getParameterTypes().length
+ 1];
+                System.arraycopy(m.getParameterTypes(), 0, ptypes, 0, m.getParameterTypes().length);
+                ptypes[m.getParameterTypes().length] = AsyncHandler.class;
+                try {
+                    ret = m.getDeclaringClass().getMethod(m.getName() + "Async", ptypes);
+                    bop.setProperty(ASYNC_METHOD, ret);
+                } catch (Throwable t) {
+                    //ignore
+                }
+            }
+            if (ret != null) {
+                JaxwsServerHandler h = ex.get(JaxwsServerHandler.class);
+                if (h != null) {
+                    return ret; 
+                }
+                ContinuationProvider cp = ex.getInMessage().get(ContinuationProvider.class);
+                if (cp == null && uam.always()) {
+                    JaxwsServerHandler handler = new JaxwsServerHandler(null);
+                    ex.put(JaxwsServerHandler.class, handler);
+                    params.add(handler);
+                    return ret;
+                } else if (cp != null && cp.getContinuation() != null) {
+                    final Continuation c = cp.getContinuation();
+                    c.suspend(0);
+                    JaxwsServerHandler handler = new JaxwsServerHandler(c);
+                    ex.put(JaxwsServerHandler.class, handler);
+                    params.add(handler);
+                    return ret;
+                }
+            }
+        }
+        return m;
+    }
+    
+    class JaxwsServerHandler implements AsyncHandler<Object> {
+        Response<Object> r;
+        Continuation continuation;
+        boolean done;
+        
+        public JaxwsServerHandler(Continuation c) {
+            continuation = c;
+        }
+        
+        public synchronized void handleResponse(Response<Object> res) {
+            r = res;
+            done = true;
+            if (continuation != null) {
+                continuation.resume();
+            }
+            notifyAll();
+        }
+        public boolean hasContinuation() {
+            return continuation != null;
+        }
+        public synchronized void waitForDone() {
+            while (!done) {
+                try {
+                    wait();
+                } catch (InterruptedException e) {
+                    //ignore
+                }
+            }
+        }
+        public boolean isDone() {
+            return done;
+        }
+        public Object getObject() {
+            try {
+                return r.get();
+            } catch (Exception ex) {
+                throw new Fault(ex);
+            }
+        }
+    }
+    
+    @Override
+    protected Object invoke(Exchange exchange, 
+                            final Object serviceObject, Method m,
+                            List<Object> params) {
+        JaxwsServerHandler h = exchange.get(JaxwsServerHandler.class);
+        if (h != null && h.isDone()) {
+            BindingOperationInfo bop = exchange.getBindingOperationInfo();
+            if (bop.isUnwrapped()) {
+                exchange.put(BindingOperationInfo.class, bop.getWrappedOperation());
+            }
+            return new MessageContentsList(h.getObject());
+        }
+        Object o = super.invoke(exchange, serviceObject, m, params);
+        if (h != null && !h.hasContinuation()) {
+            h.waitForDone();
+            BindingOperationInfo bop = exchange.getBindingOperationInfo();
+            if (bop.isUnwrapped()) {
+                exchange.put(BindingOperationInfo.class, bop.getWrappedOperation());
+            }
+            return new MessageContentsList(h.getObject());
+        }
+        return o;
+    }
     
     @Override
     protected Fault createFault(Throwable ex, Method m, List<Object> params, boolean
checked) {

Added: cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/ServerAsyncResponse.java
URL: http://svn.apache.org/viewvc/cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/ServerAsyncResponse.java?rev=1310009&view=auto
==============================================================================
--- cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/ServerAsyncResponse.java
(added)
+++ cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/ServerAsyncResponse.java
Thu Apr  5 18:53:12 2012
@@ -0,0 +1,67 @@
+/**
+ * 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.jaxws;
+
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * 
+ */
+public class ServerAsyncResponse<T> implements javax.xml.ws.Response<T> {
+    T value;
+    boolean done;
+    
+    /**
+     * Currently unused
+     */
+    public boolean cancel(boolean mayInterruptIfRunning) {
+        return false;
+    }
+    /**
+     * Currently unused
+     */
+    public boolean isCancelled() {
+        return false;
+    }
+    public boolean isDone() {
+        return done;
+    }
+    public void set(T t) {
+        value = t;
+        done = true;
+    }
+    public T get() throws InterruptedException, ExecutionException {
+        return value;
+    }
+    public T get(long timeout, TimeUnit unit) 
+        throws InterruptedException, ExecutionException, TimeoutException {
+        return value;
+    }
+    
+    /**
+     * Currently unused
+     */
+    public Map<String, Object> getContext() {
+        return null;
+    }
+}

Propchange: cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/ServerAsyncResponse.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: cxf/trunk/rt/frontend/jaxws/src/main/java/org/apache/cxf/jaxws/ServerAsyncResponse.java
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: cxf/trunk/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/ClientServerTest.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/ClientServerTest.java?rev=1310009&r1=1310008&r2=1310009&view=diff
==============================================================================
--- cxf/trunk/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/ClientServerTest.java
(original)
+++ cxf/trunk/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/ClientServerTest.java
Thu Apr  5 18:53:12 2012
@@ -1025,5 +1025,15 @@ public class ClientServerTest extends Ab
         InputStream ins = url.openStream();
         ins.close();
     }
-    
+
+    @Test
+    public void testServerAsync() throws Exception {
+        Service service = Service.create(serviceName);
+        service.addPort(fakePortName, javax.xml.ws.soap.SOAPBinding.SOAP11HTTP_BINDING, 
+            "http://localhost:" + PORT + "/SoapContext/AsyncSoapPort");
+        Greeter greeter = service.getPort(fakePortName, Greeter.class);
+        String resp = greeter.greetMe("World");
+        assertEquals("Hello World", resp);
+    }
+
 }

Modified: cxf/trunk/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/Server.java
URL: http://svn.apache.org/viewvc/cxf/trunk/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/Server.java?rev=1310009&r1=1310008&r2=1310009&view=diff
==============================================================================
--- cxf/trunk/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/Server.java (original)
+++ cxf/trunk/systests/jaxws/src/test/java/org/apache/cxf/systest/jaxws/Server.java Thu Apr
 5 18:53:12 2012
@@ -20,15 +20,20 @@
 package org.apache.cxf.systest.jaxws;
 
 import java.net.URL;
+import java.util.concurrent.Future;
 
 import javax.jws.WebService;
+import javax.xml.ws.AsyncHandler;
 import javax.xml.ws.Endpoint;
 
+import org.apache.cxf.annotations.UseAsyncMethod;
 import org.apache.cxf.jaxws.EndpointImpl;
+import org.apache.cxf.jaxws.ServerAsyncResponse;
 import org.apache.cxf.testutil.common.AbstractBusTestServerBase;
 import org.apache.hello_world_soap_http.BaseGreeterImpl;
 import org.apache.hello_world_soap_http.DocLitBareGreeterImpl;
 import org.apache.hello_world_soap_http.GreeterImpl;
+import org.apache.hello_world_soap_http.types.GreetMeResponse;
 
 public class Server extends AbstractBusTestServerBase {
     static final String PORT = allocatePort(Server.class);
@@ -42,6 +47,11 @@ public class Server extends AbstractBusT
         }
         Object implementor;
         String address;
+
+        implementor = new AsyncGreeter();
+        address = "http://localhost:" + PORT + "/SoapContext/AsyncSoapPort";
+        Endpoint.publish(address, implementor);
+        
         implementor = new GreeterImplMultiPort();
         address = "http://localhost:" + PORT + "/MultiPort/GreeterPort";
         Endpoint.publish(address, implementor);
@@ -53,7 +63,7 @@ public class Server extends AbstractBusT
         implementor = new GreeterImpl();
         address = "http://localhost:" + PORT + "/SoapContext/SoapPort";
         Endpoint.publish(address, implementor);
-        
+
         implementor = new RefGreeterImpl();
         address = "http://localhost:" + PORT + "/SoapContext/SoapPort2";
         Endpoint.publish(address, implementor);
@@ -79,9 +89,38 @@ public class Server extends AbstractBusT
     @WebService(endpointInterface = "org.apache.hello_world_soap_http.Greeter",
                 targetNamespace = "http://apache.org/hello_world_soap_http")
     public class Greeter12Impl extends BaseGreeterImpl {
+
     }
     
-    
+    @WebService(endpointInterface = "org.apache.hello_world_soap_http.Greeter",
+        targetNamespace = "http://apache.org/hello_world_soap_http")
+    public class AsyncGreeter extends BaseGreeterImpl {
+
+        @UseAsyncMethod
+        public String greetMe(String me) {
+            throw new RuntimeException("Should be async");
+        }
+
+        public Future<?> greetMeAsync(final String requestType,
+                                      final AsyncHandler<GreetMeResponse> asyncHandler)
{
+            final ServerAsyncResponse<GreetMeResponse> r = new ServerAsyncResponse<GreetMeResponse>();
+            new Thread() {
+                public void run() {
+                    try {
+                        Thread.sleep(500);
+                    } catch (InterruptedException e) {
+                        //ignore
+                    }
+                    GreetMeResponse resp = new GreetMeResponse();
+                    resp.setResponseType("Hello " + requestType);
+                    r.set(resp);
+                    asyncHandler.handleResponse(r);                    
+                }
+            } .start();
+            return r;
+        }
+    }
+
     public static void main(String[] args) {
         try {
             Server s = new Server();



Mime
View raw message