Skip to content

americanexpress/middle-manager

Repository files navigation

Build Status

What is Middle Manager?

Like any good manager, it insulates you from unpleasant things. The goal is to help you migrate off of the com.ibm.websphere.asynchbeans.WorkManager API. It provides a WorkExecutor interface that's similar to IBM's WorkManager, but uses the niceties of Executor and friends like Future. The API is purposely similar, so porting should be straightforward.

We provide implementations of WorkExecutor that are backed by WorkManager or by java.util.concurrent.ExecutorService. This provides an easy path to removing the use of WorkManager: first target WorkExecutor's API and keep using the same WorkManager under the hood. Then, switch to using the ExecutorService-backed implementation when you're ready to completely sever any dependency on WorkManager.

It's compatible with Java 6 because if you're using WorkManager, you're probably using a pretty old system!

How do I use it?

Artifacts are available in JCenter.

Gradle:

compile 'io.aexp.concurrency.middle-manager:middle-manager-core:1.0.1'
compile 'io.aexp.concurrency.middle-manager:middle-manager-ibm:1.0.1'

Maven:

<dependency>
    <groupId>io.aexp.concurrency.middle-manager</groupId>
    <artifactId>middle-manager-core</artifactId>
    <version>1.0.1</version>
</dependency>
<dependency>
    <groupId>io.aexp.concurrency.middle-manager</groupId>
    <artifactId>middle-manager-ibm</artifactId>
    <version>1.0.1</version>
</dependency>

At a high level, these are the steps to use this library :

  • Add dependencies on io.aexp.concurrency.middle-manager:middle-manager-core and io.aexp.concurrency.middle-manager:middle-manager-ibm (see above).
  • Migrate implementations of Work to implement only Runnable. Work extends Runnable, so you can leave Work there for now if you want to use the same Work implementations in both old WorkManager code and new WorkExecutor code.
  • Wrap WorkManager instances with a WorkManagerWorkExecutor. Instead of casting WorkItem#getResult() to the original Work submitted to WorkManager#doWork(), you'll get a Future<T> where T is your Runnable implementation.
  • Remove any remaining implements Work -- simplify it to just implements Runnable. You can also remove the extra method implementations that Work requires that are now no longer needed.
  • Migrate usage of WorkManagerWorkExecutor to use ExecutorWorkExecutor instead.
  • Remove all code that created or otherwise accessed WorkManager instances since they're no longer used to power the WorkExecutors

When you no longer need the IBM implementation, remove the middle-manager-ibm dependency, as well as whatever dependency you were using to access WorkManager.

Integration will depend on how you're currently accessing your WorkManager objects. We, for instance, use logic like the below snippet to determine which WorkExecutor to use, but it's likely to be custom to your situation.

private static boolean shouldUseExecutorImpl() {
    // allow forcing either way via system property
    String type = System.getProperty("com.foo.bar.baz");
    if ("workmanager".equals(type)) {
        return false;
    }
    if ("executor".equals(type)) {
        return true;
    }

    // true if you appear to be on a grown-up computer; will be false on legacy deployment. This is handy for running tests, etc.
    String arch = System.getProperty("os.arch");
    return System.getProperty("java.version").startsWith("1.8.")
            && (arch.equals("amd64") || arch.equals("x86_64"));
}

Once you've figured out how you wish to handle getting an WorkExecutor instead of a WorkManager (e.g. you could load a WorkManager from JNDI or however you're doing that, but then wrap that in a WorkManagerWorkExecutor), you'll want to migrate code from looking like this:

WorkItem item = workManager.startWork(new FooTask());

// could also assemble an ArrayList and call WorkManager#join()
while (item.getStatus() != WorkEvent.WORK_COMPLETED) {
    Thread.sleep(1234);
}

// Only provides the ability to return the original Work as a means of expression completion
FooTask task = (FooTask) item.getResult();

// This usually means that the Work implementation writes to its own field, or something like that
String result = task.fieldThatWasWrittenToDuringExecution;

to this:

Future<FooTask> future = workExecutor.submit(new FooTask());

// no need to change the structure of FooTask and how it records its result
String result = future.get().fieldThatWasWrittenToDuringExecution;

Once you're that far, it's a small leap to making FooTask implement Callable<String>, and then you can get a Future<String> directly.

What is a WorkManager?

WorkManager, WorkItem, and friends form an old concurrency API from the early days of Java. It was originally intended to provide concurrency tools to webapps running inside an app server like WebSphere. There are actually several flavors of it: CommonJ, IBM, and even an attempt at standardization in Java EE. All three are similar, and while this project includes an implementation that can use an IBM WorkManager as the actual thread handling mechanism, it would be straightforward to also implement this on top of the CommonJ or Java EE 5 flavors. Since all three APIs are similar, this library is useful for migrating away from all three.

Building

If you want to build everything except the IBM subproject, add the middleManager.excludeIbmSubproject Gradle property to your build, as in:

./gradlew build -PmiddleManager.excludeIbmSubproject

Unfortunately, there isn't a publicly available source for the com.ibm.websphere.asynchbeans.* classes, so this project's IBM subproject will not build without some manual setup. In your WebSphere installation, there is probably an asynchbeans.jar file somewhere that has those classes in it. Drop that jar in the middle-manager-ibm/ext-jars dir within this project and gradle will find the classes it needs to build middle-manager. If you have a runtime jar, that may also contain the WorkManager classes.

Contributing

We welcome Your interest in the American Express Open Source Community on Github. Any Contributor to any Open Source Project managed by the American Express Open Source Community must accept and sign an Agreement indicating agreement to the terms below. Except for the rights granted in this Agreement to American Express and to recipients of software distributed by American Express, You reserve all right, title, and interest, if any, in and to Your Contributions. Please fill out the Agreement.

License

Any contributions made under this project will be governed by the Apache License 2.0.

Code of Conduct

This project adheres to the American Express Community Guidelines. By participating, you are expected to honor these guidelines.

About

An easy migration path away from the Java WorkManager concurrency API

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages