Hi Jim, Rong,
I am not yet up to speed on the Java code, but will give some generic
answers, based on our previous Australian kernel implementation (based
on the pre-openEHR GeHR models).
> Rong,
>
> I have a several questions related to the lifecycle of archetypes once
> they are created.
>
>Question 1
>==========
>
>
> I use The following code fragment to create an object from an archetype
>
> rmobj = archetype.buildRMObject(valueMap, errorMap, sysmap());
>
> One of my constraints for this archetype is optional, as shown below
>
>ELEMENT[at0004] occurrences matches {0..1} matches {
>value matches {
> DVTEXT matches {
> value matches {/.+/}
> }
>}
>
>
> In the valueMap I don't supply a value for this element and therefore
> it is not created. The 'rmobj' instance is created as expected.
>
> At some later stage, I want to record a value against ELEMENT[at0004].
> Do I need to manipulate the 'rmobj directly as shown below
>
>Account account = (Account)rmobj;
>Element element = new Element("isDebitAccount",
> new DvText("isDebitAccount"), isDebitAccount);
>account.getDetails().items().add(element);
>
>
> or can I create it using a path expression?
Until we get a proper standardised API defined for this, you can do it
how you like - as long as the archetype is respected. In our GeHR
implementation, we had two ways of doing it, approximately as follows:
1. insert_at_path(some_path, an_element)
Note that the path here is the runtime path, which is always unique. You
can thus always insert exactly where you want.
2. routines which navigated a cursor through a structure and then
allowed an insert once you had arrived where you wanted. This kind of
API had a lot of routines, and was a lot like a data structure library.
I now believe the path-based approach to be clearer, more concise (i.e.
smaller API) and more in line with how people think today (i.e due to
XML-indoctrination;-). But neither is more right technically speaking.
The main thing is that the insert_at_path() (or whatever you call it)
call must check the relevant archetype node that the insertion is
allowable, and it should fail if it is not. Your code should always know
in advance what node this is, due to the choosing of archetypes
beforehand (e.g. by the GUI forms).
Consider the example of the Address archetype at
http://svn.openehr.org/knowledge/archetypes/dev/adl/openehr/demographic/openehr-demographic-address.location_address.draft.html.
The user might be trying to add a state/province ELEMENT. Either:
a) your software already created one of these at the create_default()
stage, just waiting for the value to be filled in
b) since that ELEMENT is optional, your software did not create one, but
somewhere on your GUI window was a way to add such a node; when the user
hits the right button, the archetype path will be known, and the check
can be made.
It might also be that the user wants to add a new ELEMENT which doesn't
correspond to any of the predefined ELEMENTs; for this the correct
archetype node is the [at9000] one.
>
>
> Question 2
> ==========
> Is there a programmatic way to validate that an object conforms to the
> constraints of an archetype?
Every subclass of ARCHETYPE_CONSTRAINT from the archeytpe object model
(AOM)
(http://svn.openehr.org/specification/TRUNK/publishing/architecture/am/aom.pdf)
should implement the method valid_value. Here are the signature from
theEiffel class C_PRIMITIVE:
deferred class C_PRIMITIVE
inherit
ANY
redefine
out
end
feature -- Access
default_value: ANY is
-- generate a default value from this constraint object
deferred
ensure
Result /= Void
end
assumed_value: like default_value
-- assumed value for this constraint object
-- FIXME: consider consolidating with assumed_value in
C_DOMAIN_TYPE
feature -- Status Report
valid_value (a_value: like default_value): BOOLEAN is
require
a_value /= Void
deferred
end
has_assumed_value: BOOLEAN is
-- True if there is an assumed value
do
Result := assumed_value /= Void
end
feature -- Modification
set_assumed_value(a_value: like assumed_value) is
-- set `assumed_value'
require
a_value /= Void and then valid_value(a_value)
do
assumed_value := a_value
ensure
assumed_value_set: assumed_value = a_value
end
feature -- Output
as_string:STRING is
deferred
ensure
Result_exists: Result /= Void
end
out: STRING is
do
Result := as_string
end
invariant
Assumed_value_valid: assumed_value /= Void implies
valid_value(assumed_value)
end
These routines should actually be defined on ARCHETYPE_CONSTRAINT, not
just C_PRIMITIVE, but I have not gotten around to doing this on my
reference implementation yet. Don't worry too much about assumed_values
if you don't want to yet, but the valid_value() method is needed. You
need to implemented it for all the basic types, e.g. like the following
(unfinished) for C_DATE_TIME:
valid_value (a_value: DATE_TIME): BOOLEAN is
do
if interval /= Void then
Result := interval.has(a_value)
else
-- Result := a_value matches pattern FIXME - to be
implemented
Result := True
end
end
For the types like C_OBJECT, the implementation of valid_value() just
needs to be a recursive call to the same function in the children.
The short-term aim is to publish standard algorithms for all of these
functions (it's only about 20 or less - just add up all the classes in
Fig 6 and Fig 9 in the AOM.
So the programmatic approach is mostly solved by doing the
implementation of this function in these classes. You also need to
provide error messages for when the result is False.
>
> Question 3
> ==========
> This relates to an earlier question. Can you explain the how "|" works
> in a path expression?
can you give more details on what you mean here?
- thomas
>
>
-
If you have any questions about using this list,
please send a message to d.lloyd at openehr.org