AN ALTERNATIVE APPROACH TO SUBCLASS IMPLEMENTATION
In this approach, subclass resources remain resources, just are mapped via the
superclass. Substantially all operations are delegated to the appropriate
subclass resource. This is motivated by simplicity, validation and
representation considerations. It is also motivated by a privilege issue I just
realized - the people authorized to create/update a lab order are likely
different from those allowed to create/update a drug order. I have assumed that
the privilege of updating a parent class field in subclass record requires only
parent class privileges
I don't believe this alternative requires much in the way of changes to
existing code other than mappings; adding the controller and resource for each
superclass; some changes in asRepresentation where it finds the right
representation to use; and some changes where updates are going on to allow the
possibility that the fields to be looked for in the request body may come from
an object which is a parent class of the object being updated. It eliminates
the need for the two variable lists used by Darius (although they could still
be used if it was thought they added value). I still think it is a good idea to
treat ActiveLists as an abstract class so that the AllergyList and the
ProblemList appear to be two different superclasses.
All members of a class hierarchy request a mapping to
/<superclass>?t=<subclass>. The superclass also requests a mapping to
/<superclass>?!t. I have tried to make all the calls of /<superclass>?!t work
the same as calls to /<superclass>?t=<superclass>, if I have missed please let
me know. It might be worthwhile to extend Resource to SuperclassResource to
make the coding of the type-free calls easier. All representations include a t
virtual field which contains the actual subclass of the object being
represented.
1. GET <superclass>?t=<subclass>&v=<rep>, GET <superclass>?!t
Purpose is to get all records of a particular subclass in a formatted
representation. Spring routes this to the subclass controller. The subclass
resource uses getAll to get a (polymorphic) list of objects. asRepresentation
determines the class of each object and looks for the requested representation
in that subclass resource; if it exists, it is used; if not, the parent class
resource (if any) is searched for a representation; this continues until the t
subclass has been searched, at which point a rep does not exist error is thrown.
2. GET <superclass>?t=<subclass>&v=<rep>&q=<search param>, GET
<superclass>?!t&v=<rep>&q=<search param>
Purpose is to use the standard query for a subclass to get a formatted
representation. Spring routes this to the subclass controller. The subclass
resource uses doSearch to get a (polymorphic) list of objects. asRepresentation
determines the class of each object and looks for the requested representation
in that subclass resource; if it exists, it is used; if not, the parent class
resource (if any) is searched for a representation; this continues until the t
subclass has been searched, at which point a rep does not exist error is thrown.
3. GET <superclass>?t=<subclass>&v=<rep>&<custom search>=<search param>
Purpose is to do a custom search that is defined at some level of the class
hierarchy. Spring routes this to the subclass controller. The subclass
controller creates a resource for its type and delegates the search to it. The
resource uses service methods to do the search to produce a (polymorphic) list
of objects. asRepresentation determines the class of each object and looks for
the requested representation in that subclass resource; if it exists, it is
used; if not, the parent class resource (if any) is searched for a
representation; this continues until the t subclass has been searched, at which
point a rep does not exist error is thrown.
4. GET <superclass>/<uuid>?!t&v=<rep>
Purpose is to get all records of a particular subclass in a formatted
representation. Spring routes this to the superclass controller. The superclass
resource uses getByUuid to get an object. asRepresentation determines the class
of each object and looks for the requested representation in that subclass
resource; if it exists, it is used; if not, the parent class resource (if any)
is searched for a representation; this continues until the t subclass has been
searched, at which point a rep does not exist error is thrown.
5. GET <superclass>/<uuid>?t=<subclass>&v=<rep>
Purpose is to use a representation from a parent class. Like 5, except after
getting by Uuid, the subclass resource coerces the result to be its type.
asRepresentation determines the class of each object and looks for the
requested representation in that subclass resource; if it exists, it is used;
if not, the parent class resource (if any) is searched for a representation;
this continues until the supertype has been searched, at which point a rep does
not exist error is thrown.
6. POST <superclass>?t=<subclass> {body}
Purpose is to create a new object of type <subclass>. The subclass resource
creates a new object whose fields are extracted from the body (no need to know.
The subclass resource save method uses services method to save the object;
validation takes place in the save method.
7. POST <superclass>/<uuid>?!t {body}
Purpose is to update an object of any subclass. The type is determined and the
operation is delegated to the resource of the actual type.
8. POST <superclass/<uuid>?t=<subclass> {body}
Purpose is to update an object using only parent-level fields. This is to avoid
additional privileges at the actual subclass level. The type is deermined and
the operation is delegated to the resource of the declared type. Throws an
error if the actual type is not a subclass of the type declared.
9. DELETE <superclass>/<uuid>?!t&!purge, DELETE
<superclass>/<uuid>?t=<subclass>&!purge
Purpose is to delete an object of any subclass. The type is determined and the
operation is delegated to the resource of the actual type. The subclass, if
present, must match the actual type of the resource.
10. DELETE <superclass>/<uuid>?purge&!t, DELETE <superclass>/<uuid>?purge
Purpose is to purge an object of any subclass. The type is determine and the
operation is delegated to the resource of the actual type. The subclass, if
present, must match the actual type of the resource.
_________________________________________
To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to
[email protected] with "SIGNOFF openmrs-devel-l" in the body (not
the subject) of your e-mail.
[mailto:[email protected]?body=SIGNOFF%20openmrs-devel-l]