Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

From From this mailing list thread...

On our last few design calls we've been working through the generic AttributeType mechanism that we're introducing in 1.9. (

Jira Legacy
TRUNK-2588
TRUNK-2588
serverOpenMRS JIRATRUNK-2588
)
We wanted to summarize the current state of things. Some of this is in trunk, but some is refactoring Darius is doing. We're especially interested in thoughts about how these classes should be linked together with parameterized types, since we're not convinced we've gotten that right:

...

Roger's notional x-ray object

Gliffy
sizeL
nameRadiology Document

Roger's proposal

These use cases all rely on the custom data service object and handler object described below. These three use cases show the way the three different uses of custom datatypes interface with the cdso and handler.

Gliffy
sizeL
nameUse case 1
Gliffy
sizeL
nameUse case 2
Gliffy
sizeL
nameUse case 3

Roger's notes on the custom data service object

...

Interface with the custom datatype consumer (global propertysettings (formerly Global Properties from platform 1.8 downwards), object attribute, complex obs)

  • one object per consumer – in attribute context, this means one per property type; in the global property context settings (formerly Global Properties from platform 1.8 downwards) context, this means one for each property that is being displayed
  • constructor() – default handler, handler config="", minOccurs=0, maxOccurs=1
  • constructor(String handler, String handlerConfig, int minOccurs, int maxOccurs)
  • the consumer loads the custom datatype with all its values and receives them back via save
    • standard interface
      • data is exchanged through a List<CustomDataRow>; deleted objects have newValue=null, new objects have oldValue=null

        Code Block
        languagejava
        
        public CustomDataRow {
          public String key;  // optionally set by/returned to consumer
          public String oldValue;  // set by/returned to consumer
          public String newValue;  // returned to consumer
          public String voidReason;  // returned to consumer
          public Object data;  // for internal use by custom data service object
        }
        

        The list is copied to a local list on load and then to a temporary list before returning from save; changes to the list by the consumer have no effect and the data object is never returnd to the customer

      • load(List<CustomDataRow>) (empty indicates no values exist)
      • save() : List<CustomDataRow> throws DataError Exception (empty indicates no values exists and none were added; underlying data is saved)
      • customerIterator() : ListIterator<Integer>
    • alternate interface where maxOccurs=1 (throws UnsupportedOperation Exception if maxOccurs != 1)
      • load(String) (null indicates no value exists)
      • save() : String throws DataError Exception (null indicates not set or voided; underlying data is saved)
      • getVoidReason() : String (returns null if not present)
    • both interfaces
      • cancel() (any changes not previously saved are abandoned and the custom data service object is cleared)
      • isDirty() : Boolean (whether any changed have been made to the list)
      • validate() : List<String> (each element is validated and the multiplicity is validated; any errors found are returned as messages; if no errors are found, returns and empty list and dirty is cleared; calling validate before saving guarantees no error will be thrown)
      • cancel() (changes are discarded and loaded data is cleared)
  • the custom data service object delegates handler calls to the handler

...

  • Any connection setup such as logging into a remote service should be done in the constructor; it should be ready to go when the data service object references it

Gliffy
sizeL
nameUse case 3 seq diagram

Roger's final design

Gliffy
sizeL
nameCustom Datatype Object Model

Attribute/Method

Description

CustomDataService Interface

* handlerName : String

Handler to use to render

* handlerConfig : String

Handler config to use to render

* minOccurs : Integer

Minimum number of values (>0)

* maxOccurs : Integer

Maximum number of values (0=infinity)

- handler : CustomDataHandler

Handler instance based on Handler

- data : List<CustomDataRow>

Holds a set of values for a single datatype

+ loadAll(data : List<CustomDataRow>)

Loads a set of CustomDataObjects

+ saveAll() : List<CustomDataRow>

Saves changed data and returns newValues to persist or voidReasons, throws data error if invalid

+ load(data : String)

Loads a single oldValue, throws UnsupportedOperation exception if maxOccurs != 1

+ add(data : String, key : String)

Adds an oldValue and key; clear must be called first if not new

+ save() : String

Saves changed data and returns newValue to persist, throws UnsupportedOperation exception if maxOccurs != 1, throws data error if invalid

+ getVoidReason() : String

Gets voidReason for singleValue, null if not void, throws UnsupportedOperation exception if maxOccurs != 1

+ clear()

Resets all data objects discarding any changes

+ isDirty() : Boolean

Returns true if there are changed objects

+ validate() : List<String>

Validates each data item and checks multiplicity, returns messages if errors are found

+ render(style : String) : Object

Delegates to handler

+ render(style : String, index : Integer) : Object

Delegates to handler

+ getScript(): String

Delegates to handler

+ getHTML(name : String)

Delegates to handler

+ getProperties() : Properties

Delegates to handler

+ setProperties(p : Properties)

Delegates to handler

+ size() : Integer

Returns number of values

+ getElement(name: String, index : Integer) : Object

Returns named data element of indexed value => getElement(null,name,index)

+ setElement(name: String, index : Integer, o : Object)

Sets named data element of indexed value => setElement(null,name,index,o)

+ getElement(name : String) : Object

Returns named data element of value0 => getElement(null,name,0)

+ setElement(name : String, o : Object)

Sets named data element of value0 => setElement(null,name,0,o)

+ getValue() : Datatype

Returns typed value, throws UnsupportedOperation exception if this is not a simple type

+ setValue(d: Datatype)

Returns typed value, throws UnsupportedOperation exception if this is not a simple type

+ getTitle() : String

Returns the short representation of value0

+ getTtile(index : Integer)

Returns the short representation of valueindex

CustomDataHandlerSupport Interface

+ getElement(me : Object,name: String, index : Integer) : Object

Get named, indexed data element, exposed/unexposed depending on me

+ setElement(me : Object, name: String, index : Integer, o : Object)

Set named, indexed data element, exposed/unexposed depending on me

+ size() : Integer

Returns number of values

CustomDataHandler Interface

* handlerConfig : String

Handler's copy of its config

+ render(style : String) : Object

Renders multiple objects in style

+ render(style : String, index : int) : Object

Renders single object in style

+ getScript(): String

Reference to an include file to go in header portion of page

+ getHTML(name : String)

HTML to insert in text for getting multiple objects, name property is prefixed with name

+ getProperties() : Properties

Returns a properties object containing properties to be returned on submit

+ setProperties(p : Properties)

Receives a properties object after submit to update value list

CustomDataRow Class

+ key : String

Optionally set by/returned to consumer

+ oldValue : String

Set by/returned to consumer

+ newValue : String

Returned to consumer

+ voidReason : String

Returned to consumer, null if not voided

- data : Object

For internal use by custom data service object