About TweetStream

In developing the
TweetStream demo for the JBoss World keynote and
JUDCon presentation, I wanted to use
CDI in a way that would choose the implementation of a given type at runtime. With Qualifiers and Producers,
CDI gives you the power to do this.
A little bit about the usecase: The
TweetStream application is an app that Jay Balunas and I developed over the past few months for our presentation at
JUDCon and JBoss World 2011. It was purposely developed with a myriad of JBoss community projects to showcase how you can build a mobile
HTML5 web application (which runs on Android and iOS devices) with things like scalable data grid,
JMS, JSF2,
HTML5/CSS3 and other middleware technologies. This application (TweetStream) was also chosen to be part of the literally incredible JBoss World 2011 keynote.
So, we had 2 scenarios – 1) for our presentation we needed a mobile app that could run solely on it’s own so that users could pull the
source code, see how we did things, and run it. 2) For the keynote, we had to make our app integrate with the Infinispan datagrid that was already setup as part of the keynote demo. The data stored on this grid utilized Drools and complex event processing as part of the keynote, so our app had to consume that data for that environment.
So we got our tweet data from the true source (twitter4j) during our
JUDCon presentation, and then from the data grid during the keynote. We could have used
CDI alternatives, but I wanted a true solution with no
XML configuration and runtime detection.
The Code...
So we have 2 Qualifier Types:
@TwitterLocal for the
JUDCon demo impl
@TwitterServer for the keynote impl
We used infinispan in both instances, but our @TwitterLocal is a single node caching a direct twitter stream from Twitter4J.
Now that we have our types defined as follows…
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface TwitterServer
{
}
@Qualifier
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER})
public @interface TwitterLocal
{
}
We need not only an implementation of each, but also a deciding bean that tells us which type to use.
First, our implementation of each Type implements an interface:
public interface TwitterSource {
public void init();
…
And our implementations have a different usage of the init method. TwitterLocal starts the stream coming from twitter and updates the infinispan cache. TwitterServer starts a method which allows us to start receiving data from the keynote which uses complex event processing and a datagrid with 6–8 nodes.
So now, how do we decide which Type to use? There are a few different ways to do it, but in the case of this being a demo and not a lot of time on my part. I used this approach:
public class TweetStream
{
@Inject
@
Any
Instance
<TwitterSource
> twitterSource
;
class TwitterLocalQualifier
extends AnnotationLiteral
<TwitterLocal
> implements TwitterLocal
{
}
class TwitterServerQualifier
extends AnnotationLiteral
<TwitterServer
> implements TwitterServer
{
}
boolean initialCheck
= true;
boolean demoexists
= false;
@PostConstruct
private void init
()
{
getTwitterSource
().
init();
}
@Produces
public TwitterSource getTwitterSource
()
{
if (initialCheck
)
{
try
{
Class.
forName("org.jboss.jbw2011.keynote.demo.model.TweetAggregate");
log.
info("Running in JBW2011 Demo Mode.");
demoexists
= true;
}
catch (ClassNotFoundException ex
)
{
log.
info("Running in local JUDCon2011 Demo Mode.");
}
initialCheck
= false;
}
Annotation qualifier
= demoexists
?
new TwitterServerQualifier
() : new TwitterLocalQualifier
();
return twitterSource.
select(qualifier
).
get();
}
This is all in the source code. Feel free to pull it and make improvements or run it to see it in action. There are many more blog posts to come from this demo, so stay tuned…