search
how tos

Identity Gateway 7.0: Async Programming 101

Introduction

One new major feature introduced in ForgeRock Identity Gateway 7.0 is standalone deployment. This is in addition to deployment into web app containers such as Apache Tomcat. It is accompanied by a major shift in the underlying HTTP server framework. Instead of dispatching incoming requests to worker threads—as this happens with web app containers—a standalone Identity Gateway server dispatches requests onto a single worker thread, following the Event Driven Reactive pattern. This allows scaling the application to levels that cannot be attained with container-based applications, where thousands of concurrent requests means bloating the JVM with thousands of worker threads. If you are interested in learning more about the inner workings of this design pattern, you can find valuable information here.

This paradigm, however, has a major impact: no blocking call to external resources is permitted in custom code, as this will block the entire server! Instead, asynchronous programming should be adopted. Note that the advice is also applicable to web app container deployments, as this design pattern has shown to be more performant even in a threaded architecture. This article focuses on facilitating the shift from blocking to async calls programming with Identity Gateway and the Groovy language.

The ingredients for asynchronous programming

Closures

Identity Gateway is in control of orchestrating the IO exchanges while your script is in control of the payload, recipients, and the business logic. To achieve this, work is submitted to the underlying framework and control is returned back to the script when data is available.

In the Java and Groovy worlds, this is accomplished with closures, also known as blocks in other languages. Closures are Functions as First Class objects that embody references to a surrounding state, and where the inner function they define is accessed by an outer scope.

In human language, these are simply self-contained pieces of code that are submitted to a framework method, and are executed on specific conditions, such as data has been received, and where said data is passed to the closure for processing. Here is a very simplistic example, in the Groovy language:


// Underlying framework
def doSomeWork(payload, callMeBackLater) {
   submitPayloadForProcessingAsync { response ->
       // process the response
       json = ....
       ...
       callMeBackLater(json)
   }
}

...
// From the script
doSomeWork(input) { json ->
      // Process result
}

The doSomeWork function can be seen as the underlying framework method that submits the work to the underlying IO framework, and which hands back control to the caller once the data is available. In the Vert.x world, ultimately, the payload is transmitted to the IO library asynchronously, where actual response data is handled—reactively—from an event/select loop, which itself follows a functional design pattern. Let's talk next about handling back completion of work, with the introduction of Promises.

ForgeRock's building blocks

For ForgeRock's asynchronous library, it is all about Promises, known also as futures in the asynchronous programming jargon. This interface is defined here.

But before diving into the abysses of this Javadoc, let's step up a little bit. First, we talked about closures. Java before version 8 did not strictly have closures, but nonetheless, could achieve this feat with interfaces and anonymous classes. Java 8 since then introduced a functional language syntax that includes functional interfaces and lambda expressions.

Before Java 8, the Promise interface would have been realized by an anonymous class that injects actual code to execute:


Promise myPromise = methodThatReturnsAPromise()
.then(new Function() {
   public MyResult apply(MyInput input) throws SomeException {
        // Do some work
      .....
      return result;
   }
})
.thenAsync(new AsyncFunction() {
    Promise apply(MyResult result) throws SomeException {
       return someOtherWorkThatReturnsAPromise()
   }
});

So, here we instruct to first execute the non-blocking call, then on completion, to execute the first, then closure, and then execute the next thenAsync closure when the previous block completes. Since then()and thenAsync() returns a Promise, these can be chained one after the other.

Notice how the output is injected in the next asynchronous block. In the example above, MyResult corresponds to VOUT in the Javadoc specification, while MyInput corresponds to V in the then argument:


 Promise then​(Function onResult)

Where the Function interface defines the following method:


VOUT apply​(VIN value) throws E extends Exception

The AsyncFunction unary method is defined as:


Promise apply​(VIN value) throws E extends Exception

So, coming back to functional language practices, starting from Java 8, as we said, the language introduced functional interfaces and lambda expressions. At its simplest, functional interfaces are unary functions; though Java also defines Bi Functions. If you want to learn more about it, you can inspect the Java documentation here.

It turns out that the AsyncFunction and Function interfaces conform to the rule, so in our example, we can make use instead of lambda expressions:


Promise myPromise = methodThatReturnsAPromise()
.then { input ->
	 // Do some work
       .....
       return result;
    }
}
.thenAsync { result ->
	return someOtherWorkThatReturnsAPromise()
    }
};

Better, right?

By then, you might have noticed the difference between then(Function) and thenAsync(AsyncFunction) closures? The former returns a (non-Promise) object while the latter returns a Promise and thus submits yet another piece of work asynchronously.

The move to Groovy

Groovy is a dynamic type checking language; so basically, if you decide to, types will be checked at runtime only, and not at compile time. You also know that Generics in Java, e.g., syntax like someMethodxxx, yyy are checked only at compile time, and erased in the generated byte code. So, creating a Promise object in Groovy is as simple as:


def myPromise = methodThatReturnsAPromise()

Next, is the anonymous class syntax. Let's say you were to transcribe the first Java code snip not making use of lambda expressions; remember, the verbose version? In Groovy, this conversion is accomplished with a Map syntax, where keys are method names, and values are closures, and then the map is cast to the interface type with the Groovy cast operator as:



[
   apply: { result ->
      // Do some work
      return result;
   }
] as Function

Groovy, though, is able to infer the Java interface into a closure, and therefore, after simplifying, we end up with the same code as in Java {(except the ending ;)}:


def myPromise = methodThatReturnsAPromise()
.then { result ->
      // Do some work
      return result
}
.thenAsync { result ->
       // Perform some other async work
      return someOtherWorkThatReturnsAPromise()
}

So, having examined the path from the Javadoc specification to actual Groovy code, we should now be able to use these building blocks to write good practice code in our scripts.

Playing nicely with Identity Gateway

A sure way to make a blocking call is to invoke in a script, myPromise.get(), but we do not want that!

Instead, we want to pass the promise back to Identity Gateway's handler, which might add more asynchronous processing on the way, and finally, initiate the whole sequence. So, eventually, this code should be transformed into:


return methodThatReturnsAPromise()
.then { input ->
	 // Do some work
       .....
       return result;
    }
}
.thenAsync { result ->
	return someOtherWorkThatReturnsAPromise()
    }
}

The HTTP Client

The default HTTP Client is one of the concrete objects that handle promises. This object is passed into the scripts scope as http, and is the interface that should be imperatively used to invoke external resources with REST! So here is the proper pattern to invoke an external REST API asynchronously:



return http.send(myRequest).then { response ->
      // Process the response and then return the response
      return response
}
.thenAsync {
      // Pass control along the chain
      next.handle(context, request)
}

The Client Javadoc can be found here.

The big takeaway here is that nothing has happened yet when the script returns control back to the Identity Gateway framework with the return statement. Things happen when the http call is invoked asynchronously, and completes, then the framework invokes the code in the closures, one by one. Some of the inner closures submit back again some asynchronous work, controls return back to the framework, and again, a closure is invoked on completion. Neat!

With these building blocks in hand, let's now look at how you can transform legacy scripts using blocking calls to a la Async mode.

Migrating legacy code

Let's assume that scripts developed for an earlier Identity Gateway release are made of functions invoking blocking functions, intricate into a mesh of if-then-else blocks. This sounds like hardship. However, you can apply a migration strategy which will avoid a major refactoring effort.

Let's start with an example that shows two bad practices: using the Groovy rest client rather than the native Identity Gateway client—and thus missing benefits from a global configuration, and further making blocking calls—which both will hit performance issues. In the example below, the script queries an IDM server for the existence of a user, and if that user exists, checks again against the same server to determine whether the user has been blocked. If the user does not exist, it returns an error. If the user exists, but is blocked, then it also returns an error. And, if the user exists, and is not blocked, proceed to the route:


def getIDMUser(user) {
  try {
      def idmRest = new RESTClient()
      def response = idmRest.get(path: "http://idm:8080/openidm/managed/user",
                             Headers: [
                                'X-OpenIDM-Username': 'openidm-admin'
                                'X-OpenIDM-Password': 'password"'
                             ],                                       
                             query: [ 
                                 '_queryId' : 'for-userName'
                                 'uid' : user
                             ])
      return response.data

  } catch(Exception ex {
    // log the error
  }
}

def getBlockedList() {
  // Check in IDM metadata for blocked users...
  ... 
}


// For the purpose of simplicity, hard code the user name
def user = "John"
logger.info("User: " + user)

def json = getIDMUser(user)       
logger.info("IDM responded with result: " + json)
if (json.resultCount != 1) {
  def errorResponse = new Response(Status.FORBIDDEN)
  errorResponse.entity = JsonOutput.toJson(["error" : "unauthorized", "error_description" : "user is not authorized"])
  return errorResponse
} else {
   def blockedUsers = getBlockedList()
   logger.info("IDM - Blocked users: " + blockedUsers)
   if (blockedUsers.contains(user)) {
        def errorResponse = new Response(Status.FORBIDDEN)
        errorResponse.entity = JsonOutput.toJson(["error" : "unauthorized", "error_description" : "user has been blocked"])
       return errorResponse
}

return next.handle(context, request)

First, we need to transform the functions from blocking to asynchronous behavior, making them return a Promise so that we can preserve the if-then-else structure, and using the default http client:


def getIDMUserAsync(user) {
   def userRequest = new Request()
   userRequest.method = "GET"
   userRequest.uri = "http://idm:8080/openidm/managed/user"
   userRequest.uri.query = "_queryId=for-userName&uid=" + user
   userRequest.headers['X-OpenIDM-Username'] = "openidm-admin"
   userRequest.headers['X-OpenIDM-Password'] = "password"

   return http.send(userRequest)
       .then { response ->
           def json = response.entity.json
           // logger.info("IDM responded with: " + result)
           response.close()
           return json
       }
}
def getBlockedListAsync() {
   def listRequest = new Request()
   listRequest.method = "GET"
   listRequest.uri = "http://idm:8080/openidm/managed/blocked"
   listRequest.uri.query = "_queryFilter=true"
   listRequest.headers['X-OpenIDM-Username'] = "openidm-admin"
   listRequest.headers['X-OpenIDM-Password'] = "password"

   return http.send(listRequest)
       .then { response ->
           def json = response.entity.json
           // logger.info("IDM responded with: " + result)
           response.close()
           if (json.resultCount >= 1) {
               return json.result[0].blockedUsers
           }
           return []
       }
}

Then, calling the function is simply:


return getIDMUserAsync(user)
   .thenAsync { json ->       
       logger.info("IDM responded with result: " + json)
       if (json.resultCount != 1) {
           def errorResponse = new Response(Status.FORBIDDEN)
           errorResponse.entity = JsonOutput.toJson(["error" : "unauthorized", "error_description" : "user is not authorized"])
           return newPromise {
               errorResponse
           }
       }
       return next.handle(context, request)
   }

We use thenAsync because next.handle(context, request) returns a Promise. At the same time, in case of error, we need to return an error response, and that needs to be encapsulated into a Promise as well. This is accomplished by using:


Import static org.forgerock.util.promise.PromiseImpl.*
… 
newPromise { result }

This utility class is documented here. The next step is to insert the checking for blocked users. It's done by adding an else block, with another asynchronous call:



return getIDMUser(user)
   .thenAsync { json ->       
       logger.info("IDM responded with result: " + json)
       if (json.resultCount != 1) {
           def errorResponse = new Response(Status.FORBIDDEN)
           errorResponse.entity = JsonOutput.toJson(["error" : "unauthorized", "error_description" : "user is not authorized"])
           return Promises.newPromise {
               errorResponse
           }
       } else {
           return getBlockedListAsync()
           .thenAsync { users ->
               logger.info("IDM - Blocked users: " + users)
               if (users.contains(user)) {
                   def errorResponse = new Response(Status.FORBIDDEN)
                   errorResponse.entity = JsonOutput.toJson(["error" : "unauthorized", "error_description" : "user has been blocked"])
                   return newResultPromise(response)
               }
               return next.handle(context, request)
           }
       }
   }

You can see that the final script is architected (almost) in the same way, while it now follows an asynchronous pattern. Next, let's inspect another structuring style, while introducing the thenCatch directive, and the subtle differences between then and thenAsync.

Structuring alternatives

A closure can access variables declared in the scope of the script. So, we can leverage that by moving the error response to the script scope, and use predefined constant values:


def errorResponse
def FORBIDDEN_ERROR = new Response(Status.FORBIDDEN)
FORBIDDEN_ERROR.entity = JsonOutput.toJson(
  ["error" : "unauthorized", "error_description" : "user is not authorized"])
def BLOCKED_ERROR = new Response(Status.FORBIDDEN)
BLOCKED_ERROR.entity = JsonOutput.toJson(
  ["error" : "unauthorized", "error_description" : "user has been blocked"])
  

Then, to demonstrate the thenCatch instruction, let's throw an exception for unauthorized users. And let's use then instead of thenAsync, as there is no more asynchronous work in the closure. So the new code—blocked users are not tested yet—becomes:



return getIDMUser(user)
   .then { json ->       
       logger.info("IDM - responded with user details: " + json)
       if (json.resultCount != 1) {
           errorResponse = FORBIDDEN_ERROR
           throw new Exception("forbidden")
       }
       return json
   }
   .thenAsync {
       next.handle(context, request)
   }
   .thenCatch {
       return errorResponse
   }

In this example, the script is extracting the user name from the request URI path, such as https://localhost:8081/home.


def user, baseUrl
def pattern = Pattern.compile('^.+/(.+[^/])$')
def m = pattern.matcher(request.uri.path)
if (m.find()) {
  user = m.group(1)
}

There are two users defined in the IDM repository: john, who is in the blocked list, and peter, who is authorized. Any non-existing user is unauthorized. So, http://localhost:8081/home/peter is routing correctly to the protected application. While https://localhost:8081/home/unknown returns the response {"error":"unauthorized","error_description":"user is not authorized"}. So, all good so far.

However, for john, who is in the blocked list, the request is still routed to the application, so let's now add the logic for blocked users. This time, it has to be in a thenAsyncclosure, as the code involves asynchronous work, and therefore, returns a Promise:


return getIDMUser(user)
   .then { json ->       
       logger.info("IDM - responded with user details: " + json)
       if (json.resultCount != 1) {
           errorResponse = FORBIDDEN_ERROR
           throw new Exception("forbidden")
       }
       return json
   }
   .thenAsync {
       return getBlockedListAsync()
       .then { users ->
           logger.info("IDM - Blocked users: " + users)
           if (users.contains(user)) {
               errorResponse = BLOCKED_ERROR
               throw new Exception("blocked")
           }
           return users
       }
   }
   .thenAsync {
       next.handle(context, request)
   }
   .thenCatch {
       return errorResponse
   }

Yes, this time, https://localhost:8081/home/john sends back : {"error":"unauthorized","error_description":"user has been blocked"}.

Another step further

Have you noticed that the closures were returning a value, but this value is not used by the next closure? It does not have to be. We have to remember that Void is a valid type for the Function unary method return type, which means a Java function that does not return a value. With Groovy, by simply not including a return statement at the end of the closure, it means the closure return type is Void.

On the other hand, the AsyncFunction's unary method always returns a value of type Promise, however the Promise can hold Void type, in other words, nothing, which is done with newPromise { /* empty */ }or newResultPromise((Void)). So, here is an improved version:


return getIDMUser(user)
   .then { json ->       
       logger.info("IDM - responded with user details: " + json)
       if (json.resultCount != 1) {
           errorResponse = FORBIDDEN_ERROR
           throw new Exception("forbidden")
       }
       // Nothing to return
   }
   .thenAsync {
       return getBlockedListAsync()
       .then { users ->
           logger.info("IDM - Blocked users: " + users)
           if (users.contains(user)) {
               errorResponse = BLOCKED_ERROR
               throw Exception("blocked"))
           }
           // Nothing to return
       }
   }
   .thenAsync {
       next.handle(context, request)
   }
   .thenCatch {
       return errorResponse
   }
  .thenAsync {
      next.handle(context, request)
  }
  .thenCatch {
      return errorResponse
  }

This means that you can adopt different strategies when structuring the script code. Either forbid usage of script scope variables and use only local scope variables passed along the closure return values and passed parameters, or use only script scope, or a mix of those; each style has its own pros and cons.

The thenOnResult case

This directive is different from the others in that it does not take a Function or AsyncFunction interface argument, but a ResultHandler whose unary method is defined as:


void handleResult​(V result)

It does not return any value, and does not throw any exception; it just processes the result after completion of the promise. Where can it be used? A good example of this is transforming a response returned by the chain handler, like this:


… 
}
.thenAsync { result ->
      next.handle(context, request)
      .thenOnResult { response ->
          if (response.status == Status.OK) {
              response.entity = JsonOutput.toJson(["status" : "OK"])
          }
      }
  }
  .thenCatch {
      return errorResponse
  }

Now, instead of sending HTML content back to the user agent after hitting the protected application, it now sends back JSON.

The same trick can be used to transform the JSON errors into renderable HTML. That can be done by inserting a new Scriptable Filter upstream the chain (remember, Identity Gateway goes down the chain in processing the request, then goes back up for processing the response). This scriptable filter would just do:


next.handle(context, request)
   .thenOnResult { response ->
       if (response.status != Status.OK) {
          response.entity = ""
       }
   }

This approach has the benefit that if you change your mind for the response format, the script can be left intact, and it is just a matter of inserting a new filter for the response up the chain.

Reaffirming the verbs

So, let's recap the directives we have talked about so far:

If the registered closure on the Promise does not require further asynchronous processing (that is, no additional external REST invocation is required), use then to process a result (which can further throw an exception), and if the Promise encounters an exception, use thenCatch.

If further asynchronous processing is required, use the counterparts, thenAsync, thenCatchAsync, and return a promise.

An AsyncFunction method returns a Promise type, so either return the promise obtained from an inner async call, or a promise holding a value with the newPromise { value } directive or newResultPromise(value).

To throw an exception from a thenAsync or thenCatchAsync closure, use newExceptionPromise(exception). For the then or thenCatchclosures, simply throw the exception.

When then or thenAsync returns a value, it is available as a parameter on the next asynchronous block. A then closure can return nothing, in which case, there is no input parameter passed to the next closure. To return nothing in thenAsync closure, return a Promise holding no value.

Finally, use thenOnResult for processing a result when it can't fail (no exceptions) and no value needs to be returned. Simple, right?

Troubleshooting

Using the proper directive for Async work

At some point, I had this code, which was not behaving as expected. Requests with blocked users were still routed to the application. Can you spot the issue?



return getIDMUser(user)
   .then { json ->       
       logger.info("IDM - responded with user details: " + json)
       if (json.resultCount != 1) {
           errorResponse = FORBIDDEN_ERROR
           throw new Exception("forbidden")
       }
       return json
   }
  .then {
       return getBlockedListAsync()
       .then { users ->
           logger.info("IDM - Blocked users: " + users)
           if (users.contains(user)) {
               errorResponse = BLOCKED_ERROR
               throw new Exception("blocked") // That exception is lost
           }
           return users
       }
   }
   .thenAsync {
       next.handle(context, request)
   }
   .thenCatch {
       // THIS IS NOT CATCHING THE EXCEPTION FOR BLOCKED USERS
       return errorResponse
   }

See that above we are using then but returning a Promise, e.g., return getBlockedListAsync().then. From a pure syntax perspective, this is valid code. However, then is expecting a value, and is not expected to realize a returned promise, it is just passing the value on. This means that the parameter passed to the next closure is a promise!

This code below is working; however, it will become rapidly unmanageable, so the recommended way is to use thenAsync, and it is far simpler. So, this code sample is shown for demonstration only, but don't code like this!


return getBlockedListAsync()
       .then { users ->
           logger.info("IDM - Blocked users: " + users)
           if (users.contains(user)) {
               errorResponse = BLOCKED_ERROR
               throw new Exception("blocked") // That exception is lost
           }
           return users
       }
   }
   .thenAsync { promise ->
       return promise.thenCatch {
           logger.info("the exception is caught here")
           throw new Exception("blocked")
       }
   }
   .thenAsync {
       next.handle(context, request)
   }
   .thenCatch {
       return errorResponse
   }

Don't mess up script scope variables

This error had me scratching my head for a while. Suddenly, Identity Gateway was returning the result of the first call to Identity Management in the browser, even though I did not touch any of the asynchronous logic. Until I remembered that I shuffled a that REST call a little bit. Remember what we said before: a closure can access any variable in the script scope. This is true as well for functions. And here we go: I changed to use the variable request in the function with this code below, forgetting to change the variable name declaration:


def userRequest
request.uri = "http://idm:8080/openidm/managed/user"
… 
return http.send(request)
.then …  

So the request object (from the script scope) was modified (accidentally) by the function...no wonder next.handle(context, request) was indeed rerouting to Identity Management instead of the application. So, be careful not to override accidentally objects in global scope!

You might ask, why not response in the closures parameter, since response is also in the script scope? In this case, the response is declared as a parameter of the closure (and is a response from a previous closure), so referring to response is referring to the variable in the scope of the owner (which is the scope of the closure) versus this, which is the scope of the enclosing class (script). By default, closures access first the owner scope, unless the closure strategy is changed. There is actually another scope which is delegate, but this is another story, for which I am sure you'll find a lot of literature on the net. This is where Groovy closures are so much more powerful than Java lambdas, and make it so great to write DSLs!

Conclusion

Moving to asynchronous and functional programming can be daunting the first time, and I must say, that at the beginning it boiled by brain with pain. But as with everything, learning new ways is about getting used to, much the way that you learn a new foreign language. So, in the end, once you get a handle on it, it becomes easier and easier; the great benefit will be improved server performances and simpler deployment with a standalone deployment.