In this lab we will look at doing some asynchronous tasks in the application to perform background maintanance.
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.
Adapted from the blog post: Writing a simple MicroProfile application: Using Java EE concurrency
- Completed Part 2: MicroProfile Meeting Application - Adding persistance
- Eclipse IDE for Web Developers: Run the installer and select Eclipse IDE for Java EE developers. Note: these steps were tested on the 2018-09 version of Eclipse running on Linux and Liberty Developer Tools 18.0.0.3. Note: If you encounter an error message like
Could not initialize class org.codehaus.plexus.archiver.jar.JarArchiverplease see the Troubleshooting section. - IBM Liberty Developer Tools (WDT)
- Start Eclipse
- Launch the Eclipse Marketplace: Help -> Eclipse Marketplace
- Search for IBM Liberty Developer Tools, and click Install with the defaults configuration selected
- Git
- Install the IBM Cloud CLI
Run the following commands:
$ git clone https://github.com/IBM/microprofile-meeting-concurrency.git
- In Eclipse, switch to the Git perspective.
- Click Clone a Git repository from the Git Repositories view.
- Enter URI
https://github.com/IBM/microprofile-meeting-concurrency.git - Click Next, then click Next again accepting the defaults.
- From the Initial branch drop-down list, click master.
- Select Import all existing Eclipse projects after clone finishes, then click Finish.
- Switch to the Java EE perspective.
- The meetings project is automatically created in the Project Explorer view.
If you completed the previous labs 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 is not running there will be a lot of noise in the server logs.
To start writing code the Maven pom.xml needs to be updated to indicate the dependency on the Concurrency API for Java EE:
- Open the
pom.xmlin Eclipse. - In the editor, select the Dependencies tab.
- 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.
- Enter a groupdId of
javax.enterprise.concurrent. - Enter a artifactId of
javax.enterprise.concurrent-api. - Enter a version of
1.0. - From the
scopedrop-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. - Click OK.
- Save the
pom.xml.
-
Open the
MeetingManagerclass from: meetings > Java Resources > src/main/java > net.wasdev.samples.microProfile.meetings > MeetingManager.java. -
Just below the class definition, just after the DB definition, get a
ManagedScheduledExecutorServiceinjected:
@Resource
private ManagedScheduledExecutorService executor;- This introduces a new class, the
ManagedScheduledExecutorService, which is in thejavax.enterprise.concurrentpackage:
import javax.enterprise.concurrent.ManagedScheduledExecutorService;- Find the
startMeetingmethod. 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 theschedulemethod of the injectedManagedScheduledExecutorService, this requires a Runnable, a duration, and a time unit for the duration.
- First, let’s get the meeting duration from the database. It’ll be a
Longin the database but thegetmethod just returnsObject. If we cast it to anumberand then calllongValuewe get aLongand will be resilient if the code later gets changed to add anIntegerinstead:
long duration = ((Number)obj.get("duration")).longValue();- 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;- This introduces a new class
TimeUnitwhich is in the packagejava.util.concurrent:
import java.util.concurrent.TimeUnit;- In the next step you will add a
runmethod in which you will need to find the entry that needs to have the meeting removed. To do this we need access to theidvariable in the enclosing method. To access theidvariable, it needs to be markedfinal. So update the first variable declaration in thestartMeetingmethod to be:
final String id = meeting.getString("id");- Call the
schedulemethod of the injectedManagedScheduledExecutorServicepassing in an anonymous inner class of typeRunnable:
executor.schedule(new Runnable() {
@Override
public void run() {
// code will be added here
}
}, duration, unit);- As with all things involving the data model, the first thing to do is get the MongoDB collection. This code should go in the
runmethod that you added above:
DBCollection coll = getColl();- Next, get the
DBObjectrepresenting the meeting:
DBObject obj = coll.findOne(id);- Resetting the meeting URL is as simple as just removing the field:
obj.removeField("meetingURL");- Then it needs to be saved back to MongoDB:
coll.save(obj);- 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.outis good enough. At the end of therunmethod, add:
System.out.println(id + " meeting ended");- Save the file.
-
Open the
server.xml from src > main > liberty > config > server.xml. -
Find the feature manager element. It should look like this:
<featureManager>
<feature>mongodb-2.0</feature>
</featureManager>- Before the closing
</featureManager>element add a feature element with the featureconcurrent-1.0as the body.
<feature>concurrent-1.0</feature>- Save the file.
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:
-
Open the
pom.xml. -
Switch to the
pom.xmltab in the editor. -
Install the
concurrent-1.0feature: search formongodb-2.0and add another feature element but, this time, withconcurrent-1.0mentioned. After this change you should see this:
<features>
<feature>mongodb-2.0</feature>
<feature>concurrent-1.0</feature>
</features>- Save the file
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.
There are two ways to get the application running from within WDT:
- The first is to use Maven to build and run the project:
- Run the Maven
installgoal to build and test the project: Right-click pom.xml in themeetingsproject, click Run As… > Maven Build…, then in the Goals field typeinstalland click Run. The first time you run this goal, it might take a few minutes to download the Liberty dependencies. - Run a Maven build for the
liberty:start-server goal: Right-click pom.xml, click Run As… > Maven Build, then in the Goals field, typeliberty:start-serverand click Run. This starts the server in the background. - Open the application, which is available at
http://localhost:9080/meetings/. - To stop the server again, run the
liberty:stop-serverbuild goal.
- The second way is to right-click the
meetingsproject 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 insrc/main/liberty/configwon’t be picked up unless you add an include.
Part 4: MicroProfile Meeting Application - Using WebSockets and CDI events