Eron Hennessey from Amazon has responded below with a new updated Java SDK that’s much easier to grok. The title of this article has since been changed accordingly.
We recently had a use case that was a perfect for the Amazon Simple Workflow Service (SWF).
In the end it was quite simple to implement. I simply read the C# SWF Hello World example and implemented that in Java.
The actual Java example is a nightmare. The following is not a rant about Java, Design Patterns or Aspect Oriented programming. I actually don’t mind any of those. It’s a rant about a Hello World example that requires hours to even setup and comprehend and in the end abstracts the whole point of the exercise away.
The fucking ridiculous HelloWorld example
Let me show you why i do not like to use the Java examples and why in general the AWS documentation is complete shit.
Let me introduce you to the SWF Hello World Java example. It has a few prerequisites.
Setting up the Framework with the Toolkit for Eclipse
I’m in a huge project that uses IntelliJ and this example is for Eclipse specifically. Oh well I’ll install Eclipse just for this example.
Couple of plug ins. No problem.
Now we need to enable annotation processing. Hmmm i wonder if that’s really required for a simple HelloWorld example. Oh well lets go ahead and do that.
Enabling and Configuring AspectJ
Wait a minute. Is this really required for a HelloWorld example?
Oh well lets go through that subsection and get this done.
First it says to download AspectJ for your Java version here. Ok done.
Now it says we need to enable AspectJ by setting our preferences to use AspectWeaver.jar
Now it says to create a META-INF folder in your project and place an aop.xml file with the following contents in it…
XML file editing… In a HelloWorld example application… Hmmm
In the Available Software dialog box, enter http://download.eclipse.org/tools/ajdt/
version/update, whereversion represents your Eclipse version number. For example, if you are using Eclipse 4.3 (Kepler), you would enter: http://download.eclipse.org/tools/ajdt/43/update
And we install 3 more Eclipse plugins. I wonder how well i’ll go when i implement this in our actual IntelliJ project since it uses a lot of Eclipse specific plug-ins?
Add some more AspectJ JARs to your classpath.
Editing of that aop.xml to specifically include components from this HelloWorld example.
Wait a minute did i just complete a tutorial on setting up Aspect Oriented Programming?
Well it seems i now know how to setup an Aspect Oriented Programming (AOP) project along with all the various plugins and helpers. That’s a strange thing when all i wanted was a HelloWorld tutorial for Amazon SWF. Alright well it’s now done, back to it i guess…
Create GreeterActivities interface. Hmm i actually have no problem with using various design patterns. But this is a HelloWorld sample. Can’t we just get to the meat of it?
Create the sole implementation of the above interface. If it’s only ever implemented once perhaps the interface wasn’t required?
A workflow interface. I’m wonder how long it’ll be till i get to the meat of the application.
The workflow implementation of the above interface.
The HelloWorld workflow starter.
No actual meat here. This code doesn’t directly call the AWS SDK. This whole exercise was just a confusing introduction for workflows and a prerequisite for what comes next.
The HelloWorldWorkflow. It now builds on the above to actually talk to AWS. Here’s a handy diagram Amazon has provided to help us understand our code. Most HelloWorld examples don’t require diagrams explaining how the interfaces and implementations of various classes interact but this one sure as hell does.
Got all that? OK lets continue.
The activities worker.
Personal preference here – I believe in a HelloWorld tutorial hiding things behind annotations isn’t such a good idea. Sure annotations are great once you understand what they’re doing to the code behind but for now in a tutorial where i want to learn they’re not so great.
The workflow worker.
Hmm more unexplained annotations. Remember i want to learn how AWS SWF works behind the scenes. Annotations might be a nice shortcut but i really need to see the meat of the application. How exactly is anything pushed to or pulled from the SWF queue? This tutorial skips that part.
The implementation of the above interface.
So far all I’ve ever seen is variables passed around. Where’s the goddamn meat of the application?
A few more paragraphs to read about the program structure so far.
HelloWorldWorkflow Workflow and Activities Implementation. Yes that’s the title of this section. Man i have a headache right now…
Ok this apparently processes our workflow. You’ll note this is the first time we’ve directly used the AWS SDK stuff in code. Although even here it’s just to setup our login details. So far any actual SWF functionality has been hidden behind layers of annotations. Even now it’s not clear how everything is taking items off the workflow queue and processing them.
Similar to the above. Still not sure of the exact call made behind the scenes in the AWS SDK.
GreeterMain creates an
AmazonSimpleWorkflowClient object by using the same code as
GreeterWorker. It then creates a
GreeterWorkflowClientExternal object, which acts as a proxy for the workflow in much the same way that the activities client created in
GreeterWorkflowClientImpl acts as a proxy for the activity methods. Rather than create a workflow client object by using
new, you must:
- Create an external client factory object and pass the
AmazonSimpleWorkflowClient object and Amazon SWF domain name to the constructor. The client factory object is created by the framework’s annotation processor, which creates the object name by simply appending “ClientExternalFactoryImpl” to the workflow interface name.
- Create an external client object by calling the factory object’s
getClient method, which creates the object name by appending “ClientExternal” to the workflow interface name. You can optionally pass
getClient a string which Amazon SWF will use to identify this instance of the workflow. Otherwise, Amazon SWF represents a workflow instance by using a generated GUID.
The client returned from the factory will only create workflows that are named with the string passed into the getClient method, (the client returned from the factory already has state in Amazon SWF). To run a workflow with a different id, you need to go back to the factory and create a new client with the different id specified.
Are you fucking serious?
I really don’t have anything against design patterns but i do think there’s a time and a place. What should be a fairly simple HelloWorld example is not the right place to go off the deep end like this.
And We’re Done… Apparantly
Wait a minute. At no point in that massive and confusing HelloWorld tutorial was there ever any actual code that pushes or pulls items off the workflow queue. The tutorial got so far up its ass that it actually forgot to teach us anything about the AWS SWF service.
Well at least i learnt a lot about AspectJ and aspect weaving
Namely that it’s tied down pretty hard to the Eclipse ecosystem (note the Eclipse only plug-ins above) and my current project is using IntelliJ. Also why the hell did i get taken down this path? I get that some people at Amazon might love Aspect Oriented Programming but there’s a time and a place to force your methodologies on others and go through the many steps to use those methodologies. HelloWorld examples that are meant to teach AWS usage are not the place for this crap.
The C# example is a better Java example than the Java example.
Amazon provides some straightforward C# sample applications. I’m not a C# developer but I’ve found them to be the best resource for how to do things in AWS using Java. Simply install the AWS SDK for .Net and create the sample application.
In that sample you’ll see pushing work to the SWF workflow queue is as simple as setting up a StartWorkflowExecutionRequest object with any data you want and call
Pulling work from the workflow queue involves a decider which determines how the workflow is to be processed. You pull workflow items requiring a decision with the following
response = swfClient.PollForDecisionTask(request);
You can that take that decider object and check it’s history to determine if the activity has finished (so you can go ahead and mark it done in the database) or you can schedule an activity to be run for it.
On your workers you’ll be pulling activities off the queue with
PollForActivityTaskResponse response = swfClient.PollForActivityTask(request);
The PollForActivityTaskResponse will contain the data you passed in above and you can go ahead and do the task you wanted.
It’s a straightforward example with a lot of meaty parts that actually accomplish tasks. Those above lines are just as valid in Java as they are in C#. In fact the whole C# project only requires some trivial (if admittedly verbose) syntax changes if you want to use it in Java. It’s a pretty good example and i was able to grok it in minutes. The AWS Java SDK has all the same class and member names and works in exactly the same way as the AWS .Net SDK.
Seriously Amazon. Look at the C# example. Convert that to Java syntax. It’s quite clear. It doesn’t take any Eclipse only plug-ins. No Aspect Oriented Programming tutorials required. No XML editing. No factory methods or implementations in sight. It’s a straightforward meaty application. And it pretty much works as-is in Java.