Abdera2 - Common LibraryTBDDate and Time Handling within Abdera2 extensively leverages the
capabilities of both the
Joda-Time and
Guava Libraries.Specifically, Joda-Time handles all operations with regards to the
handling of the ISO-8601 formatted timestamps required by both the
Atom Syndication Format and JSON Activity Streams standards. The
Guava Library is used as the foundation for a range of utilities
that make working with those dates easier, and more fluid within
the Abdera2 API. Use of the Date-Time utilities provided by the
Common Library is driven deep and extensively throughout the Abdera2
API for both the Atom Syndication Format and Activity Streams implementations.For example, suppose we have a stream of Activity objects and we
want to iterate only those published before the current date and time:The response to getItems() called this way will be an Iterable whose
items specify published property values are date-times occurring before
now. Obviously, this is a bit of a contrived example given that, typically,
all items in the stream will be published before the current date and time,
but you should get the basic idea.In the following example, we ask only for the activities that have
been published within the last 60 seconds:The Abdera2 Common Library includes support for a handful of
complex HTTP Headers including WWW-Authenticate, Cache-Control,
ETag, Link and Preference.The Authentication header support makes it easier to support
custom authentication mechanisms within Abdera2 applications.
For instance, to use OAuth 2.0 Bearer Tokens, you can use:Adding additional parameters is straightforward:Parsing the header is equally straightforward:The CacheControl class makes it simple to generate and parse any
combination of Cache-Control directives:Extension directives are also supported:The Prefer header
is a proposed extension to HTTP.The Abdera2 Common Library contains a handful of specialized
InputStream and Reader implementations for performing a variety
of tasks including limited character set encoding detection based
on byte order marks, character code filtering, Multipart MIME
parsing, peeking ahead in a stream without consuming the bytes,
and rewinding an already read stream. These utilities are
available in the org.apache.abdera2.common.io package.TBDTBDThe org.apache.abdera2.common.security.HashHelper class provides
a handful of helpful utility methods and Guava Function implementations
for generating MD5 hashed, HMACs and simple digital signatures.The Abdera2 Selector Framework is an extension to the Guava
Libraries
Predicate interface and is used extensively throughout
the Abdera2 API. A single Selector instance can be used to perform
a broad range of tests and conditions operations.Most Selector implementations are threadsafe and immutable, maintaining
no internal state. However, Selectors returned by the limit() method, illustrated
above, maintain an internal counter and are not considered to be threadsafe.
Such Selectors should implement the org.apache.abdera2.common.selector.StatefulSelector
interface to indicate that they are not threadsafe.Abdera2 includes an implementation of the current URI Template
specification.
A URI Template is a specially formatted string containing tokens that
can be replaced to expand into a URI or IRI. For example:The URI generated by this template is:
http://example.org/~johndoe/a/b/c?foo=xyz&bar=123TBDThere's quite a bit there... so let's break down exactly what's going on...First of all, the Abdera2 MapReduce implementation is integrated tightly
with the Guava Libraries Function interface. Essentially, all of the core
components of the MapReduce operations (e.g. the mapper, the reducer,
combiners, etc) are all implemented as Function objects. The MyMapper class is straightforward and should be recognizable to
anyone familiar with MapReduce in general...If it's not clear what's going on in the mapper, we basically take an
Activity as input, grab the displayName of the Actor object, and collect
using the displayName as key and the actor object as the value. The
counting reducer, then, goes through and counts the number of unique
values we've collected. This particular implementation doesn't keep track
of different actors who happen to share the same name, but that's not
important for now.Note that the mapper and the counting reducer are wrapped inside a
Guava Function object that takes an Iterable of
org.apache.abdera2.common.misc.Pair<Void,Activity> objects and
outputs an Iterable of org.apache.abdera2.common.misc.Pair<String,Iterable<Integer>>
objects. The output is a mapping of each actor displayName to the number of
activities in which that name appeared in the input collection.That gives us our counts, but doesn't quite give us the output we
want.. so we need to define a bit more...This code creates another function that will take as input the output
of our initial mapper (f1) and perform an inversion mapping (swap the
key and the value), then reverse the order using the natural order of
the keys. Since the keys are integers, the highest numbers will appear
first.So now we have two functions, f1 and f2. We could call these separately,
but since the output of one becomes the output of the second, it's easier
if we just go ahead and compose those into a single function...So now we have a function (f3) that takes as input a bunch of Activity
objects and outputs a sorted listing of actor names ordered by number of
occurrences. But we're still not quite done yet... note that the input of
the function is an Iterable of Pair<Void,Activity> objects. That's kind of
annoying really because what I really want to start off with is an Activity
Stream. So let's create a function that converts an Activity Stream to the
appropriate Iterable...I've marked in bold the important bits.. basically, the Pair object has
a static method called index that takes a collection of items and an
Key-generating Function object (which in this case always returns void)
and generates an Iterable of Pair objects for each of the Activities in
the Stream.Once we have our transform function, it's time to do a bit more
composition...Note that here, we're creating another Function that takes as input an
Activity Stream Collection object and outputs a java.util.concurrent.Future
whose value, when set, will be our sorted listing of actors. The new
function is composed of two individual functions: our transform created
above, and the combined MapReduce function (f3) that we created previously.
However, first, we wrap f3 within another special Abdera2 construct called
a "futureFunction", which is essentially a Guava Function object that
operates asynchronously using a java.util.concurrent.ExecutorService.Once all of this is defined and composed together (note that everything
is stored in static, final, immutable thread-safe constants) and once we've
built our Activity Stream, we can call our analysis operation using a
single simple line of code (shown in bold below):The call to ff.apply(col) returns our Future object. Calling get() on
that blocks until the asynchronous operation is complete. Obviously this
is just an example; there are a variety of ways we can use that Future
object so that blocking the current thread isn't required (the Future
returned is actually a Guava ListenableFuture).