|
ref_send API 2.17 defensive programming in Java |
|||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
See:
Description
Interface Summary | |
---|---|
Record | A pass-by-construction object. |
Annotation Types Summary | |
---|---|
deserializer | Marks the deserialization constructor. |
name | Provides a parameter's name. |
A pass-by-construction interface.
The ref_send API supports the design of interfaces that work well in a distributed application. One of the differences between a local application and a distributed application is the importance of pass-by-copy data. In a local application, the difference between accessing a variable versus calling a method may be negligible. In a distributed application, the difference may be significant since an additional network request may be required for the method invocation. This network request negatively impacts performance since an additional network round-trip is required. More importantly though, the additional network request complicates the client code since it must now cope with the timing issues and failure modes that come with doing a network request. Client code is often much simpler when all the data it needs can be provided as one bundle. To support creating such data bundles, this package defines an API for declaring a pass-by-construction class. When an object of such a class is sent in a method invocation, or return, its publicly accessible state is sent, instead of a remote reference. Similarly, such an object can be reconstructed when its state is received as part of a method invocation.
A class can be made pass-by-construction simply by declaring it to be so and annotating one of its public constructors with information mapping the class' public fields to its constructor parameters. For example:
package org.example.membership; import org.joe_e.Struct
; import org.ref_send.deserializer
; import org.ref_send.name
; import org.ref_send.Record
; import java.io.Serializable
; /** * Information about a club member. */ public class LoyaltyCard extends Struct implements Record, Serializable { static private final long serialVersionUID = 1L; /** * member's full name */ public final String name; /** * year membership began */ public final int year; /** * Is a premium member? */ public final boolean premium; /** * Constructs an instance. * @param name {@link #name} * @param year {@link #year} * @param premium {@link #premium} */ public @deserializer LoyaltyCard(@name("name") final String name, @name("year") final int year, @name("premium") final boolean premium) { this.name = name; this.year = year; this.premium = premium; } }
The Javadoc comments in the above example are purely optional. The important steps are:
Record
Serializable
and declare a
serialVersionUID
public final
fielddeserializer
annotationStruct
class, which provides default
implementations for the Object
equals()
and
hashCode()
methods that do a by-value
comparision, instead of using the object's creation identityWhen using the Waterken Server, a remote invocation whose sole argument is an instance of the class above results in an HTTP request with the following JSON data:
[ { "class" : [ "org.example.membership.LoyaltyCard" ], "name" : "Tyler Close", "year" : 2008, "premium" : true } ]
The networking code in the Waterken Server automatically recognizes which
invocation arguments are Record
objects and produces the
corresponding JSON data for them. You can create an arbitrarily large JSON
document by constructing an arbitrarily deep tree of
Record
objects. For example, the class below adds an
address and array of tags:
package org.example.membership; import org.joe_e.array.PowerlessArray
; import org.ref_send.deserializer
; import org.ref_send.name
; /** * Postal information about a club member. */ public class MailingLoyaltyCard extends LoyaltyCard { static private final long serialVersionUID = 1L; /** * postal address */ public final Address mailto; /** * a list of tags indicating mailing preferences */ public final PowerlessArray<String> preferences; /** * Constructs an instance. * @param name {@link #name} * @param year {@link #year} * @param premium {@link #premium} * @param mailto {@link #mailto} * @param preferences {@link #preferences} */ public @deserializer MailingLoyaltyCard( @name("name") final String name, @name("year") final int year, @name("premium") final boolean premium, @name("mailto") final Address mailto, @name("preferences") final PowerlessArray<String> preferences) { super(name, year, premium); this.mailto = mailto; this.preferences = preferences; } }
An instance of the above class would produce JSON like:
{ "class" : [ "org.example.membership.MailingLoyaltyCard", "org.example.membership.LoyaltyCard" ], "name" : "Tyler Close", "year" : 2008, "premium" : true, "mailto" : { "street" : "1501 Page Mill Road", "city" : "Palo Alto", "state" : "CA", "zip" : "94304" }, "preferences" : [ "2-day-shipping", "monthly" ] }
The value of the "class"
member is an array listing the
name of every type implemented by the object, ordered from most specific to
least. If the most specific type of an object is implied by the referring
object, the type declaration is omitted. For example, the object referred
to by the "mailto"
member is not annotated with a
"class"
member, since the type
org.example.membership.Address
is implied by the referring
object's type "org.example.membership.MailingLoyaltyCard"
.
By making effective use of Record
objects, you can
create distributed applications in the document-oriented messaging style. In
such applications, clients and servers coordinate primarily based on the
content of exchanged documents, rather than on expectations about remotely
maintained state. Such designs can sometimes result in fewer dependencies
between clients and servers and so facilitate the creation of interoperable
software. When using the ref_send API, you define the structure of your
exchanged documents by defining a set of Record
types.
Each exchanged document is then created by composing an object tree from
these Record
types.
org.ref_send.scope
|
ref_send API 2.17 defensive programming in Java |
|||||||||
PREV PACKAGE NEXT PACKAGE | FRAMES NO FRAMES |
Copyright 1998-2009 Waterken Inc. under the terms of the MIT X license.