In my last article on MicroProfile, Writing a simple MicroProfile application (2): Adding persistence, I went through the steps of adding persistence using a MongoDB database to a sample MicroProfile application. In this article I’ll look at doing some asynchronous tasks in the application to perform background maintanance.

The sample application solves a real problem that the Liberty development team had. The globally-distributed Liberty development team has a lot of online meetings using IBM Connections Cloud Meetings. IBM Connections Cloud provides meeting rooms to individual employees, which is a problem for team meetings if the person who initially set up the meeting room can’t make it (e.g. they were called into another meeting, are on vacation, or sick). The sample application provides a single URL for a meeting, which can then be ‘started’ by one person and everyone else gets redirected.

Until now, when a meeting is started, a link is stored to the e-meeting but never removed when the meeting ends. That means the next time a meeting gets run it will redirect everyone to the old meeting, which is clearly not right. You want to ensure that after the meeting ends the URL gets deactivated. In this article we will use the concurrency utilities for Java EE to achieve this.

The meeting application is available in GitHub. Each branch in the repository maps to an article. The starting point for the app for this article is branch part2. By the end of this article, your code should match the code in branch part3.

This article assumes you are using Eclipse and WebSphere Developer Tools (WDT). To install WDT, download and start Eclipse, then drag and drop
Drag to your running Eclipse workspace to install WebSphere Developer Tools
on to the toolbar to start the WDT installer.

Getting the source into Eclipse from GitHub

The files for this application are available in GitHub. To follow this article, you want to clone the repository, check out the part2 branch of the repository, and import the project into Eclipse. You can do this from the command line or directly from Eclipse.

From the command line

If you prefer to clone the Git repository from the command line:

  1. Run the following commands:
    git clone https://github.com/WASdev/sample.microprofile.meetingapp.git
    cd sample.microprofile.meetingapp
    git checkout part2
  2. In Eclipse, import the project as an existing project.

From Eclipse

If you prefer to clone the Git repository from Eclipse:

  1. In Eclipse, switch to the Git perspective.
  2. Click Clone a Git repository from the Git Repositories view.
  3. Enter URI https://github.com/WASdev/sample.microprofile.meetingapp.git
  4. Click Next, then click Next again accepting the defaults.
  5. From the Initial branch drop-down list, click part2.
  6. Select Import all existing Eclipse projects after clone finishes, then click Finish.
  7. Switch to the Java EE perspective.

The meetings project is automatically created in the Project Explorer view.

Installing MongoDB

If you completed the previous articles and installed MongoDB, make sure MongoDB is running. If you are starting fresh, make sure you install MongoDB. Depending on what platform you are on the installation instructions may be different. For this exercise you should get the community version of MongoDB from the mongoDB download-center.

Once installed you can run the MongoDB database daemon using:

mongod -dbpath <path to database>

The database needs to be running for the application to work. If it isn’t running there will be a lot of noise in the server logs.

Updating the application to compile against the Concurrency API for Java EE

To start writing code the Maven pom.xml needs to be updated to indicate the dependency on the Concurrency API for Java EE:

  1. Open the pom.xml in Eclipse.
  2. In the editor, select the Dependencies tab.
  3. On the Dependencies tab there are two sections, one for Dependencies and the other for Dependency Management. Just to the right of the Dependencies box there is an Add button. Click the Add button.
  4. Enter a groupdId of javax.enterprise.concurrent
  5. Enter a artifactId of javax.enterprise.concurrent-api
  6. Enter a version of 1.0
  7. From the scope drop-down list, select provided. This will allow the application to compile but will prevent the Maven WAR packager putting the API in the WAR file. Later, the build will be configured to make it available to the server.
  8. Click OK.
  9. Save the pom.xml.

Updating the meeting manager to end the meeting

  1. Open the MeetingManager class from: meetings > Java Resources > src/main/java > net.wasdev.samples.microProfile.meetings > MeetingManager.java
  2. Just below the class definition, just after the DB definition, get a ManagedScheduledExecutorService injected:
    	@Resource
    	private ManagedScheduledExecutorService executor;
    
  3. This introduces a new class, the ManagedScheduledExecutorService, which is in the javax.enterprise.concurrent package:
        import javax.enterprise.concurrent.ManagedScheduledExecutorService;
    
  4. Find the startMeeting method. This is where we will put the logic for ending the meeting. Place all the code at the very end of the method. The event will be scheduled to run, and a response isn’t required because we just need to ensure it happens later on. Multiple steps will take place before all compile errors will be gone. The code will call the schedule method of the injected ManagedScheduledExecutorService, this requires a Runnable, a duration, and a time unit for the duration.
    1. First, let’s get the meeting duration from the database. It’ll be a Long in the database but the get method just returns Object. If we cast it to a number and then call longValue we get a long and will be resilient if the code later gets changed to add an Integer instead:
              long duration = ((Number)obj.get("duration")).longValue();
      
    2. Next, we need to define a time unit. In reality, meeting durations are measured in minutes or hours. The correct code would be:
              TimeUnit unit = TimeUnit.MINUTES;
      

      but this would not be very useful for demo/sample purposes so instead add:

              TimeUnit unit = TimeUnit.SECONDS;
      
    3. This introduces a new class TimeUnit which is in the package java.util.concurrent:
          import java.util.concurrent.TimeUnit;
      
    4. In the next step you will add a run method in which you will need to find the entry that needs to have the meeting removed. To do this we need access to the id variable in the enclosing method. To access the id variable, it needs to be marked final. So update the first variable declaration in the startMeeting method to be:
              final String id = meeting.getString("id");
      
    5. Call the schedule method of the injected ManagedScheduledExecutorService passing in an anonymous inner class of type Runnable:
              executor.schedule(new Runnable() {
      			
                  @Override
                  public void run() {
                      // code will be added here
                  }
              }, duration, unit);
      
    6. As with all things involving the data model, the first thing to do is get the MongoDB collection. This code should go in the run method that you added above:
                      DBCollection coll = getColl();
      
    7. Next, get the DBObject representing the meeting:
                      DBObject obj = coll.findOne(id);
      
    8. Resetting the meeting URL is as simple as just removing the field:
                      obj.removeField("meetingURL");
      
    9. Then it needs to be saved back to MongoDB:
                      coll.save(obj);
      
    10. Everything is done but, since these things are asynchronous for debug purposes, it is a good idea to write something to the log. You could use a proper logging API but, in this case, System.out is good enough. At the end of the run method, add:
                      System.out.println(id + " meeting ended");
      
  5. Save the file.

Configuring Liberty to run the Concurrency Utilities for Java EE

  1. Open the server.xml from src > main > liberty > config > server.xml.
  2. Find the feature manager element. It should look like this:
        <featureManager>
            <feature>mongodb-2.0</feature>
        </featureManager>
    
  3. Before the closing </featureManager> element add a feature element with the feature concurrent-1.0 as the body.
            <feature>concurrent-1.0</feature>
    
  4. Save the file.

Ensuring the Concurrency Utilities for Java EE are available

The Concurrency Utilities for Java EE are not part of the Java EE Web profile, which means that if you are using that distribution of Liberty the feature won’t be available. The pom.xml generated by the Liberty app accelerator depends on the Java EE Web profile distribution, so you need to either install concurrent-1.0 from the Liberty Repository or pull in the larger Java EE Full platform distribution:

  1. Open the pom.xml.
  2. Switch to the pom.xml tab in the editor.
  3. Then take one of the following approaches:
    1. To switch to the Java EE Full platform distribution of Liberty search for wlp-webProfile7 and change it to wlp-javaee7. After this change you should see this:
                          <assemblyArtifact>
                              <groupId>com.ibm.websphere.appserver.runtime</groupId>
                              <artifactId>wlp-javaee7</artifactId>
                              <version>17.0.0.1</version>
                              <type>zip</type>
                          </assemblyArtifact>
      
    2. To download the just concurrent-1.0 feature, search for mongodb-2.0 and add another feature element but, this time, with concurrent-1.0 mentioned. After this change you should see this:
                                  <features>
                                      <acceptLicense>true</acceptLicense>
                                      <feature>mongodb-2.0</feature>
                                      <feature>concurrent-1.0</feature>
                                  </features>
      
  4. Save the file

Some final thoughts

Those of you with eagle eyes will notice that there is a flaw in this logic: It isn’t very fault-tolerant. If I have a 90-minute meeting and the server crashes or restarts, the meeting will still never end. There are ways (he writes mysteriously) to solve this problem but that is an exercise for another day.

Running the application

There are two ways to get the application running from within WDT:

  • The first is to use Maven to build and run the project:
    1. Run the Maven install goal to build and test the project: Right-click pom.xml in the meetings project, click Run As… > Maven Build…, then in the Goals field type install and click Run. The first time you run this goal, it might take a few minutes to download the Liberty dependencies.
    2. Run a Maven build for the liberty:start-server goal: Right-click pom.xml, click Run As… > Maven Build, then in the Goals field, type liberty:start-server and click Run. This starts the server in the background.
    3. Open the application, which is available at http://localhost:9080/meetings/.
    4. To stop the server again, run the liberty:stop-server build goal.
  • The second way is to right-click the meetings project and select Run As… > Run on Server but there are a few things to note if you do this. WDT doesn’t automatically add the MicroProfile features as you would expect so you need to manually add those. Also, any changes to the configuration in src/main/liberty/config won’t be picked up unless you add an include.

Find out more about MicroProfile and WebSphere Liberty.

Related articles

Join The Discussion

Your email address will not be published. Required fields are marked *