Darius -- Could you please show how the methods you are defining in the resources and controllers work? You should at least do a final version of the list for the methods that are needed for regular class, superclass and subclass. At best, you should show/point to examples of all 3.
From: dev@openmrs.org [mailto:dev@openmrs.org] On Behalf Of Darius Jazayeri Sent: Tuesday, April 24, 2012 9:22 PM To: openmrs-deve...@listserv.iupui.edu Subject: Re: [OPENMRS-DEV] An Alternative Approach to Subclass Implementation On RESTWS-243<https://tickets.openmrs.org/browse/RESTWS-243> I've attached a patch that contains my implementation that I'm now ready to commit. (It's what Roger was responding to in his email.) I'm going to hold off on committing until after tomorrow's design call in case we have time to discuss this a bit. Basically what I've done is allow resources to indicate that they support subclasses, and if they do, they'll have all appropriate DelegatingSubclassHandlers registered with them via spring. The idea is that we're hiding subclasses from the consumer of the REST API. As far as they're concerned there is a single "order" resource, which has documents of different types (e.g. "order", "drugorder", etc.) Behind the scenes each type is a subclass, but in REST that's not visible, rather they're exposed as different document types. DelegatingSubclassHandler encapsulates the methods subclasses need to specify for their owning resource. Here is the functionality that my approach supports: GET order * gets all orders regardless of type * each document in the list may have different types * the top-level resource does the db query and delegates to the appropriate handler to convert each result GET order?t=drugorder * gets all orders whose type is drugorder * the subclass handler does the db query * In my implementation GET order?t=order (i.e. get only things that are order stubs) is not allowed GET order?patient=<uuid> * gets all orders for the given patient * each document in the list may have different types GET order?patient=<uuid>&t=drugorder * gets all orders for the given patient whose type is drugorder * if the subclass handler defines a suitable method, we use it, otherwise the top-level resource queries by patient, and manually filters out by type GET order/<uuid> * returns a specific order * representations are defined by the type, e.g. { "type": "drugorder", "dose": "100", ... } POST order * creates a new order * you must specify the type in the content, e.g. { "type": "drugorder", "dose": "100", ... } * allowed properties are defined by the type POST order/<uuid> * modifies an existing order * you are not allowed to change the type * allowed properties are defined by the type DELETE order/<uuid> * voids an order * handled by the top-level resource, not the subclass handler DELETE order/<uuid>?purge=true * purges an order * handled by the top-level resource, not the subclass handler @Roger, can you please phrase your counterproposal in terms of the additional functionality that you want to expose beyond these methods? -Darius On Mon, Apr 23, 2012 at 9:54 AM, Burke Mamlin <bmam...@regenstrief.org<mailto:bmam...@regenstrief.org>> wrote: Roger, Could you provide some concrete examples? -Burke On Mon, Apr 23, 2012 at 8:07 AM, Friedman, Roger (CDC/CGH/DGHA) (CTR) <r...@cdc.gov<mailto:r...@cdc.gov>> wrote: 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. ________________________________ Click here to unsubscribe<mailto:lists...@listserv.iupui.edu?body=SIGNOFF%20openmrs-devel-l> from OpenMRS Developers' mailing list ________________________________ Click here to unsubscribe<mailto:lists...@listserv.iupui.edu?body=SIGNOFF%20openmrs-devel-l> from OpenMRS Developers' mailing list ________________________________ Click here to unsubscribe<mailto:lists...@listserv.iupui.edu?body=SIGNOFF%20openmrs-devel-l> from OpenMRS Developers' mailing list _________________________________________ To unsubscribe from OpenMRS Developers' mailing list, send an e-mail to lists...@listserv.iupui.edu with "SIGNOFF openmrs-devel-l" in the body (not the subject) of your e-mail. [mailto:lists...@listserv.iupui.edu?body=SIGNOFF%20openmrs-devel-l]