The issue that I neglected to mention is that I imagine these things will
be spring beans, wired up that way, so there won't actually be a register
method called at all...

You're right that we should be able to use generic type signatures to
require and self-document the need for a subclass. I'll deal with that as
an implementation detail. (And we're way in the weeds now...)

-Darius


On Thu, Apr 19, 2012 at 11:52 AM, Burke Mamlin <[email protected]>wrote:

> Sure, but don't you typically indicate the need for subclasses in Java by
> requiring an interface or specific base class as a parameter instead of
> putting the term "subclass" in your method name?  For example, assuming new
> types of orders will show up as new concept classes:
>
> registerOrderableClass(Class<? extends Order> clazz, String name,
> OrderableClassHandler handler);
>
> -Burke
>
>
> On Thu, Apr 19, 2012 at 2:40 PM, Darius Jazayeri 
> <[email protected]>wrote:
>
>> From a code-writing perspective, it actually *is* important that it's a
>> subclass. Particularly, this approach depends on the fact that we have an
>> OrderService.getOrders(...) that returns a list of different kinds
>> (subclasses) of orders.
>>
>> I agree that we should not mention "subclass" anywhere in the
>> externally-facing WS docs (and that's why I prefer this approach to the
>> subclass-links-to-superclass approach: this way give us "different kinds of
>> orders"). But I feel like it's important for the developer writing the code
>> behind the scenes to know that subclasses are involved. Maybe this is just
>> a javadoc issue.
>>
>> -Darius
>>
>>
>> On Thu, Apr 19, 2012 at 11:20 AM, Burke Mamlin 
>> <[email protected]>wrote:
>>
>>> Can we remove "subclass" from any of this?  That term is not intuitive
>>> and has no clinical meaning – e.g., instead use something like
>>> registerOrderType or registerOrderClass, depending on how we decide to
>>> decide to model different types of orders.  If we follow the path laid out
>>> during the design call and start out just supporting different types as
>>> orderables using concept classes, then I'd favor registerOrderClass or
>>> registerOrderableClass.
>>>
>>> -Burke
>>>
>>> On Thu, Apr 19, 2012 at 1:29 PM, Darius Jazayeri <
>>> [email protected]> wrote:
>>>
>>>> I just replied on the ticket...
>>>>
>>>> @Roger, I really really don't like the idea of ignoring extra
>>>> properties. Trying to update a resource with a property it doesn't support
>>>> should _not_ fail silently, it should give you a BAD REQUEST.
>>>>
>>>> From my proposal above, I think we _should_ include a discriminator
>>>> property when you're doing a POST to create, e.g:
>>>> {code}
>>>> {
>>>>     type: "org.openmrs.module.lab.LabModuleOrder",
>>>>     startDate: "2011-03-04",
>>>>     labModuleSpecimen: "<uuid>"
>>>> }
>>>> ...will be delegated to the registered handler for LabModuleOrder,
>>>> rather than being handled directly by OrderResource.
>>>> {code}
>>>>
>>>> The one revision I'd make to what I said before is that we should hide
>>>> the fully-qualified classnames from the end-user of REST. The module should
>>>> do something like
>>>> {code}
>>>> registerSubclass(OrderResource.class, "LabModuleOrder", new
>>>> LabModuleOrderSubclassHandler());
>>>> {code}
>>>>
>>>> -Darius
>>>>
>>>> On Thu, Apr 19, 2012 at 10:15 AM, Friedman, Roger (CDC/CGH/DGHA) (CTR)
>>>> <[email protected]> wrote:
>>>>
>>>>>  That's why I'd like to see subclasses appear as "flat"; you'd still
>>>>> have to update up the tree, but you could use the same body and each layer
>>>>> would pick off the variables it needs.  As for create, Hibernate would 
>>>>> take
>>>>> care of the splitting and only the subclass would be exposed, so there's 
>>>>> no
>>>>> need for multiple updates.  But this means that there would be no errors
>>>>> for specifying "extra" variables.****
>>>>>
>>>>> ** **
>>>>>
>>>>> *From:* [email protected] [mailto:[email protected]] *On Behalf Of *Darius
>>>>> Jazayeri
>>>>> *Sent:* Thursday, April 19, 2012 1:01 PM
>>>>>
>>>>> *To:* [email protected]
>>>>> *Subject:* Re: [OPENMRS-DEV] REST WS and subclasses****
>>>>>
>>>>> ** **
>>>>>
>>>>> Burke, if we incorporate Jeff Wishnie's off-list suggestion to us
>>>>> about making the "Subclass links to Superclass" also include a link from
>>>>> the superclass to the subclass, we could do something like this:****
>>>>>
>>>>> ** **
>>>>>
>>>>> GET order ->****
>>>>>
>>>>> [****
>>>>>
>>>>>     {****
>>>>>
>>>>>         // order properties here****
>>>>>
>>>>>         links: [****
>>>>>
>>>>>             { rel: "self": uri: "order/<uuid>" },****
>>>>>
>>>>>             { rel: "more-details": uri: "drugorder/<uuid>" }****
>>>>>
>>>>>         ]****
>>>>>
>>>>>     },****
>>>>>
>>>>>     {****
>>>>>
>>>>>         // order properties here****
>>>>>
>>>>>         links: [****
>>>>>
>>>>>             { rel: "self": uri: "order/<uuid2>" },****
>>>>>
>>>>>             { rel: "more-details": uri: "laborder/<uuid2>" }****
>>>>>
>>>>>         ]****
>>>>>
>>>>>     }****
>>>>>
>>>>> ]****
>>>>>
>>>>> ** **
>>>>>
>>>>> GET drugorder ->****
>>>>>
>>>>> {****
>>>>>
>>>>>     // only DrugOrder-specific properties here****
>>>>>
>>>>>     order: { ref representation of the superclass },****
>>>>>
>>>>>     links: [****
>>>>>
>>>>>         { rel: "self": uri: "drugorder/<uuid>" }****
>>>>>
>>>>>     ]****
>>>>>
>>>>> }****
>>>>>
>>>>> ** **
>>>>>
>>>>> Personally I prefer my originally-proposed approach #3 instead of
>>>>> this, though. It seems like it would be easier for clients to put all a
>>>>> DrugOrder properties (own and inherited) in a single document, rather than
>>>>> having dosage in one document and startDate and concept in a linked
>>>>> document. As I phrased it before, it makes sense to me that if subclasses
>>>>> "inherit the *meaning* of the superclass, not just its implementation
>>>>> details" then it makes sense to expose them all through a single 
>>>>> resource...
>>>>> ****
>>>>>
>>>>> ** **
>>>>>
>>>>> (But I'm no REST expert, so...)****
>>>>>
>>>>> ** **
>>>>>
>>>>> -Darius****
>>>>>
>>>>> ** **
>>>>>
>>>>> ** **
>>>>>
>>>>> On Thu, Apr 19, 2012 at 9:29 AM, Burke Mamlin <[email protected]>
>>>>> wrote:****
>>>>>
>>>>> Orders are often approached generically (e.g. getting a list of active
>>>>> orders; creating order sets that contain meds, tests, educational
>>>>> materials, referrals, etc.; etc.), all orders share a base of properties &
>>>>> workflows, and we want to allow for modules to add additional types.  By
>>>>> treating all orders types as "orders", we allow consumers to treat
>>>>> different types differently when they know about them, but also fall back
>>>>> to treating them as generic orders for those types they don't understand.
>>>>> ****
>>>>>
>>>>> ** **
>>>>>
>>>>> For example, if I want to generate a list of all active orders, I can
>>>>> go to one place, get this list, and show the names of them, who ordered
>>>>> them, etc. rather than fetching the active list from each resource
>>>>> (drugorder, laborder, radiologyorder, nursingorder, referralorder,
>>>>> dietorder, activityorder, precautionorder, and callorder) and then be
>>>>> forced to refactor my code when I want to include Roger's latest
>>>>> whirlygigorder.****
>>>>>
>>>>> ** **
>>>>>
>>>>> We could model all order types as separate resources, if we can still
>>>>> have a centralized mechanism for dealing with orders (e.g., fetching all
>>>>> active orders) and ensure that all of these resources have some shared 
>>>>> part
>>>>> of their representation that was guaranteed to not only have the same
>>>>> properties, but follow the same business logic (e.g., all orders must have
>>>>> an orderer, the definition of "active" needs to be applied the same across
>>>>> all orders, etc.)****
>>>>>
>>>>> ** **
>>>>>
>>>>> -Burke****
>>>>>
>>>>> ** **
>>>>>
>>>>> On Thu, Apr 19, 2012 at 11:08 AM, Saptarshi Purkayastha <
>>>>> [email protected]> wrote:****
>>>>>
>>>>> The Approach#3 is extremely complex and means that someone needs to
>>>>> understand the type of "what"****
>>>>>
>>>>> ** **
>>>>>
>>>>> A client does not have to understand the types, just resources and so
>>>>> to me the approach #1 is generalizable and concise to understand as a
>>>>> general pattern when having to communicate with OpenMRS web services. 
>>>>> Again
>>>>> why would it be a problem to use Approach#1 with drugorder or laborder
>>>>> resource??****
>>>>>
>>>>>
>>>>> ---
>>>>> Regards,
>>>>> Saptarshi PURKAYASTHA
>>>>>
>>>>> My Tech Blog:  http://sunnytalkstech.blogspot.com
>>>>> You Live by CHOICE, Not by CHANCE****
>>>>>
>>>>>
>>>>>
>>>>> ****
>>>>>
>>>>> On 19 April 2012 06:43, Darius Jazayeri <[email protected]>
>>>>> wrote:****
>>>>>
>>>>> Hi All,****
>>>>>
>>>>> ** **
>>>>>
>>>>> We had a very good design call discussion on this, and Burke and I got
>>>>> some brief, dense, and helpful insight on this from Jim Webber.****
>>>>>
>>>>> ** **
>>>>>
>>>>> The key insight: "Dealing with inheritance is easy: REST doesn't do
>>>>> it." Basically: think of REST resources as simply exchanging documents.
>>>>> There can be links between documents, but they are not allowed to have any
>>>>> formal type hierarchy.****
>>>>>
>>>>> ** **
>>>>>
>>>>> So, after wrapping our heads around that, we've come up with three
>>>>> different approaches to hide inheritance in the REST API, each applicable
>>>>> to different things in the underlying Java class model:****
>>>>>
>>>>> ** **
>>>>>
>>>>> *Approach #1 - Subclass links to Superclass*****
>>>>>
>>>>> *Used for: Person/Patient*****
>>>>>
>>>>> In the REST API, the subclass document contains only subclass-specific
>>>>> attributes, as well as a link to the superclass document. Example:****
>>>>>
>>>>> GET patient/1234 ->****
>>>>>
>>>>> {****
>>>>>
>>>>>     identifiers: [ ... ],****
>>>>>
>>>>>     person: { ref representation of person/1234 }****
>>>>>
>>>>> }****
>>>>>
>>>>> ** **
>>>>>
>>>>> Even though the underlying Patient object inherits from Person, the
>>>>> PatientResource should hide this. Thus you cannot edit a birthdate via the
>>>>> patient resource, *and* creating a patient requires two POSTs (one to
>>>>> create a person resource, the next to create a patient resource that links
>>>>> to the person resource).****
>>>>>
>>>>> ** **
>>>>>
>>>>> *Approach #2 - Hide the Superclass*****
>>>>>
>>>>> *Used for: ActiveListItem/Allergy/Problem*****
>>>>>
>>>>> We use this approach when the multiple subclasses are not meaningfully
>>>>> related to each other, and they only share a superclass for ease of
>>>>> implementation. The REST API has no resource for the superclass. Each
>>>>> subclass is its own resource, which contains the union of the properties 
>>>>> of
>>>>> its superclass and itself.****
>>>>>
>>>>> ** **
>>>>>
>>>>> *Approach #3 - Single Resource for Class Hierarchy*****
>>>>>
>>>>> *Used for: Concept/ConceptNumeric/ConceptComplex*****
>>>>>
>>>>> *Used for: Order/DrugOrder/XyzModuleOrder*****
>>>>>
>>>>> We use this approach when multiple subclasses really are different
>>>>> versions of the same basic thing. In other words, they inherit the meaning
>>>>> of the superclass, not just its implementation details.****
>>>>>
>>>>> The REST API has a single resource (Concept, Order) that manages the
>>>>> documents for all subclasses. Each document represents an underlying
>>>>> instance of some class in the hierarchy, and it contains all properties of
>>>>> that class, including inherited ones.****
>>>>>
>>>>> For example, GET order?patient=1234 ->****
>>>>>
>>>>> [****
>>>>>
>>>>>     {****
>>>>>
>>>>>         type: "org.openmrs.DrugOrder",****
>>>>>
>>>>>         startDate: "2011-01-01",****
>>>>>
>>>>>         // other Order properties go here****
>>>>>
>>>>>         dosage: "100mg",****
>>>>>
>>>>>         // other DrugOrder properties go here****
>>>>>
>>>>>         links: [ { rel: "self", uri: "order/11111" } ]****
>>>>>
>>>>>     },****
>>>>>
>>>>>     {****
>>>>>
>>>>>         type: "org.openmrs.Order",****
>>>>>
>>>>>         startDate: "2011-02-03",****
>>>>>
>>>>>         // other Order properties go here****
>>>>>
>>>>>         links: [ { rel: "self", uri: "order/22222" } ]****
>>>>>
>>>>>     },****
>>>>>
>>>>>     {****
>>>>>
>>>>>         type: "org.openmrs.module.lab.LabModuleOrder",****
>>>>>
>>>>>         startDate: "2011-03-04",****
>>>>>
>>>>>         // other Order properties go here****
>>>>>
>>>>>         specimen: { ref representation of a lab specimen },****
>>>>>
>>>>>         // other LabModuleOrder properties go here****
>>>>>
>>>>>         links: [ { rel: "self", uri: "order/33333" } ]****
>>>>>
>>>>>     }****
>>>>>
>>>>> ]****
>>>>>
>>>>> ** **
>>>>>
>>>>> I've put a discriminator field in here ("type" might not be a safe
>>>>> name) because it seems quite useful, and I think it's necessary for object
>>>>> creation.****
>>>>>
>>>>> For example: POST order****
>>>>>
>>>>> {****
>>>>>
>>>>>         type: "org.openmrs.module.lab.LabModuleOrder",****
>>>>>
>>>>>         startDate: "2011-03-04"   ****
>>>>>
>>>>> }****
>>>>>
>>>>> ...will be delegated to the registered handler for LabModuleOrder,
>>>>> rather than being handled directly by OrderResource.****
>>>>>
>>>>> ** **
>>>>>
>>>>> Implementation-wise:****
>>>>>
>>>>>    - we are going to count on the underlying OpenMRS API (and
>>>>>    ultimately Hibernate) to work such that if we do
>>>>>    OrderService.getOrdersByPatient(1234) we get back a List<Order> whose
>>>>>    individual items are actually of their correct subclasses.****
>>>>>    - the core RESTWS module, and other modules, need to register
>>>>>    handlers for their known subclasses****
>>>>>    - we will have to write some code, but that's the fun part. :-)****
>>>>>
>>>>>  Thoughts?****
>>>>>
>>>>> ** **
>>>>>
>>>>> -Darius****
>>>>>
>>>>> ** **
>>>>>
>>>>> ** **
>>>>>
>>>>> On Wed, Apr 18, 2012 at 6:35 AM, Burke Mamlin <[email protected]>
>>>>> wrote:****
>>>>>
>>>>> My biggest concern is that it requires that consumers of the API
>>>>> know/learn our data model; however, since the person is presented as a
>>>>> property of the patient and gender as a property of the person (not the
>>>>> patient directly), it's about as good a solution as I can imagine.****
>>>>>
>>>>> ** **
>>>>>
>>>>> -Burke****
>>>>>
>>>>> ** **
>>>>>
>>>>> On Tue, Apr 17, 2012 at 10:42 PM, Darius Jazayeri <[email protected]>
>>>>> wrote:****
>>>>>
>>>>> Yes, I meant what you said Burke.****
>>>>>
>>>>> (Hopefully that was my only typo.)****
>>>>>
>>>>> -Darius (by phone)****
>>>>>
>>>>> On Apr 17, 2012 6:48 PM, "Burke Mamlin" <[email protected]>
>>>>> wrote:****
>>>>>
>>>>> Darius,****
>>>>>
>>>>> ** **
>>>>>
>>>>> Did you mean to two posts, one to patient & the other to person?  Both
>>>>> of yours were to the same resource.****
>>>>>
>>>>> ** **
>>>>>
>>>>> This implies that if you want to modify a patient's gender *and* 
>>>>> identifiers,
>>>>> you have to do *two* POSTs.
>>>>> For example:
>>>>> POST patient/abcd1234 { identifiers: [ ... ] }
>>>>> POST *person*/abcd1234 { gender: 'M' }****
>>>>>
>>>>>  ** **
>>>>>
>>>>> Cheers,****
>>>>>
>>>>> ** **
>>>>>
>>>>> -Burke****
>>>>>
>>>>> ** **
>>>>>
>>>>> On Tue, Apr 17, 2012 at 8:01 PM, Darius Jazayeri <[email protected]>
>>>>> wrote:****
>>>>>
>>>>> Hi All,****
>>>>>
>>>>> ** **
>>>>>
>>>>> On tomorrow's design call one topic we will discuss is how to properly
>>>>> represent inheritance and subclasses in a RESTful way. Fun and exciting
>>>>> background discussion can be found on the ticket:
>>>>> https://tickets.openmrs.org/browse/RESTWS-221. Call-in details are
>>>>> here <https://tickets.openmrs.org/browse/RESTWS-221>.****
>>>>>
>>>>> ** **
>>>>>
>>>>> My proposal, generally supported by Saptarshi, and disliked by Roger,
>>>>> is that we represent a subclass as basically the composition of a
>>>>> superclass resource, and a subclass resource contains subclass-specific
>>>>> properties, and a pointer to the superclass.****
>>>>>
>>>>> ** **
>>>>>
>>>>> For example: GET patient/abcd1234 ->****
>>>>>
>>>>> {****
>>>>>
>>>>>     identifiers: [ ... ], // this is the only Patient-specific property
>>>>> ****
>>>>>
>>>>>     links: [****
>>>>>
>>>>>         { rel: "self", uri: "patient/abcd1234" }****
>>>>>
>>>>>     ],****
>>>>>
>>>>>     person: { // this is a pointer to the superclass****
>>>>>
>>>>>         names: [ ... ],****
>>>>>
>>>>>         gender: 'M',****
>>>>>
>>>>>         // other properties on the Person superclass follow ****
>>>>>
>>>>>         links: [****
>>>>>
>>>>>             { rel: "self", uri: "person/abcd1234" }****
>>>>>
>>>>>         ]****
>>>>>
>>>>>     }****
>>>>>
>>>>> }****
>>>>>
>>>>> ** **
>>>>>
>>>>> This implies that if you want to modify a patient's gender * and* 
>>>>> identifiers,
>>>>> you have to do *two* POSTs.****
>>>>>
>>>>> For example:****
>>>>>
>>>>> POST patient/abcd1234 { identifiers: [ ... ] }****
>>>>>
>>>>> POST patient/abcd1234 { gender: 'M' }****
>>>>>
>>>>> ** **
>>>>>
>>>>> You should be able to *create* a patient in a single POST, but not
>>>>> update one that way.****
>>>>>
>>>>> ** **
>>>>>
>>>>> At first this seems inconvenient, and unintuitive for someone who's
>>>>> used to the OpenMRS Java API. The reason for this is that I think it's
>>>>> necessary to support web-standard caching, which allows web service
>>>>> scalability. Basically, imagine that someone may be running a 
>>>>> reverse-proxy
>>>>> on their server, which caches resources generated by the server and serves
>>>>> them up to many web clients, relieving server load. In order for that
>>>>> reverse-proxy cache to avoid serving up stale data, we cannot allow doing
>>>>> POST patient/abc123 to modify the resource at person/abc123. (According to
>>>>> web standards, if the cache sees a POST to patient/abc123, this 
>>>>> invalidates
>>>>> that specific cache entry, but all of this is invisible to the
>>>>> server.) Thus my proposal.****
>>>>>
>>>>> ** **
>>>>>
>>>>> I'm only moderately certain I'm approaching this right, so if you know
>>>>> or suspect the right answer to this problem (especially if it's different
>>>>> from my proposal), please reply and/or join us on the design call 
>>>>> tomorrow!
>>>>> ****
>>>>>
>>>>> ** **
>>>>>
>>>>> -Darius****
>>>>>
>>>>> ** **
>>>>>
>>>>> PS- The other topic we'll discuss on the call is Wyclif's proposal for
>>>>> a module, that will allow us to reboot our implementation of orders and
>>>>> order entry, such that we implement something better, and it runs on both
>>>>> old and new versions of OpenMRS. All in all this will be an action-packed
>>>>> call.****
>>>>>  ------------------------------
>>>>>
>>>>> Click here to 
>>>>> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
>>>>>  OpenMRS Developers' mailing list
>>>>> ****
>>>>>
>>>>> ** **
>>>>>  ------------------------------
>>>>>
>>>>> Click here to 
>>>>> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
>>>>>  OpenMRS Developers' mailing list
>>>>> ****
>>>>>  ------------------------------
>>>>>
>>>>> Click here to 
>>>>> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
>>>>>  OpenMRS Developers' mailing list
>>>>> ****
>>>>>
>>>>> ** **
>>>>>    ------------------------------
>>>>>
>>>>> Click here to 
>>>>> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
>>>>>  OpenMRS Developers' mailing list
>>>>> ****
>>>>>
>>>>> ** **
>>>>>
>>>>> ** **
>>>>>     ------------------------------
>>>>>
>>>>> Click here to 
>>>>> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
>>>>>  OpenMRS Developers' mailing list
>>>>> ****
>>>>>
>>>>> ** **
>>>>>    ------------------------------
>>>>>
>>>>> Click here to 
>>>>> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
>>>>>  OpenMRS Developers' mailing list
>>>>> ****
>>>>>
>>>>> ** **
>>>>>  ------------------------------
>>>>>
>>>>> Click here to 
>>>>> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
>>>>>  OpenMRS Developers' mailing list
>>>>> ****
>>>>>  ------------------------------
>>>>> Click here to 
>>>>> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
>>>>>  OpenMRS Developers' mailing list
>>>>>
>>>>
>>>> ------------------------------
>>>> Click here to 
>>>> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from
>>>>  OpenMRS Developers' mailing list
>>>>
>>>
>>> ------------------------------
>>> Click here to 
>>> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from 
>>> OpenMRS Developers' mailing list
>>>
>>
>> ------------------------------
>> Click here to 
>> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from 
>> OpenMRS Developers' mailing list
>>
>
> ------------------------------
> Click here to 
> unsubscribe<[email protected]?body=SIGNOFF%20openmrs-devel-l>from 
> OpenMRS Developers' mailing list
>

_________________________________________

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]

Reply via email to