Asynchronous it’s mean not Synchronous, ok it was a lame joke I’m sorry. When we’re talking about asynchronous it’s more like you’re delegate your work to another reliable man and don’t need to wait and supervise him, you can move to doing another task and when this man done with his work he will tell you. In technical explanation your work or in this case we call it task, was proceed on the different time table, it’s not depends with another task, and mostly was delegate into another thread. The simpler explanation between the different of asynchronous and synchronous.

Synchronous: you’re in queue to enter a parking lot which of course have ticketing system, you can’t get in before every car in front of you pick their ticket and then start to move in. This is also apply on queue behind you.

Asynchronous: you’re on your favorite coffee shop which is very popular and always full of people.You can order your favorite coffee on the same time with another customer and you don’t have to wait your coffee to be brewed and served before another customer order it’s done. The coffee shop workers will continuously take order, brew coffee and serving. People will get their coffee as soon as it’s ready.

Asynchronous with Java

Java was already support asynchronous programming with Future that represent pending result from asynchronous process and offers method get which is return the result of computation from asynchronous process. But, there was a little problem, get method will cause an blocking until the computation was done and it’s make the asynchronous in java was pointless.

Then, here comes the savior of asynchronous in Java 8, beside a hot stuff like Lambda Expression and Stream, Java 8 also shipped a cool stuff and the name is CompletableFuture. Not only implemented Future to perform asynchronous it’s also implements CompletionStage which is a promise, so with CompletableFuture you can attach a callback. For example the code for CompletableFuture is like this:

CompletableFuture.supplyAsync(this::sendMessage)

This CompletableFuture support multi-chaining callbacks and support lambdas and of course stream, but actually the one that I want to show you today not about this hot stuff rather than an old API but it’s still powerful and magnificent, it was Asynchronous annotations.

Events CDI

Events was one of the shiniest feature on CDI specifications which is straight forward implementation of Observer Design Pattern yet easy to understand. Events CDI add more decoupling to the Dependency Injection by allowing notification of unknown target at development time. Events allow beans to communicate without any compile-time dependency. One bean can define an event, another bean can fire the event, and yet another bean can handle the event. The beans can be in separate packages and even in separate tiers of the application. Bellow is example how to fire an events:

@Inject
Event<Person> event;

public void createPerson() {
    event.fire(new Person());
}

Then to observer an events you will have to add Observer annotations in an enable bean of your application.

public void listenPerson(@Observer Person person) {
    ...
}

However this CDI have some limitations, which is it can’t be ordered and it’s not asynchronous. Out of the box events are synchronous method.

Combine Asynchronous with Events CDI

I told you before beside hot stuff like CompletableFuture there is asynchronous annotations which is actually a Future. We can combine this with Events CDI to make it perform an asynchronous. So, let’s start write some code. You will build a simple application with upload file feature asynchronously. So, the user don’t need to wait until the file uploaded and it’s need to show a error message or success message as soon as the file was submit to be uploaded. This application will be build with Java EE 7 (JSF, CDI, EJB) and Wildfly Application Server.

Create Upload Page with JSF

You will use one of the most popular web component in JavaEE, Java Server Faces (JSF). In order to made JSF work properly first we need to configure the servlet in web.xml like this.

<?xml version="2.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
    <display-name>javaee example</display-name>

    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.xhtml</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>/faces/*</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.xhtml</welcome-file>
    </welcome-file-list>
</web-app>

Then you can create your index.html which consist of upload file form and submit button.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://xmlns.jcp.org/jsf/html"
      xmlns:ui="http://xmlns.jcp.org/jsf/facelets"
      xmlns:f="http://xmlns.jcp.org/jsf/core">
<f:view contentType="text/html" encoding="UTF-8">
    <h:head>
        <meta charset="utf-8"/>
        <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
        <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
        <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->

        <meta name="description" content=""/>
        <meta name="author" content=""/>

        <title>Asyncrhonous</title>
    </h:head>
    <h:body>
        <h2>Upload Files</h2>
        <h:form id="form" enctype="multipart/form-data">
            <table>
                <tr>
                    <td>
                        <h:outputLabel>Upload Files: </h:outputLabel>
                    </td>
                    <td>
                        <h:inputFile id="file" value="#{uploadBean.file}"></h:inputFile>
                    </td>
                </tr>
                <tr>
                    <td></td>
                    <td>
                        <h:commandButton value="Submit"
                                         action="#{uploadBean.submit}"></h:commandButton>
                    </td>
                </tr>
            </table>
        </h:form>
    </h:body>
</f:view>
</html>

Then don’t forget to create your ManagedBean class.

@Model
public class UploadBean {
    private Part file;

    public void submit() {
        // perform uploading files
    }

    public Part getFile() {
        return file;
    }

    public void setFile(Part file) {
        this.file = file;
    }
}

For uploading files, we can used Files and Copy interface, so in your submit method it will be like this.

private Part file;

public void submit() {
    String path = "../uploads/";
    try(InputStream input = this.file.getInputStream()) {
        String fileName = this.file.getSubmittedFileName();
        Files.copy(input, new File(path + fileName).toPath());
    } catch (IOException e) {
        e.printStackTrace();
    }
}

Create EJB Listener

The next steps was build a listener with Observer annotations, this class will listen when the events was fired. Don’t forget to add Asynchronous annotations in your method to make the Event CDI asynchronously and move the logic of uploading file from ManagedBean class into this listener class.

@Stateless
public class UploadListener {
    private static final String PATH = "../uploads/";

    @Asynchronous
    public void uploadFile(@Observes Part file) {
        try (InputStream input = file.getInputStream()) {
            TimeUnit.MILLISECONDS.sleep(50_000);
            checkDirectory();
            String fileName = PATH + file.getSubmittedFileName();
            Files.copy(input, new File(fileName).toPath());
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * Create the directory if not exists
     *
     * @throws IOException
     */
    private static void checkDirectory() throws IOException {
        Path path = Paths.get(PATH);
        if (!Files.exists(path)) {
            Files.createDirectory(path);
        }
    }

}

I made the file that uploaded will stored in Wildfly Application Server with folder name uploads. So, you can freely change where to store the file but I suggest to keep it on the same directory of the Application Server.

WILDFLY_HOME
|-- bin
|-- ...
|-- uploads (your file will be stored in here)
|-- ...

Next, you need to refactor your ManagedBean class to have an Events CDI. This will be responsible in fire the event into your Observable class.

@Inject
Event<Part> event;

public void submit() {
    event.fire(this.file);
}

Conclusion

Congratulations, you’re already build an asynchronous upload files with Events CDI. Actually you can use CompletableFuture as well, because Asynchronous annotations it’s just a Future and it’s already shipped on since Java EE 6, it’s a little bit old right? The main reason why I choose this method was because CompletableFuture is will be powerful if you’re combine it with lambdas, but in this case for uploading files it will be cumbersome because you need to catch many IO exception and it made your code a little bit hard to read. So, the full source code was on github and this time for you to explore many possibility to do Asynchronous with Java.

References: