View Javadoc
1   /*
2    * JBoss, Home of Professional Open Source
3    * Copyright 2014, Red Hat, Inc. and/or its affiliates, and individual
4    * contributors by the @authors tag. See the copyright.txt in the
5    * distribution for a full listing of individual contributors.
6    *
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   * http://www.apache.org/licenses/LICENSE-2.0
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.jboss.as.quickstarts.ejb.asynchronous.client;
18  
19  import java.util.Collection;
20  import java.util.Date;
21  import java.util.Hashtable;
22  import java.util.concurrent.ExecutionException;
23  import java.util.concurrent.Future;
24  import java.util.concurrent.TimeUnit;
25  import java.util.concurrent.TimeoutException;
26  import java.util.logging.Logger;
27  
28  import javax.naming.Context;
29  import javax.naming.InitialContext;
30  import javax.naming.NamingException;
31  
32  import org.jboss.as.quickstarts.ejb.asynchronous.AsynchronousAccess;
33  import org.jboss.as.quickstarts.ejb.asynchronous.ParallelAccess;
34  
35  /**
36   * A client to call the SingletonService via EJB remoting (AS7.1 / EAP6) to demonstrate the behaviour of asynchronous invocations.
37   * 
38   * @author <a href="mailto:wfink@redhat.com">Wolf-Dieter Fink</a>
39   */
40  public class AsynchronousClient {
41      private static final Logger LOGGER = Logger.getLogger(AsynchronousClient.class.getName());
42      /**
43       * Proxy of the SLSB with asynchronous methods
44       */
45      private final AsynchronousAccess accessBean;
46      /**
47       * Proxy of the SLSB that uses asynchronous bean calls inside to parallelize internal actions.
48       */
49      private final ParallelAccess parallelBean;
50  
51      /**
52       * Constructor to prepare the client-context.<br/>
53       * There must be a jboss-ejb-client.properties file in the classpath to specify the server connection(s).
54       * 
55       * @throws NamingException
56       */
57      private AsynchronousClient() throws NamingException {
58          final Hashtable<String, String> jndiProperties = new Hashtable<String, String>();
59          jndiProperties.put(Context.URL_PKG_PREFIXES, "org.jboss.ejb.client.naming");
60          final Context context = new InitialContext(jndiProperties);
61          String lookupName = "ejb:/jboss-ejb-asynchronous-ejb/AsynchronousAccessBean!" + AsynchronousAccess.class.getName();
62          LOGGER.info("Lookup Bean >" + lookupName);
63          accessBean = (AsynchronousAccess) context.lookup(lookupName);
64          lookupName = "ejb:/jboss-ejb-asynchronous-ejb/ParallelAccessBean!" + ParallelAccess.class.getName();
65          LOGGER.info("Lookup Bean >" + lookupName);
66          parallelBean = (ParallelAccess) context.lookup(lookupName);
67      }
68  
69      /**
70       * Demonstrate a fire-and-forget call to an asynchronous bean.
71       * 
72       * @throws InterruptedException
73       */
74      private void fireAndForget() throws InterruptedException {
75          long sleepMillis = 15000;
76          accessBean.fireAndForget(sleepMillis);
77          LOGGER.info(String.format("The server log should contain a message at (about) %s, indicating that the call to the asynchronous bean completed.", new Date(new Date().getTime() + sleepMillis)));
78          // in AS7.1.1.Final there is a bug that an ERROR will be logged that the result can not be written
79          // it will be solved in a later version
80      }
81  
82      /**
83       * Demonstrate how to call an asynchronous EJB, and then perform another task whilst waiting for the result.
84       * If the result is not present after the timeout of get(<timeout>) the result will be ignored.
85       * 
86       * @throws TimeoutException Will be thrown if you change the timing
87       */
88      private void getResultAsync() throws InterruptedException, ExecutionException, TimeoutException {
89          Future<String> myResult = accessBean.longerRunning(200); // Start a call with a short duration
90          // simulate something
91          // wait below 200ms will force a timeout during get
92          Thread.sleep(400);
93          // If you handle the TimeoutException you are able to ignore the result
94          // WARNING: there might be an ERROR at server side that the result is not delivered
95          LOGGER.info("Got the async result as expected => " + myResult.get(1, TimeUnit.MILLISECONDS));
96      }
97  
98      /**
99       * Demonstrate how to call an asynchronous EJB and continue local work meanwhile. After finishing local work
100      * wait for the result of the server call.<br/>
101      * Remember that the call of Future.get() will have a remote roundtrip to the server.
102      */
103     private void waitForAsyncResult() throws InterruptedException, ExecutionException, TimeoutException {
104         Future<String> myResult = accessBean.longerRunning(1500); // Start a call with a short duration
105         // you might do something here
106         
107         // get() without a timeout will wait until the remote result is present.
108         LOGGER.info("Got the async result as expected after wait => " + myResult.get());
109     }
110 
111     /**
112      * Invoke a remote synchronous EJB method. The remote method uses asynchronous calls internally, to parallelize it's workload.
113      */
114     private void callAnEJBwithAsyncAccess() {
115         Collection<String> results = parallelBean.invokeAsyncParallel();
116         LOGGER.info("Results of the parallel (server) processing : " + results);
117     }
118 
119     /**
120      * Demonstrate how a EJB can call different annotated asynchronous methods within the same application.
121      */
122     private void waitForAnotherAsyncResult2() throws InterruptedException, ExecutionException, TimeoutException {
123         parallelBean.callInterfaceAnnotatedMethod();
124     }
125 
126     /**
127      * Demonstrate how to handle an Exception from an asynchronous call.
128      */
129     private void callAsyncWithFailure() throws InterruptedException {
130         Future<String> x;
131         try {
132             x = accessBean.failure(); // this method will return successfully, because the invocation will be successful!
133         } catch (IllegalAccessException e) {
134             throw new RuntimeException("Unexpected failure during start asynchronous execution!", e);
135         }
136         try {
137             x.get(); // this will not return successfully
138         } catch (ExecutionException e) {
139             // the IllegalAccessException is thrown by the bean method
140             if (e.getCause() instanceof IllegalAccessException) {
141                 // This is the expected behavior
142                 LOGGER.info("Catch the expected Exception of the asynchronous execution!");
143             } else if (e.getCause().getCause() instanceof IllegalAccessException) {
144                 // For releases < AS7.1.2 (EAP6.0.0) the Exception is covered by a second ExecutionException because of a bug 
145                 LOGGER.info("Catch the covered Exception of the asynchronous execution, you may be using a release <= AS7.1.2 or EAP6.0.0!");
146             } else {
147                 throw new RuntimeException("Unexpected ExecutionException during asynchronous call!", e);
148             }
149         }
150     }
151 
152     /**
153      * Call all the different asynchronous methods.
154      * 
155      * @param args no arguments needed
156      */
157     public static void main(String[] args) throws Exception {
158         AsynchronousClient client = new AsynchronousClient();
159 
160         client.fireAndForget();
161         client.getResultAsync();
162         client.waitForAsyncResult();
163 
164         client.callAsyncWithFailure();
165 
166         client.callAnEJBwithAsyncAccess();
167         client.waitForAnotherAsyncResult2();
168     }
169 
170 }