Field sets are a new facility for adding arbitrary typed data to crack objects.
Synopsis:
import crack.fieldset FieldSet, HashMapFieldSet;
@import crack.fieldset_ann fieldset_accessors;
class Context : HashMapFieldSet { ... }
class Foo {
@fieldset_accessors(Foo);
String name;
}
void func(Context context) {
# Try to get the Foo instance for the context.
foo := Foo.get(context);
if (!foo) {
# If the instance wasn't defined, create it and add it to the
# field set.
foo = getFooFromSomewhere();
foo.putIn(context);
}
}
void otherFunc(Context context) {
# Remove the Foo field.
Foo.deleteField(context);
}
In the interest of loose coupling, it is often useful for a modular subsystem
to be able to inject its own data into a shared context object provided by a
framework. This tends to be relevant in workflow systems.
For example, when defining HTTP request handlers, it's often useful to chain
several handlers together. We might have an authentication handler that
verifies the user, a session handler that stores information on a specific
interaction and a page-specific handler that does whatever it is that the URL
is intended to serve.
It's hard to do something like this modularly in a statically typed language.
Typically the page handler will require knowledge of facts gathered by the
authentication handler and session handler but there is no good place to store
these facts, so the generic handlers end up being implemented as functions
which are called from all of the page-specific handlers, making them
impossible to compose and contributing to the amount of boilerplate code
required.
What we'd typically like to do in these cases is to attach all of this custom
information to the request object that is typically passed into a handler from
the framework. Then the process of writing generic handlers becomes one of
defining a handler for the framework and having the handler attach its facts
to the request object. A page-specific handler can then query the request
object for the required subsystems.
Field sets let us do this. If the request object is a field set, each of the
generic handlers can attach their own piece of data to it and any interested
consumer with that request object can retrieve it.
FieldSet is implemented as an interface (in #crack.fieldset#) providing
getFieldVal() and setFieldVal() methods. These essentially map a uintz to an
Object. A uintz is used as the key to allow us to use object addresses as
unique keys. The fieldset code is designed around using the addressses of
class instances as keys, but any other uintz values can be used providing they
do not collide. If general object addresses are used, you'll need to ensure
that the objects are never deleted and their addresses reused. Class
instances have the virtue of remaining stable for the duration of the
program's execution.
HashMapFieldSet implements the FieldSet interface with a HashMap.
#crack.fieldset_ann# contains the @fieldset_accessors annotation which defines
the get(), putIn() and deleteField() methods for a class to be stored in a
field set. It should be used in any class that you want to store in a field
set.
So looking at our example above, we have the Context class (which derived from
HashMapFieldSet) and the Foo class (which defines the FieldSet accessors to
store its instances in a FieldMap).
We can set the Foo instance with: foo.putIn(context);
We can get it with: Foo.get(context)
And we can delete it: Foo.deleteField(context);
For an undefined field, the get() accessor just returns null. So deleting a
field is equivalent to just setting it to null.
Field sets are not currently used elsewhere in the library. I plan to add
them to crack.net.httpsrv.Request.
=============================================================================
michaelMuller =
mmu...@enduden.com |
http://www.mindhog.net/~mmuller
-----------------------------------------------------------------------------
In this book it is spoken of the Sephiroth, and the Paths, of Spirits and
Conjurations; of Gods, Spheres, Planes and many other things which may or
may not exist. It is immaterial whether they exist or not. By doing
certain things certain results follow. - Aleister Crowley
=============================================================================