To begin with, let us show you a small code snippet from one of our controllers. The saveSurveyResponse
method underneath gets called every time some user takes an in-site survey on a customer’s website.
/** * This method is invoked everytime someone takes a survey on a customer's website. * It performs two main tasks - * 1. saves the user's response in our database * 2. refreshes the stats and data graphs for the corresponding survey */ public ... saveSurveyResponse(...) throws IOException { //mundane code here to compute a response object "surveyResponseDto" //first save the response in database this.publisherBc.saveSurveyResponse(licenseCode, surveyResponseDto); //then, refresh all the analytics associated with this survey this.publisherBc.refreshSurveyStatusOnResponse(licenseCode, surveyId); }
As you can see above, the code performs two major tasks – #1. save the response in database and #2. refresh the analytics associated with the corresponding survey. We pre-compute a lot of data graphs
and collate the information to create a bunch of Maps
, so that the stats for our customers can be presented in real-time, in its true essence. That’s a lot of computing work. The method refreshSurveyStatusOnResponse
usually takes about half a second (and much more at times) to complete. We can’t keep the end user on a third party website waiting because (s)he took a simple survey and we got in to some crazy computing business!
Solution? Simple – make that method call asynchronous.
Yes, one would either use a batch process or make that call asynchronous. However, it is a much bigger problem to address. There are several such methods in any application stack which should be executed asynchronously to keep the user experience intact. E.g. in any action that needs to send out an email, the sending email part can easily be made asynchronous because SMTP
relays can be painful at times leading to huge lag; in the process, it keeps your end user waiting for a response.
Implementation? We created a cool Java annotation called Asynch
.
We first created an annotation interface called Asynch
and then implemented a method interceptor to look for this annotation on the callee
. If the annotation were present, we’d execute it further in a new thread. Snippet from the implementation below.
/** * Defining the Asynch interface */ @Retention(RetentionPolicy.RUNTIME) public @interface Asynch {} /** * Implementation of the Asynch interface. Every method in our controllers * goes through this interceptor. If the Asynch annotation is present, * this implementation invokes a new Thread to execute the method. Simple! */ public class AsynchInterceptor implements MethodInterceptor { public Object invoke(final MethodInvocation invocation) throws Throwable { Method method = invocation.getMethod(); Annotation[] declaredAnnotations = method.getDeclaredAnnotations(); if(declaredAnnotations != null && declaredAnnotations.length > 0) { for (Annotation annotation : declaredAnnotations) { if(annotation instanceof Asynch) { //start the requested task in a new thread and immediately //return back control to the caller new Thread(invocation.getMethod().getName()) { public void execute() { invocation.proceed(); } }.start(); return null; } } } return invocation.proceed(); } }
Done? Just that much?
Oh yes, pretty much. Here’s how the declaration of heavyweight method, refreshSurveyStatusOnResponse
, looks like –
/** * So, earlier we had a simple method in our interface which we later * annotated with the Asynch @interface. Bang! The caller doesn't need * to worry about it now. This method (no matter who the caller is) * gets executed asynchronously. Ain't that awesome? */ @Asynch public void refreshSurveyStatusOnResponse(String licenseCode, Integer surveyId);
How did we use annotations to build our security layer?
Now that we gave you a fair idea of how we are using Annotations
to our advantage, let’s dive a bit deeper. You are about to see how we built our entire Authorization
and Authentication
stacks using Java Annotation
.
We are security freaks. Be it the web layer or data exchange layer, access to all our code is protected. The caller
of a method is denied entry to the method if it does not have right privileges. Underneath is a small snippet from one of our web layer controllers. This method is invoked when someone tries to edit
a survey from the WebEngage dashboard.
/** * This is a public method invoked via a URL on the site. Once a user on the site * tries to reach this method, the "rules" specified below (via annotations) are * evaluated. If it matches with the criterion specified for the UserAuth class, * the user is allowed an entry into the method; otherwise is shown the exit door! * * In the specific example below, only "signed-in" users who are "authorized * publishers" (our terminology for WebEngage customers) AND have access to * "survey configuration" related features, are allowed entry into this method. */ @UserAuth ( userTypes = { UserType.SIGNED, UserType.AUTHORIZED_PUBLISHER }, publisherUserFeatures = { Feature.SURVEY_CONFIGURATION } ) public ... edit(...) throws IOException{ }
Pretty nice. Right? So just by annotating the edit
method with UserAuth
, we made sure that survey edit URL’s returns a sweet nothing to those who are not supposed to use those URL’s. Where’s the beauty? This piece of annotation is reusable; we use it in a variety of ways on pretty much all the code that needs to be protected behind the concepts of user
and their corresponding roles
.
Of-course there’s a lot of application specific code behind understanding the annotation UserAuth
. However, that’s one time and we have managed to reuse it in a much more sophisticated manner inside our Business Layer as well. Take a look at this usage in one of the methods below:
/** * This is our business component method for customers who intend to change * the styling of their surveys to match the CSS with their site's look and * feel [oh, we have a sexy CSS editor inside dashboard for them to do so ;)] * * This is a nested annotation. A list of @Authorize methods can be specified * as rules. Each of them specifying the method to be called (for authorization) * and the argument to be passed to it. For the caller to get access, these * values should meet the AuthRules criteria. If it does not, an * AuthorizationException is thrown. */ @AuthRules( authRules = { @Authorize( method = "hasPublisherUserFeatureAccess", sargs = {"$0", "SURVEY_STYLING"} ), @Authorize( method = "hasPublisherFeatureAccess", sargs = {"$0", "WE_SURVEY_CUSTOM_CSS"} ) } ) public void saveSurveyStyleCss( Integer publisherId, AdhocAttributeName cssAdhocAttributeName, String css ) throws AuthorizationException;
This explains how powerful annotations can get. At WebEngage, we use them to the fullest. Hope this article helps you build some cool stuff with attributes. Do let us know!
Note: Use the Asynch
annotation idea with care. Spawning new threads without being in control can be fatal. If you plan to use it, make sure the threads are fetched from a pre-created thread pool.
Stay tuned. We love you!
Pingback: Quora
For asynchronous programming you cold have used Future and Executors with a thread pool. Did you evaluate the same ? Any special reason to create special annotation and thread spawn ( even from a pool )?
The primary reason for using annotations was re-use. Look at the first code snippet in this article. See the second method call. We have many such methods. Now, imagine a redundant block of code snippet (to use an Executor) all over your codebase. Instead, with annotations, we could simply put an @Asynch annotation on all such method definition and the code gets invoked in a new thread no matter who the caller is.
Makes sense?
@Asynch
public “”void”” refreshSurveyStatusOnResponse(String licenseCode, Integer surveyId);
in current case method returns nothing AND you a new primitive thread spawned as follows,
//return back control to the caller
new Thread(invocation.getMethod().getName()) {
public void execute() {
invocation.proceed();
}
}.start();
// plain thread management could have been averted by using “newCachedThreadPool”
http://docs.oracle.com/javase/6/docs/api/java/util/concurrent/Executors.html#newCachedThreadPool%28%29
______________
AND what in case when you require to return something from a method ( not just fire and forget case like above with return type void ) how it is being dealt then ?
Having a return type for the caller of an async method – does that sound logical?
And the article does mention that we use a pool.
“Having a return type for the caller of an async method – does that sound logical?”
Yes very much !
Consider a real world and real time “multiple account summary” request from a net banking user who has multiple accounts in a single bank having legacy core banking system.
We have a web application in picture. You have to develop a Service layer asynchronous method which in turn will be called from Action class to get List of account details.
The async method we talk about is going to communicate to a TCP interface where you could query only one account at a time ( this is a constraint you can’t put multiple accounts in single request message as a payload, one account request->one summary response ).
Now there are two approaches spawn individual threads inside async method and return the list of account summaries OR make TCP call sequentially ! In both case you are doing IO heavy proportion and zero data processing ! But ultimately list has to be prepared and returned in action layer !
Pointers,
http://docs.oracle.com/javaee/6/tutorial/doc/gkkqg.html
“Retrieving the Final Result from an Asynchronous Method Invocation” 🙂
Sorry for reiterating the thread pool part.
Clever usage of annotations is good though ! 🙂
Suppose I need to upload a user image on ec2 bucket. On server side, i spawn a thread and upload the image. But there are rare cases when image upload can fail. In that case, there is no way to tell the user that image upload has failed? Is this the right use case for using another thread?
The best way to address such asynchronous processing is to have a “message queue based task queue” in between a web layer and your worker thread to upload stuff.
following article briefly explains the use cases.
http://bitmechanic.com/2011/12/30/reasons-to-use-message-queue.html
from a web layer request you get a file to upload, your pack it as a standard message and put it into an “upload” queue. A ( group of ) worker thread takes one message at a time tries to upload it to S3 Bucket.
When your upload fails you will have a “message id” to track with.
A better compendium of use cases.
http://stackoverflow.com/a/1035958/861454
@Rakesh,
You might have not faced any problem with Thread Executor but I have faced many problems while trying to build a thread manager.
1.)Thread manager gives you the facility of changing maximum pool size but if you decrease the pool size in run-time it doesn’t give the expected results and when i dig into it turned out that there is no implementation for decreasing the pool size in class provided by java.
2.)And even the FutureTask class is not upto the mark. You can’t even get the identity of the running task until it is finished(you can only get the returned object but after the execution).
So I ended up writing my own threadpoolexecuter and concluded that java threadpoolexecuter are good for nothing.