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.JarArchiver
please 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.xml
in 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
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. - Click OK.
- Save the
pom.xml
.
-
Open the
MeetingManager
class 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
ManagedScheduledExecutorService
injected:
@Resource
private ManagedScheduledExecutorService executor;
- This introduces a new class, the
ManagedScheduledExecutorService
, which is in thejavax.enterprise.concurrent
package:
import javax.enterprise.concurrent.ManagedScheduledExecutorService;
- 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 theschedule
method 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
Long
in the database but theget
method just returnsObject
. If we cast it to anumber
and then calllongValue
we get aLong
and will be resilient if the code later gets changed to add anInteger
instead:
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
TimeUnit
which is in the packagejava.util.concurrent
:
import java.util.concurrent.TimeUnit;
- 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 theid
variable in the enclosing method. To access theid
variable, it needs to be markedfinal
. So update the first variable declaration in thestartMeeting
method to be:
final String id = meeting.getString("id");
- Call the
schedule
method of the injectedManagedScheduledExecutorService
passing 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
run
method that you added above:
DBCollection coll = getColl();
- Next, get the
DBObject
representing 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.out
is good enough. At the end of therun
method, add:
System.out.println(id + " meeting ended");
- Save the file.
-
Open the
server.xm
l 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.0
as 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.xml
tab in the editor. -
Install the
concurrent-1.0
feature: search formongodb-2.0
and add another feature element but, this time, withconcurrent-1.0
mentioned. 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
install
goal to build and test the project: Right-click pom.xml in themeetings
project, click Run As… > Maven Build…, then in the Goals field typeinstall
and 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-server
and 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-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 insrc/main/liberty/config
won’t be picked up unless you add an include.
Part 4: MicroProfile Meeting Application - Using WebSockets and CDI events