7 RIM Services

The oracle.hsgbu.hdr.hl7 package contains a single interface [RIM Service] that provides the main entry point into HDR's query functionality and RIM object persistence.

Submit a Query

Example 7-1 Submit a Query

Use the following RimService APIs to query Acts, ActRelationships, Participations, Roles and Entities directly:

  • queryActs(ServiceLocator s1, ActFetch fetch) throws HDRRimException

  • queryParticipations(ServiceLocator s1, ParticipationFetch fetch) throws HDRRimException

  • queryRoles(ServiceLocator s1, RoleFetch fetch) throws HDRRimException

  • queryEntities(ServiceLocator s1, EntityFetch fetch) throws HDRRimException

  • queryActRelationships(ServiceLocator s1, ActRelationshipFetch fetch) throws HDRRimException

The results of a query are an Iterator of Acts, ActRelationships, Participations, Roles and Entities respectively.

HDR HL7 Domain Constants

Domain constants provide consistent definitions for structural codes. The names of the classes correspond to HL7 vocabulary domains that are coded no exceptions (CNE). Domain constants should be used wherever possible.

Example 7-2 Import the ActStatus Domain Class

Import the ActStatus Domain Class

import oracle.hsgbu.hdr.hl7.rim.domain.ActStatus;

Example 7-3 Use the ActStatus Domain Class to Set Status Code

Use the ActStatus domain class to set the status code on an act that is being created or updated.

act.setStatusCode(ActStatus.ACTIVE);

The following domain classes are available:

  • AcknowledgementCondition

  • AcknowledgementType

  • ActClass

  • ActMood

  • ActRelationshipCheckpoint

  • ActRelationshipJoin

  • ActRelationshipSplit

  • ActRelationshipType

  • ActStatus

  • ActUncertainty

  • BinaryDataEncoding

  • CommunicationFunctionType

  • ContextControl

  • EntityClass

  • EntityDeterminer

  • EntityStatus

  • LocalMarkupIgnore

  • ManagedParticipationStatus

  • ModifyIndicator

  • NullFlavor

  • ParticipationSignature

  • ParticipationType

  • ProcessingID

  • ProcessingMode

  • QueryPriority

  • QueryResponse

  • QueryStatusCode

  • RelationalOperator

  • RelationshipConjunction

  • ResponseLevel

  • ResponseModality

  • RoleClass

  • RoleLinkType

  • RoleStatus

  • Sequencing

HDR Factories

This section contains the following topics:

Factories

Classes in this package provide factory methods for creating instances of the following data types and classes:

A reference to ServiceLocator is required to get an instance of each factory. Factories are thus tied to a specific HDR session, and should not be cached and reused across different login sessions.

Note:

Do not use Java's new operator to construct instances of HDR classes. Use factories instead— to ensure that RIM objects or data types that require a service locator for their operation will have access to one.

Data Type Factory

Because the Code System UID is mandatory on coded datatypes (CD, CE, CV), factory methods that do not include the code system UID (Example: methods that take the code system name instead) incur a performance penalty while the factory method requests the UID from ETS.

To achieve optimal performance, provide the code system UID explicitly. You can retrieve the complete mapping of code system names to UIDs by querying the corresponding ETS coding system.

Note:

You can also retrieve the complete mapping of code system names to UIDs in the following way:
  • For coding systems registered with HL7, an online OID Registry is provided as a free service by the HL7 website.

RIM Object Factories

You can create RIM objects through one of the three available factories: ActFactory, EntityFactory, or RoleFactory.

Each factory contains one generic factory method, for creating Act, Entity, and Role objects respectively:

  • ActFactory.newAct

  • EntityFactory.newEntity

  • RoleFactory.newRole

In addition, there are numerous convenience methods within each class for creating various subtypes of Acts, Entities and Roles.

Examples:

Example 7-4 Create RIM Observations Using the Generic Factory Method

DataTypeFactory dtf = DataTypeFactory.getInstance();
ActFactory af = ActFactory.getInstance(serviceLocator);
Observation observation = (Observation) af.newAct(ActClass.OBS, 
ActMood.EVN, dtf.nullCD(NullFlavor.NI), dtf.nullSET_II(NullFlavor.NI));

Example 7-5 Create RIM Observations Using the Convenience Factory Method

The following example illustrates the preferred method for creating RIM objects:

DataTypeFactory dtf = DataTypeFactory.getInstance();
ActFactory af = ActFactory.getInstance(serviceLocator);
Observation observation = af.newObservation(ActMood.EVN, dtf.nullCD(NullFlavor.NI),
dtf.nullSET_II(NullFlavor.NI));

Query Component Factory

See Also:

HDR Query for information about creating criteria and fetch objects using this factory, submitting them to RIM Service, and interpreting results returned.

Reference Modifiers

In addition to factory classes, the oracle.hsgbu.hdr.hl7.rim.factories package contains the ReferenceModifier class, a typed enumeration of all possible values for RIM class reference modifiers.

See Also:

Use RIM Services for information about how RIM service persistence uses ReferenceModifier values.

HDR Query

The query framework provides a RIM-like Java interface to retrieve data from the HDR repository. This document introduces constructs and features included with the query framework to retrieve information.

At the high level, a query is defined in terms of fetch and criteria objects. A fetch corresponds to a request for a certain type of information (for example, an ActFetch is a request for act information). Fetches are used in combination with criteria, which specify conditions objects must meet if they are to be retrieved by the query. In SQL query terms, a fetch corresponds to the SELECT/FROM clause and the criteria to the WHERE clause.

The code samples below help you do the following:

Query Submission Diagram Conventions :

  • Fetches are represented by red boxes.
  • Criteria are represented by boxes that correspond to standard RIM diagram colors for their object type.

  • Text adjacent to links distinguishes between link types where necessary (such as Player vs Scoper).

Scenario

This scenario illustrates the following query fundamentals:

  • Submitting a query.

  • Combining fetches and criteria to retrieve data.

  • Resulting object graph and the fetch graph symmetry.

  • Navigating object graph results.

Figure 7.5.1 describes how to retrieve a patient (including the playing entity) based on the patient id. The following information must be retrieved:

  • The patient role with the id attribute.

  • The playing person entity with the name, address, birth time and administrative gender code attributes.

Figure 7-1 Scenario Description

Surrounding text describes Figure 7-1 .

Fetches

A fetch is a request for information. Queries consist of one or more connected fetches that request some combination of Act, ActRelationship, Participation, Entity and Role data. These sections describe important fetch functions used in querying:

Flexible Retrieval

Flexible retrieval is the ability to specify a subset of attributes to retrieve in a query. This lets you optimize performance by retrieving only the data necessary to satisfy application requirements. For each fetch there are several retrieve<AttributeName>(boolean bool) methods that can be used to specify which attributes should be retrieved.

Example 7-6 Retrieve the Patient Id

The following code line requests the retrieval of the patient id:

patRoleFetch.retrieveId(true);

By default, no attributes are retrieved so you must call the appropriate retrieve method for all of the attributes you require. For convenience, fetches include a retrieveAll() method that specifies that all attributes of the class should be retrieved. There is also a retrieveNone() method that acts in reverse to the retrieveAll() method. The retrieve methods used by a fetch specify the minimum set of data that the system must retrieve to fulfill the query; the platform may retrieve additional data beyond that requested.

Set Criteria on Fetches

Criteria are used in combination with fetches to constrain the data retrieved by a query. You can associate criteria with a fetch in two ways:

  • Pass the criteria as a parameter to the factory method for the fetch. Each fetch factory method is overloaded to accept a criteria object of the corresponding HL7 type (Example 7-16).

  • Call setTopLevel<HL7Class>Criteria, which associates a criteria with a preexisting fetch.

Note:

Use of either method (Examples 7-16, 7-17) is discretionary; there is no functional difference between the two methods.

Example 7-7 Construct Patient Role

In the introductory scenario the patient role fetch was constructed with the role criteria using the following code line:

RoleFetch patRoleFetch = queryComponentFactory.newRoleFetch(patRoleCriteria);

Associating Patient Role Criteria with Role Fetch: Each fetch has a setTopLevel<HL7Class>Criteria(...) method that associates criteria with a pre-constructed fetch.

Example 7-8 Associate Patient Role Criteria with Role Fetch

To associate the patient role criteria with a pre-constructed role fetch, use the following code:

RoleFetch patRoleFetch = queryComponentFactory.newRoleFetch();patRoleFetch.setTopLevelRoleCriteria(patRoleCriteria);

Add Detail Fetches

Fetches can be linked together to retrieve related Act, ActRelationship, Participation, Role and Entity data in a single query. The added fetches are called detail fetches. Detail fetches behave like normal fetches allowing specific attributes to be retrieved and criteria to be specified, but they only retrieve data associated with their master.

Detail fetches are added using the add<RelatedObject>Fetch(...) APIs on the fetch class. These APIs are specific to each fetch to restrict the query results to a RIM consistent structure. As the API name suggests, it is possible to add multiple detail fetches of the same type to a master, each having their own set of attributes to retrieve, with their own criteria. This lets you group detail objects by criteria. For example, you can retrieve the subject participations and attending physician participations of an act separately by adding two participation detail fetches (one with criteria for subject participations and the other with criteria for the attending physician participations) to the main act fetch.

Detail fetches also play an important role in navigating the result graph, as every result object is related to the fetch that caused it to be retrieved.

Note:

Navigate the Result Graph for more information about detail fetches.

Incremental Fetches

The query framework has a pseudo-incremental fetch mechanism that lets you retrieve blocks of results by a fetch. This is useful to improve query response time and to page through results when processing large result sets.

Developers specify the size of the result set (window size) required using the setRetrievalWindow(int first, int last) API on the top level fetch. To implement a paging solution, submit the same fetch graph to the RimService multiple times modifying the retrieval window accordingly. To ensure that subsequent queries return consistent results, you should apply an ordering directive on the fetch (described in the next section). Sample code demonstrating a paging solution follows the ordering fetch results discussion (see Example 7-18 ).

Note:

Read consistency is not guaranteed between calls. If data that matches the query criteria is persisted between subsequent fetches the newly persisted data is retrieved.

Order Fetch Results

To facilitate incremental fetching, the query framework lets you order results in ascending or descending order of a subset of attributes. This is to ensure that the result set is ordered, so that subsequent incremental fetch results are consistent.

Specify the set of ordering attributes by using the addOrderBy(String attribute, int order API on the top level fetch. Results can be ordered by a restricted set of attributes represented by constants in QueryComponentFactory (look for ORDER_BY_<ATTRIBUTE_NAME> constants).

Example 7-9 Incremental Fetch / Ordering

The following example illustrates how to use the incremental fetch and ordering features of the query framework to retrieve ten acts at a time:

// create Act fetch and criteria
   // order the fetch by 1 or more orderable act attributes
   actFetch.addOrderBy(QueryComponentFactory.ORDER_BY_ACT_EXISTENCE_TIME_LOW, 
    QueryComponentFactory.ORDER_BY_ASCENDING);
   // set the intial window size
   actFetch.setRetrievalWindow(1, 10);
   // execute the query
   Iterator firstTenResults = rimService.queryActs(serviceLocator, actFetch);
   // display first 10 results
   ...
   // set the next window size
   actFetch.setRetrievalWindow(11, 20);
   // execute the results
   Iterator secondTenResults = rimService.queryActs(serviceLocator, actFetch);
   // display second 10 results
   ...

Cyclic (Recursive) Fetches

Fetches can be linked in cycles to retrieve data that is recursively related. This lets you avoid coding individual fetches for each component in the recursive relationship. This is particularly useful for retrieving a series of related acts.

Figure 7-2 Cyclic Recursive Fetches

Description of Figure 7-2 follows
Description of ''Figure 7-2 Cyclic Recursive Fetches''

Figure 7-2 illustrates how cyclic fetches can be used to retrieve an entire chain of acts, avoiding the need to code an entire chain of fetch/criteria objects:

Note:

Exercise care when using this feature; the query response time and memory consumption is relative to the depth of recursion and there is no mechanism to restrict the level of results retrieved. If you have data that exists in a deeply recursive structure and you only want to recurse to a certain level it may be better to explicitly code the expanded fetch graph rather that use the cyclic fetch functionality.

Criteria

Query criteria are used to specify conditions HL7 objects must satisfy to be retrieved by a particular query–a criteria graph is analogous to the WHERE clause in a SQL Select statement.

Criteria exist for the main HL7 objects (Acts, ActRelationships, Participations, Roles and Entities) as well as the more complex datatypes that provide a high degree control in restricting the data being retrieved.

There are two fundamental types of criteria:

  • Attribute criteria, which let you set restrictions on attributes such as an Act class code.

  • Connective criteria, which allow attribute criteria to be ANDed and ORed together to construct more complex conditions.

Criteria described in further detail:

Attribute Criteria

AttributeCriteria are used to specify conditions that object attributes must satisfy to be retrieved by a query. Specific criteria classes exist for the core HL7 objects and for datatypes where necessary. The criteria classes provide a combination of query-by-criteria (QBC) and query-by-example (QBE) APIs depending upon the type of attribute. The following table lists all of the attribute types and indicates whether a QBE or QBC interface is exposed for each type:

Attribute Types
Query-by-Example Types Query-by-Criteria Types
BL AD
CS ADXP
CD/CE CD/CE
II EN
INT ENXP
REAL GTS
ST IVL<DATATYPE>
TS MO
URL PQ
RTO<DATATYPE, DATATYPE>  
SC  
TEL  
ED  

Query-by-Example (QBE) APIs

Query-by-example interfaces are provided for attributes where constraints can be adequately specified using an example datatype. The following attribute types fall into this category:

  • BL

  • CS

  • CD

  • CE

  • II

  • INT

  • REAL

  • ST

  • TS

  • URL

Where the attribute is represented by a single datatype the interface has the following form:

public void set<AttributeName>(SearchOperator op, <DataType> value);

where SearchOperator is one of the following:

  • EQUALS

  • NOT_EQUALS

  • GREATER_THAN

  • LESS_THAN

  • GREATER_THAN_OR_EQUAL

  • LESS_THAN_OR_EQUAL

  • IS_NULL

  • IS_NULL

  • IS_NOT_NULL

  • LIKE

  • NOT_LIKE

Example 7-10 Using QBE API to Set Class Code Criteria

The following code sample illustrates the usage of this style of API for setting a class code criteria for an entity:

entityAttributeCriteria.setClassCode(SearchOperator.EQUALS, EntityClass.PSN);

The following interface is exposed for set based attributes (SET<CS>, SET<CD>, SET_II etc):

public void set<AttributeName>(SetSearchOperator op, <DataType>[] values);

The following special operators are provided to support set based searching: ALL and ANY. The ALL operator is used to specify that the target search object must have all of the values passed in the array type. The ANY operator means that the object must have at least one of the values passed in the array to match.

Example 7-11 Using QBE API to Set Instance Identifier Criteria

The following code sample illustrates typical usage of this form of API when setting Instance Identifier criteria for an object:

II[] patientIIs = new II[1];
...
 
patientIIs[0] = dataTypeFactory.newII(dataTypeFactory.newUID("ROOT"),
                                         dataTypeFactory.newST("EXTENSION"),
                                         dataTypeFactory.newBL(true));
   patRoleCriteria.setId(SetSearchOperator.ANY, patientIIs);

Query-by-Criteria (QBC) APIs

Query-by-Criteria interfaces are provided for attributes represented by complex datatypes-those where using an example datatype to specify a constraint is not flexible enough to meet common uses. For example, there is a criteria interface for EN attributes because it consists of a set of use codes (SET<CS>), a list of name parts (LIST<ENXP>), a formatted string (ST), and a valid time (IVL<TS>, all of which require individual constraints to be set in various use cases. This cannot be specified with a QBE interface. The attribute sets that fit into this category are represented by the following datatypes:

  • AD

  • ADXP

  • ED

  • EN

  • ENXP

  • GTS

  • IVL<INT>

  • IVL<MO>

  • IVL<PQ>

  • IVL<REAL>

  • IVL<TS>

  • MO

  • PQ

  • RTO<MO,PQ>

  • RTO<PQ>

  • SC

  • TEL

...where the attribute is represented by a complex datatype the interface has the following form:

public void set<AttributeName>Criteria(<Datatype>Criteria criteria);

The API differs from the QBC interface for complex datatypes by accepting a versioning type parameter. This is used to specify whether the neighboring criteria should be applied to the version that is directly related to the master object (version dependent), or to any version of the detail object (version independent). Versioning and query are discussed in more detail in Versioning and Query.

CodedTypeCriteria APIs

You can use CodedTypeCriteria expose functionality, in the API, to query by qualifiers, classifications, and equivalence. Classifications and equivalence are defined in ETS (Enterprise Terminology Services). You can combine three types of queries using ConnectiveCriteria. You can apply only one type of query on any single Criteria object.

Querying-by-Qualifiers

Queries on CD.qualifier follow the Query-by-Criteria pattern described in the Criteria section. The following operators can be used for qualifier queries:

  • SearchOperator.IS_NULL

  • SetSearchOperator.ANY

  • SetSearchOperator.NONE

  • SetSearchOperator.ALL

CodedTypeAttributeCriteria.includeEquivalentCodes(boolean, String, boolean) cannot be used with the CodedTypeAttributeCriteria.setQualifier(SearchOperator, CR[]) method.

CodedTypeAttributeCriteria codedTypeCriteria = queryComponentFactory.newCodedTypeAttributeCriteria();

// use the DataTypeFactory to instantiate the data types

codedTypeCriteria.setCode(parentCode);
codedTypeCriteria.setCodeSystem(parentCodeSystem);
codedTypeCriteria.setQualifier(SearchOperator.IS_NULL, new CR[] { } );

// null values are passed in for the II, the StatusCode and the CurrentVersionFlag, because we are not
// querying using these attributes

RoleAttributeCriteria roleCriteria = queryComponentFactory.newRoleAttributeCriteria(RoleClass.ACCESS, roleCode, null, null, null);

roleCriteria.setTargetSiteCode(codedTypeCriteria);
RoleFetch roleFetch = queryComponentFactory.newRoleFetch(roleCriteria);
roleFetch.retrieveAll();

Iterator fetchedRoles = rimService.queryRoles(localServiceLocator, roleFetch);

Querying-by-Classifications

Classification queries are constructed using ClassificationCriteria, which is a subclass of CodedTypeCriteria. Only ClassificationAttributeCriteria.setCode(ST) applies to a query by classification. Other methods inherited from CodedTypeAttributeCriteria are not applicable. This is because the value is predetermined to be one appropriate to the code system that contains classifications or because the method does not apply to this type of query.

ClassificationAttributeCriteria classificationCriteria = qcf.newClassificationAttributeCriteria();

// Set the classification code; no code system is needed because classifications are all

// stored in a specific code system that is known to the system.

classificationCriteria.setCode(classificationCode);

ActAttributeCriteria actCriteria = this.queryComponentFactory.newActAttributeCriteria();

actCriteria.setCode(codedTypeAttrCriteria);

actCriteria.setId(SetSearchOperator.ALL, ii);

ActFetch actFetch = this.queryComponentFactory.newActFetch(actCriteria);

actFetch.retrieveAll();

Iterator fetchedActs = rimService.queryActs(localServiceLocator, actFetch);

Querying-by-Equivalence

Equivalence queries must use CodedTypeAttributeCriteria.includeEquivalentCodes(boolean, String, boolean) method. These queries must specify a code and code system. The setQualifierMethod(SearchOperator, CR[]) method cannot be invoked on a CodedTypeAttributeCriteria instance where includeEquivalentCodes(..) has been called.

CodedTypeAttributeCriteria codedTypeAttrCriteria = this.queryComponentFactory.newCodedTypeAttributeCriteria(); codedTypeAttrCriteria.setCode(actCode); codedTypeAttrCriteria.setCodeSystem(actCodeSystem); codedTypeAttrCriteria.includeEquivalentCodes(true, null, true); ActAttributeCriteria actCriteria = this.queryComponentFactory.newActAttributeCriteria(); actCriteria.setCode(codedTypeAttrCriteria); actCriteria.setId(SetSearchOperator.ALL, ii);

ActFetch actFetch = this.queryComponentFactory.newActFetch(actCriteria); actFetch.retrieveAll(); Iterator fetchedActs = rimService.queryActs(localServiceLocator, actFetch);

Implicit AND Behavior for Attribute Criteria

When multiple criteria are set on an instance of an AttributeCriteria (regardless of the type), they are implicitly ANDed together. For example, see Example 7-21:

Example 7-12 Implicit AND Behavior: Restricting Retrieved Results

In this code sample, the retrieved results are restricted to those Acts that have a ...

actAttributeCriteria.setMoodCode(SearchOperator.EQUALS, ActMood.EVN);
...
ctAttributeCriteria.setClassCode(SearchOperator.EQUALS, ActClass.OBS);

ConnectiveCriteria can be used to build more complex criteria where ANDs and ORs can be used.

Connective Criteria

Connective criteria are used to AND and OR attribute criteria together, permitting more complex queries to be constructed. You must use connective criteria with attribute criteria of the same type. For example, you can use an ActConnectiveCriteria to AND/OR multiple Act criteria (attribute or connective) together. You should exercise care with regard to the level the connective is applied; otherwise the results may not be what you expected.

Figure 7-3 Retrieve active encounter event and observation event Acts: Example 1:

Surrounding text describes Figure 7-3 .

Figure 7-3 illustrates the use of connective criteria. In this example, two equivalent fetch diagrams show that the same result can be achieved in different ways. In the first diagram, an OR connective is used between two act attribute criteria to fetch the required results. The result of the query will be the union of the results returned by the execution of the two attribute criteria independently. The criteria on the left retrieves all active encounter event acts, and the criteria on the right retrieves all active observation events. The resulting set of retrieved acts will be the union of the two sets.

The second diagram is semantically equivalent but achieves the result using a combination of AND and OR connectives. The left side of the AND connective retrieves all active acts in EVN mood and the right side retrieves all acts of class ENC or OBS. The end result is the intersection of the two individual sets-all active encounter and observation events.

Figure 7-4 Retrieve encounter events that have a subject participation to an identified patient role with an attending participation to an identified employee role: Example 2:

Surrounding text describes Figure 7-4 .

As in Example 1, you must exercise care to ensure that the connective is made at the correct level.

Figure 7-4 shows two branches of criteria connected at the top level by an AND connective. The result of the query will be the intersection of the results returned by the execution of the two branched independently. The left branch retrieves all encounter events that have an SBJ participation to a PAT role. The right branch retrieves all encounter events that have an ATND participation to an EMP role.

Figure 7-5

Surrounding text describes Figure 7-5 .

Figure 7-5 shows a typical mistake of specifying the above criteria with the connective at the participation level. Logically this can be thought of as asking for encounter events that have a participation with a class code of SBJ and ATND-an impossible construct that returns no results.

Navigate the Result Graph

Complex queries that consist of several fetches return a RIM object structure that replicates the fetch graph that was submitted (assuming that existing data matches the criteria specified). The core RIM classes contain specific APIs that let you navigate from the master object to its related details. The following table lists the complete set of core RIM navigational APIs:

Core RIM Navigational APIs

Class Navigational API Description
Act getParticipations(...) Returns act participations fetched by a detail participation fetch.
getIBActRelationships(...) Returns inbound act relationships fetched by a detail inbound act relationship fetch.
getOBActRelationships(...) Returns outbound act relationships fetched by a detail outbound act relationship fetch.
ActRelationship getSource(...) Returns the source act that was fetched by a detail act fetch.
getTarget(...) Returns the target act that was fetched by a detail act fetch.
Participation getAct(...) Returns the act that was fetched by a detail act fetch.
getRole(...) Returns the role that was fetched by a detail role fetch.
Role getParticipations(...) Returns participations fetched by a detail participation fetch
getPlayerEntity(...) Returns entities fetched by a detail player entity fetch
getScoperEntity(...) Returns entities fetched by a detail scoper entity fetch
Entity getPlayedRoles(...) Returns roles fetched by a detail played role fetch
getScopedRoles(...) Returns roles fetched by a detail scoped role fetch
getOwnedPlayedRoles(...) Returns roles fetched by a detail owned played role fetch
getOwnedScopedRoles(...) Returns roles fetched by a detail owned scoped role fetch

Note:

Fetches have additional navigation methods for HDR extensions such as control act and merge navigations, discussed in HDR RIM Extensions.

Two types of navigational APIs provide flexibility when navigating the result graph. The simplest form accepts no parameters and returns all details retrieved regardless of which particular fetch was responsible for the result being retrieved.

The overloaded form accepts a fetch parameter and returns results directly related to the execution of the detail fetch passed in. This API is used when multiple detail fetches of the same type are added to a fetch.

For example, to retrieve an act, subject and attending physician participations you could have an act fetch and add separate subject and attending physician participation fetches. To navigate from the act to the participations, you can retrieve both concurrently by calling the no parameter getParticipations method, or you can access each participation individually by calling the navigation method that takes a participation fetch parameter passing in the particular fetch.

Figure 7-6

Surrounding text describes Figure 7-6 .

Figure 7-6 illustrate Fetch and Result Graphs.

HDR RIM Extensions

Versioning and Query

The query framework provides several APIs on the core fetch and criteria classes that let you fetch particular versions of objects and specify criteria on the different object versions. These APIs are described below.

Versioning and Fetches

In the context of fetches, the versioning behavior determines whether all versions or the referenced version of a detail object are retrieved by a detail fetch. The version of a detail object to retrieve is specified on the detail fetch by using the fetch factory methods (on QueryComponentFactory) that accept a versioning parameter. The QueryComponentFactory defines two versioning constants to be used with the following factory methods:

  • QueryComponentFactory.VERSION_DEPENDENT

  • QueryComponentFactory.VERSION_INDEPENDENT

It is possible to use the same factory methods to construct the top level fetch. However, the versioning constant supplied is ignored as it only applies to detail fetches. To specify particular versions for the top level fetch you must set the version on the criteria for that fetch.

Note:

By default, navigations are version dependent. Detail navigations that retrieve a single object, such as Participation to Role, return an undefined version of the detail object unless a specific version is requested (via a criteria with setCurrentVersion(...) or setVersionNum(...) methods).

Versioning and Criteria

The core attribute criteria classes provide APIs for specifying particular versions of objects as well as versions of detail objects. These APIs are described in the following sections.

Retrieving the Current Version

To restrict retrieval to the most current version of an object you can use the following AttributeCriteria method:

setCurrentVersion(boolean currentVersionFlag);

This method, combined with a version independent detail navigation, effectively retrieves the most current version of a related object. Alternatively, this method can be used to retrieve all but the current version of an object by passing false as the argument.

Retrieving a Specific Version

To retrieve a specific version of an object, use the following API:

setVersionNum(int versionNumber);

As with any other criteria specified, if the version specified does not exist no results are returned.

Detail Criteria Versioning Behavior

The criteria setters for neighboring core objects accept a versioning parameter that specifies whether the detail criteria is applied to the referenced version or any version of the detail object.

Detail Fetches

Assuming patient role version 1 and both versions of the player entity match the criteria, to retrieve patient and person information a detail player entity fetch is attached to the role fetch. When constructing the entity fetch you can specify either the VERSION_DEPENDENT or VERSION_INDEPENDENT constant for the versioning parameter (provided you use the EntityFetch newEntityFetch(EntityCriteria criteria, int versioningType) API on QueryComponentFactory). If you construct the entity fetch with the VERSION_DEPENDENT constant the person directly linked to the role is returned–in this case, version 1 of the person. If you construct the entity fetch with the VERSION_INDEPENDENT constant the current version (version 2) of the person is returned.

Detail Criteria

Assuming you have a role criteria that matches version 1 of the patient role, you can add a detail player entity criteria and specify either the VERSION_DEPENDENT orVERSION_INDEPENDENT constant for the versioning parameter. If you added a detail player entity criteria that matched person entities with name John Smith, the role would only be fetched if its playing entity has that name.

ControlAct Querying

You can retrieve or base queries on the ControlAct associated with an object using methods in the fetch and criteria interfaces. To fetch the creating/updating ControlAct, add a detail fetch using the following API:

addControlActFetch(ActFetch actFetch);

To specify criteria based on the creating or updating ControlAct, add a dependent criteria using the following API:

setControlActCriteria(ActCriteria actCriteria);

Both of these APIs work in the same way as other dependent fetch/criteria setter methods except that they exclude any versioning behavior; there is only one version of ControlActs associated with a particular version of an object.

Person Merge Querying

Person merge is the ability to collate data from a number of person entities (typically entered in different systems) into a single person that contains the superset of data. The single entity at the end of a potential chain of merges is typically called the ultimate survivor and the group of entities involved in a set of merge operations (including the ultimate survivor) is called the merge peers group.

The query framework exposes methods on the entity fetch and criteria classes that let you fetch and specify criteria for the merge group. To fetch members of the merge group, add a detail fetch using the following API:

addMergePeersEntityFetch(EntityFetch fetch);

To specify criteria for the merge group, add a detail criteria using the following API:

setMergePeersCriteria(EntityCriteria entityCriteria);

The EntityAttributeCriteria class also contains the following method that lets you specify whether or not the entity is the ultimate survivor of a merge:

setUltimateSurvivor(boolean ultimateSurvivor);

The ultimate surviving person of a set of potential merges can be found efficiently by combining the merge peers navigation with the setUltimateSurvivor(...) criteria specification.

Example 7-13 Retrieve Ultimate Survivor of an Entity

The following example shows how to retrieve the ultimate survivor of an entity:

// create the ultimate survivor fetch and criteria
   EntityAttributeCriteria ultimateSurvivorCriteria = mQueryComponentFactory.newEntityAttributeCriteria();
   ultimateSurvivorCriteria.setUltimateSurvivor(true);
   EntityFetch survivorFetch = mQueryComponentFactory.newEntityFetch(ultimateSurvivorCriteria, 
    QueryComponentFactory.VERSION_INDEPENDENT);
   survivorFetch.retrieveId(true);
 
   // create the fetch and criteria for an entity that has been merged
   EntityAttributeCriteria entityACriteria = mQueryComponentFactory.newEntityAttributeCriteria();
   entityACriteria.setCurrentVersion(true);
   entityACriteria.setId(SetSearchOperator.ANY, new II[]{sEntityAII});
   EntityFetch entityAFetch = mQueryComponentFactory.newEntityFetch(entityACriteria);
   entityAFetch.retrieveId(true);
 
   // add the ultimate survivor fetch
   entityAFetch.addMergePeersEntityFetch(survivorFetch);

Owned Roles

Owned roles are a HDR extension to the RIM that lets your create roles that do not directly participate in an act (the role is linked to or owned by an entity). The query framework supports the retrieval of owned roles specifically through detail fetch and criteria methods in the entity fetch and criteria classes respectively. To fetch an owned role, add a detail fetch to an EntityFetch using the following API:

addOwned<Played/Scoped>RoleFetch(RoleFetch ownedplayedroleFetch);

To specify criteria for an owned role, add a detail criteria using the following API:

setOwned<Played/Scoped>RoleCriteria(RoleCriteria roleCriteria, int versioningType);

Note:

The query framework does not distinguish between typical roles and owned roles when the standard fetch and criteria APIs are used. In a role fetch where both normal and owned roles match the criteria they are all returned by the query. To return only owned roles you must use the detail fetch and criteria APIs on the entity fetch and criteria interfaces illustrated above.

Example 7-14 Patient Query by ID Code Sample

Find a person associated with a known patient Id, retrieving basic demographic information:

/**
 * Finds roles with the following attributes:
 * - class code = PAT
 * - id = id of the particular patient
 *
 * and must meet the following detail criteria:
 *
 * 1. be played by a PSN entity
 *
 * The query should return the patient, the player entity.
 *
 */
package oracle.hsgbu.hdr.sample.scenarios;
 
 
import java.io.IOException;
import oracle.hsgbu.hdr.exception.HDRRimException;
import oracle.hsgbu.hdr.hl7.query.EntityAttributeCriteria;
import oracle.hsgbu.hdr.hl7.query.SearchOperator;
import oracle.hsgbu.hdr.hl7.query.EntityFetch;
import oracle.hsgbu.hdr.hl7.query.RoleAttributeCriteria;
import oracle.hsgbu.hdr.hl7.query.SetSearchOperator;
import oracle.hsgbu.hdr.hl7.query.RoleFetch;
import oracle.hsgbu.hdr.hl7.rim.domain.EntityClass;
import oracle.hsgbu.hdr.hl7.rim.domain.RoleClass;
import oracle.hsgbu.hdr.hl7.rim.factories.QueryComponentFactory;
import oracle.hsgbu.hdr.hl7.rim.factories.DataTypeFactory;
import oracle.hsgbu.hdr.hl7.rim.types.II;
import oracle.hsgbu.hdr.hl7.rim.Role;
import oracle.hsgbu.hdr.hl7.rim.Entity;
 
 
import java.util.Iterator;
import java.util.Properties;
import oracle.hsgbu.hdr.exception.CommonException;
import oracle.hsgbu.hdr.fwk.servicelocator.common.ServiceLocator;
 
public class PatientSearchById 
{
  public void executeScenario() throws HDRRimException, CommonException, IOException
  {
    ServiceLocator serviceLocator = getServiceLocator();  
    QueryComponentFactory queryComponentFactory = QueryComponentFactory.getInstance();
    DataTypeFactory dataTypeFactory = DataTypeFactory.getInstance();
    
    // create an EntityAttributeCriteria and specify that the class code should equal PSN
    EntityAttributeCriteria eCriteria = queryComponentFactory.newEntityAttributeCriteria();
    eCriteria.setClassCode(SearchOperator.EQUALS, EntityClass.PSN);
 
    // create a person Entity fetch with the PSN entity criteria and specify that the name, administrative gender 
    // code, birth time, code and addr attributes should be retrieved.
    EntityFetch entityFetch = queryComponentFactory.newEntityFetch(eCriteria, 
    QueryComponentFactory.VERSION_DEPENDENT);
    entityFetch.retrieveId(true);
    entityFetch.retrieveName(true);
    entityFetch.retrieveAdministrativeGenderCode(true);
    entityFetch.retrieveBirthTime(true);
    entityFetch.retrieveCode(true);
    entityFetch.retrieveAddr(true);
 
     // create the patient II which will be used in the role criteria
    II[] patientIIs = new II[1];
    patientIIs[0] = dataTypeFactory.newII(dataTypeFactory.newUID("1.2.3.4"),
                                          dataTypeFactory.newST("PAT_ROLE_1_II_EXT"),
                                          dataTypeFactory.newBL(true));
 
    // create an EntityAttributeCriteria and specify that the class code should equal PAT and that the id 
    // should be one of the id's in the II array
    RoleAttributeCriteria patRoleCriteria = queryComponentFactory.newRoleAttributeCriteria();
    patRoleCriteria.setClassCode(SearchOperator.EQUALS, RoleClass.PAT);
    patRoleCriteria.setId(SetSearchOperator.ANY, patientIIs);
 
    // create the patient Role fetch with the PAT role criteria and specify that the id should be retrieved
    RoleFetch patRoleFetch = queryComponentFactory.newRoleFetch(patRoleCriteria);
    patRoleFetch.retrieveId(true);
    patRoleFetch.retrieveClassCode(true);
 
    // link the person fetch to the patient fetch
    patRoleFetch.addPlayerEntityFetch(entityFetch);
 
    // submit the query
    Iterator patientRoles = serviceLocator.getRimService().queryRoles(serviceLocator, patRoleFetch);
 
    System.err.println("PatientSearchById Query Results:");
    System.err.println("********************************");
    for(;patientRoles.hasNext();)
    {
      Role patientRole = (Role)patientRoles.next();
      System.err.println("Role Id: " + patientRole.getId());
      System.err.println("Role Class: " + patientRole.getClassCode());
 
      Entity playerEntity = patientRole.getPlayerEntity(entityFetch);
      System.err.println("Entity Id: " + playerEntity.getId());
      System.err.println("Entity Version Number: " + playerEntity.getVersionNum());
      System.err.println("Entity Class Code: " + playerEntity.getClassCode());      
    }
  }
  
   private  ServiceLocator getServiceLocator() throws IOException, CommonException {
        Properties props = new Properties();
        props.load(this.getClass().getClassLoader().getResourceAsStream("jndi.properties"));
        return ServiceLocator.getInstance(props);
    }  
}

Example 7-15 Query for Identified Patient Roles and Player Entities

This code sample queries for new or active encounters admitted by a known staff member; retrieves the associated subject patient with basic demographics, as well as the location of the encounter:

/**
 * The roles must have the following attributes:
 * - class code = ENC
 * - mood code = EVN 
 * - status code = NEW or ACTIVE
 * - code = ??? 
 * - current version = true
 *
 * and must meet the following criteria:
 *
 * 1. have an ADM participation to either a EMP or ASSIGNED role where the role id is that of the staff practitioner 
 * 2. have an SUBJ participation to a PAT role played by a PSN entity 
 * 3. have a LOC participation to a SDLOC role
 *
 * The query should return the encounters along with the ADM, SUBJ and LOC participations
 * along with their corresponding roles and player entities.
 *
 */
 
package oracle.hsgbu.hdr.sample.scenarios;
 
import java.io.IOException;
import oracle.hsgbu.hdr.exception.HDRRimException;
import oracle.hsgbu.hdr.hl7.rim.types.II;
import oracle.hsgbu.hdr.hl7.rim.types.CD;
import oracle.hsgbu.hdr.hl7.query.RoleAttributeCriteria;
import oracle.hsgbu.hdr.hl7.query.SetSearchOperator;
import oracle.hsgbu.hdr.hl7.query.SearchOperator;
import oracle.hsgbu.hdr.hl7.query.ParticipationAttributeCriteria;
import oracle.hsgbu.hdr.hl7.query.ActAttributeCriteria;
import oracle.hsgbu.hdr.hl7.query.ActFetch;
import oracle.hsgbu.hdr.hl7.query.RoleFetch;
import oracle.hsgbu.hdr.hl7.query.ParticipationFetch;
import oracle.hsgbu.hdr.hl7.query.EntityAttributeCriteria;
import oracle.hsgbu.hdr.hl7.query.EntityFetch;
import oracle.hsgbu.hdr.hl7.query.ActCriteria;
import oracle.hsgbu.hdr.hl7.rim.domain.RoleClass;
import oracle.hsgbu.hdr.hl7.rim.domain.ParticipationType;
import oracle.hsgbu.hdr.hl7.rim.domain.ActClass;
import oracle.hsgbu.hdr.hl7.rim.domain.ActMood;
import oracle.hsgbu.hdr.hl7.rim.domain.ActStatus;
import oracle.hsgbu.hdr.hl7.rim.domain.EntityClass;
import oracle.hsgbu.hdr.hl7.rim.factories.QueryComponentFactory;
import oracle.hsgbu.hdr.hl7.rim.factories.DataTypeFactory;
import oracle.hsgbu.hdr.hl7.rim.Act;
import oracle.hsgbu.hdr.hl7.rim.Participation;
import oracle.hsgbu.hdr.hl7.rim.Role;
import oracle.hsgbu.hdr.hl7.rim.Entity;
 
import java.util.Iterator;
import java.util.Properties;
import oracle.hsgbu.hdr.exception.CommonException;
import oracle.hsgbu.hdr.fwk.servicelocator.common.ServiceLocator;
import oracle.hsgbu.hdr.hl7.rim.domain.NullFlavor;
 
public class EncountersByStaffPractitioner {
 
    public void executeScenario() throws HDRRimException, CommonException, IOException {
        ServiceLocator serviceLocator = getServiceLocator();
        QueryComponentFactory queryComponentFactory = QueryComponentFactory.getInstance();
        DataTypeFactory dataTypeFactory = DataTypeFactory.getInstance();
 
        // create the staff II which will be used in the role criteria
        II[] practitionerIIs = new II[1];
        practitionerIIs[0] = dataTypeFactory.newII(dataTypeFactory.newUID("1.2.3.4"),
                dataTypeFactory.newST("STAFF_ROLE_1_II_EXT"),
                dataTypeFactory.newBL(true));
 
        // practitioner role
        RoleAttributeCriteria rAssignedCriteria = queryComponentFactory.newRoleAttributeCriteria();
        rAssignedCriteria.setClassCode(SearchOperator.EQUALS, RoleClass.ASSIGNED);
        rAssignedCriteria.setId(SetSearchOperator.ANY, practitionerIIs); //Particular practitioner
        RoleAttributeCriteria rEmpCriteria = queryComponentFactory.newRoleAttributeCriteria();
        rEmpCriteria.setClassCode(SearchOperator.EQUALS, RoleClass.EMP);
        rEmpCriteria.setId(SetSearchOperator.ANY, practitionerIIs); //Particular practitioner
        RoleAttributeCriteria rCriteria = (RoleAttributeCriteria) queryComponentFactory.or(rAssignedCriteria, rEmpCriteria);
 
        // ADM participation
        ParticipationAttributeCriteria pCriteria = queryComponentFactory.newParticipationAttributeCriteria();
        pCriteria.setRoleCriteria(rCriteria, QueryComponentFactory.VERSION_INDEPENDENT);
        pCriteria.setTypeCode(SearchOperator.EQUALS, ParticipationType.ADM);
 
        // act criteria
        ActAttributeCriteria aCriteria = queryComponentFactory.newActAttributeCriteria();
        aCriteria.setCurrentVersion(true);
        aCriteria.setClassCode(SearchOperator.EQUALS, ActClass.ENC);
        aCriteria.setMoodCode(SearchOperator.EQUALS, ActMood.EVN);
 
        //    aCriteria.setCode(SearchOperator.EQUALS, actCd);
        aCriteria.setParticipationCriteria(pCriteria, QueryComponentFactory.VERSION_INDEPENDENT);
 
        // create an act criteria to retrieve new and active acts
        ActAttributeCriteria activeActStatus = queryComponentFactory.newActAttributeCriteria();
        activeActStatus.setStatusCode(SearchOperator.EQUALS, ActStatus.ACTIVE);
        activeActStatus.setClassCode(SearchOperator.EQUALS, ActClass.ENC);
        activeActStatus.setMoodCode(SearchOperator.EQUALS, ActMood.EVN);
        CD actCd = dataTypeFactory.newCD(dataTypeFactory.newST("AMB"),
                dataTypeFactory.nullUID(NullFlavor.NI), dataTypeFactory.newST("ActCode"), dataTypeFactory.nullST(NullFlavor.NI),
                dataTypeFactory.nullED(NullFlavor.NI));
 
        activeActStatus.setCode(SearchOperator.EQUALS, actCd);
        activeActStatus.setCurrentVersion(true);
        activeActStatus.setParticipationCriteria(pCriteria, QueryComponentFactory.VERSION_INDEPENDENT);
        ActAttributeCriteria newActStatus = queryComponentFactory.newActAttributeCriteria();
        newActStatus.setStatusCode(SearchOperator.EQUALS, ActStatus.NEW);
        newActStatus.setClassCode(SearchOperator.EQUALS, ActClass.ENC);
        newActStatus.setMoodCode(SearchOperator.EQUALS, ActMood.EVN);
        newActStatus.setCurrentVersion(true);
 
        newActStatus.setCode(SearchOperator.EQUALS, actCd);
        newActStatus.setParticipationCriteria(pCriteria, QueryComponentFactory.VERSION_INDEPENDENT);
        ActCriteria activeOrNewStatus = (ActCriteria) queryComponentFactory.or(activeActStatus, newActStatus);
 
        ActFetch actFetchMain = queryComponentFactory.newActFetch(activeOrNewStatus,
                QueryComponentFactory.VERSION_INDEPENDENT);
        actFetchMain.retrieveId(true);
 
        // Add location to a fetch
        RoleAttributeCriteria lrCriteria = queryComponentFactory.newRoleAttributeCriteria();
        lrCriteria.setClassCode(SearchOperator.EQUALS, RoleClass.SDLOC);
        RoleFetch lrFetch = queryComponentFactory.newRoleFetch(lrCriteria,
                QueryComponentFactory.VERSION_INDEPENDENT);
        lrFetch.retrieveId(true);
        lrFetch.addPlayerEntityFetch(queryComponentFactory.newEntityFetch());
        ParticipationAttributeCriteria lpCriteria = queryComponentFactory.newParticipationAttributeCriteria();
        lpCriteria.setTypeCode(SearchOperator.EQUALS, ParticipationType.LOC);
        ParticipationFetch lpFetch = queryComponentFactory.newParticipationFetch(lpCriteria,
                QueryComponentFactory.VERSION_INDEPENDENT);
        lpFetch.addRoleFetch(lrFetch);
 
        actFetchMain.addParticipationFetch(lpFetch);
 
        // Add patient to a fetch
        EntityAttributeCriteria eCriteria = queryComponentFactory.newEntityAttributeCriteria();
        eCriteria.setClassCode(SearchOperator.EQUALS, EntityClass.PSN);
        EntityFetch eFetch = queryComponentFactory.newEntityFetch(eCriteria);
        eFetch.retrieveName(true);
        eFetch.retrieveAdministrativeGenderCode(true);
        eFetch.retrieveBirthTime(true);
        eFetch.retrieveCode(true);
        RoleAttributeCriteria patRoleCriteria = queryComponentFactory.newRoleAttributeCriteria();
        patRoleCriteria.setClassCode(SearchOperator.EQUALS, RoleClass.PAT);
        RoleFetch patRoleFetch = queryComponentFactory.newRoleFetch(patRoleCriteria,
                QueryComponentFactory.VERSION_INDEPENDENT);
        patRoleFetch.retrieveId(true);
        patRoleFetch.addPlayerEntityFetch(eFetch);
        ParticipationAttributeCriteria patPartCriteria = queryComponentFactory.newParticipationAttributeCriteria();
        patPartCriteria.setTypeCode(SearchOperator.EQUALS, ParticipationType.SBJ);
        ParticipationFetch patPartFetch = queryComponentFactory.newParticipationFetch(patPartCriteria,
                QueryComponentFactory.VERSION_INDEPENDENT);
        patPartFetch.addRoleFetch(patRoleFetch);
 
        actFetchMain.addParticipationFetch(patPartFetch);
 
        Iterator fetchedActs = ServiceLocator.getInstance().queryActs(serviceLocator, actFetchMain);
 
        System.err.println("EncountersByStaffPractitioner Query Results:");
        System.err.println("********************************************");
        for (; fetchedActs.hasNext();) {
            Act fetchedAct = (Act) fetchedActs.next();
            System.err.println("Act class code: " + fetchedAct.getClassCode());
            System.err.println("Act mood code: " + fetchedAct.getMoodCode());
            System.err.println("Act status code: " + fetchedAct.getStatusCode());
 
            Iterator fetchedPatientParticipations = fetchedAct.getParticipations(patPartFetch);
            for (; fetchedPatientParticipations.hasNext();) {
                Participation fetchedPatientParticipation = (Participation) fetchedPatientParticipations.next();
                System.err.println("Participation type code: " + fetchedPatientParticipation.getTypeCode());
 
                Role fetchedPatientRole = (Role) fetchedPatientParticipation.getRole(patRoleFetch);
                System.err.println("Role class code: " + fetchedPatientRole.getClassCode());
 
                Entity fetchedPlayerEntity = fetchedPatientRole.getPlayerEntity(eFetch);
                System.err.println("Player entity class code: " + fetchedPlayerEntity.getClassCode());
            }
        }
    }
 
    private ServiceLocator getServiceLocator() throws IOException, CommonException {
        Properties props = new Properties();
        props.load(this.getClass().getClassLoader().getResourceAsStream("jndi.properties"));
        return ServiceLocator.getInstance(props);
    }
}

Original Coded Attributes

Coded attributes are commonly coerced into equivalent concepts during persistence into HDR. By default these coerced concepts are retrieved by Rim Query. You can retrieve the original data, using the oracle.hsgbu.hdr.hl7.util.CodedTypeUtility.getOriginalAttributes(CD) method.

Since qualifiers are not copied from original to coerced code, qualifiers can only be retrieved from CD datatypes that have been obtained via the getOriginalAttributes method.

See Also:

  • oracle.hsgbu.hdr.hl7 package for further information about HDR HL7 interfaces.

  • oracle.hsgbu.hdr.hl7.query package for further information about HDR Query interfaces.

DCTB Subqueries

The SQL queries generated by the RIM query API can be optimized in three different ways. By default, in all nested SELECT sub queries, the WHERE conditions will be generated as a SQL IN condition. This can be modified by configuring the HDR managed server start-up JVM argument CTB_SUBQRY_OPT_METHOD with one of the values NONE, EXISTS, or JOIN. Based on the database version and configuration, you can choose an option that results in the best database SQL execution plans for the HDR generated SQL queries.

-DCTB_SUBQRY_OPT_METHOD=NONE

This is the default behavior where all nested select sub queries in the where condition will be generated as the SQL IN condition.

For example, SELECT CtbCoreRolesEO.ROLE_ID, CtbCoreRolesEO.ROLE_VERSION_NUM FROM CTB_CORE_ROLES CtbCoreRolesEO WHERE CtbCoreRolesEO.CLASS_CODE = 'PAT' AND(CtbCoreRolesEO.PLAYER_ID, CtbCoreRolesEO.PLAYER_VERSION_NUM) IN ( SELECT CtbCoreEntitiesEO.ENTITY_ID, CtbCoreEntitiesEO.ENTITY_VERSION_NUM FROM CTB_CORE_ENTITIES CtbCoreEntitiesEO WHERE CtbCoreEntitiesEO.CLASS_CODE = 'PSN' AND CtbCoreEntitiesEO.DETERMINER_CODE = 'INSTANCE' AND CtbCoreEntitiesEO.ENTITY_ID IN ( SELECT CtbCoreEntyIIEO.ENTITY_ID FROM CTB_CORE_ENTY_II CtbCoreEntyIIEO WHERE CtbCoreEntyIIEO.ROOT_ID = '1.2.3' AND CtbCoreEntyIIEO.EXTENSION_TXT = 'Person1' ) ) ;

-DCTB_SUBQRY_OPT_METHOD=EXISTS

By setting sub-query optimization method to EXISTS, all nested select sub queries in the where condition will be generated as the SQL EXISTS condition.

For example, SELECT CtbCoreRolesEO.ROLE_ID, CtbCoreRolesEO.ROLE_VERSION_NUM FROM CTB_CORE_ROLES CtbCoreRolesEO WHERE CtbCoreRolesEO.CLASS_CODE = 'PAT' AND EXISTS ( SELECT 1 FROM CTB_CORE_ENTITIES CtbCoreEntitiesEO WHERE CtbCoreEntitiesEO.CLASS_CODE = 'PSN' AND CtbCoreEntitiesEO.DETERMINER_CODE = 'INSTANCE' AND CtbCoreEntitiesEO.ENTITY_ID = CtbCoreRolesEO.PLAYER_ID AND CtbCoreEntitiesEO.ENTITY_VERSION_NUM = CtbCoreRolesEO.PLAYER_VERSION_NUM AND EXISTS ( SELECT 1 FROM CTB_CORE_ENTY_II CtbCoreEntyIIEO WHERE CtbCoreEntyIIEO.ROOT_ID = '1.2.3' AND CtbCoreEntyIIEO.EXTENSION_TXT = 'Person1' AND CtbCoreEntyIIEO.ENTITY_ID = CtbCoreEntitiesEO.ENTITY_ID ) ) ;

-DCTB_SUBQRY_OPT_METHOD=JOIN

By setting sub-query optimization method to JOIN, all nested select sub queries in the where condition will be converted to the SQL JOIN condition.

For example, SELECT CtbCoreRolesEO1.ROLE_ID, CtbCoreRolesEO1.ROLE_VERSION_NUM FROM CTB_CORE_ROLES CtbCoreRolesEO1, CTB_CORE_ENTITIES CtbCoreEntitiesEO1, CTB_CORE_ENTY_II CtbCoreEntyIIEO1 WHERE CtbCoreRolesEO1.CLASS_CODE = 'PAT' AND CtbCoreEntitiesEO1.CLASS_CODE = 'PSN' AND CtbCoreEntitiesEO1.DETERMINER_CODE = 'INSTANCE' AND CtbCoreEntitiesEO1.ENTITY_ID = CtbCoreRolesEO1.PLAYER_ID AND CtbCoreEntitiesEO1.ENTITY_VERSION_NUM = CtbCoreRolesEO1.PLAYER_VERSION_NUM AND CtbCoreEntyIIEO1.ROOT_ID = '1.2.3' AND CtbCoreEntyIIEO1.EXTENSION_TXT = 'Person1' AND CtbCoreEntyIIEO1.ENTITY_ID = CtbCoreEntitiesEO1.ENTITY_ID;

HDR RIM Services

Core functions:

Use The RIM Service

The RimService provides the primary mechanism to persist or query Entities, Roles, Acts and related objects through HDR. Both persist and query operations are supported through the RimService.submit(ControlAct) method.

The control act passed to submit is expected to contain one outbound ActRelationship with a typeCode of SUBJ with an instance of a subclass of Act as its target, which can similarly be related to other objects to form a graph of objects to be persisted. If the target Act of the Act Relationship is an instance of a QueryAct, a data query results; see Section 7.5 for more information about querying.

These code samples help you to:

Example 7-16 Create an Organization Using a Registry Event

The following example illustrates the registration of an Entity—in this case an Organization is created. To create any Entity in HDR you must provide a Role and an Act; typically an AssignedEntity Role is used, and a RegistryEvent is used for the Act.

// Create the ORG Entity to be registered
        SET_II orgId = dataTypeFactory.newSET_II("9.989898.5.3.1", "ORG002", true);
        Organization organization = entityFactory.newOrganization(
            dataTypeFactory.nullCE(NullFlavor.NI), 
            EntityDeterminer.INSTANCE, orgId);    
 
        // Build up the organization name using
        SET<CS> orgNameUseCode= dataTypeFactory.newSET_CS(dataTypeFactory.newCS("L"));
        ENXP orgNameUsePart = dataTypeFactory.newENXP("Pro Health Systems", null, 
         dataTypeFactory.nullSET<CS>(NullFlavor.NI));
        ENXP[] orgNameUsePartArray = new ENXP[] {orgNameUsePart};
        ON orgName = dataTypeFactory.newON(orgNameUsePartArray, orgNameUseCode, 
         dataTypeFactory.nullIVL<TS>(NullFlavor.NI));
 
        // Set the organization name, desc and status
        organization.setName(dataTypeFactory.newBAG<EN>(orgName));
        organization.setStatusCode(EntityStatus.ACTIVE);
 
        // build a TEL type and addto the telecom attribute.
        SET<CS> orgTelUseCode= dataTypeFactory.newSET_CS(dataTypeFactory.newCS("H"));
        TEL orgTel = dataTypeFactory.newTEL("tel", "1-510-555-1234", 
         dataTypeFactory.nullGTS(NullFlavor.NI),orgTelUseCode);
        organization.addTelecom(orgTel);
 
        // build an ADXP type and add the address
        ADXP adxp1 = dataTypeFactory.newADXP("100 Oracle Parkway", dataTypeFactory.newCS("SAL")); 
        ADXP adxp2 = dataTypeFactory.newADXP("Redwood Shores", dataTypeFactory.newCS("CTY"));
        ADXP adxp3 = dataTypeFactory.newADXP("CA", dataTypeFactory.newCS("STA")); 
        ADXP adxp4 = dataTypeFactory.newADXP("94065", dataTypeFactory.newCS("ZIP"));
        ADXP adxp5 = dataTypeFactory.newADXP("US", dataTypeFactory.newCS("CNT"));
 
        ADXP[] addrPartArray = new ADXP[] {
            adxp1,
            adxp2,
            adxp3,
            adxp4,
            adxp5
        };
 
        AD addr = dataTypeFactory.newAD(addrPartArray,
            dataTypeFactory.newSET<CS>(dataTypeFactory.newCS("WP")), 
                dataTypeFactory.nullGTS(NullFlavor.NI));
        
        organization.addAddr(addr);
 
        // Create an ASSIGNED Role for the organization, 
        // with the organization as the player
        // CD roleCode = dataTypeFactory.newCD("000172","HDR Supplemental");
        SET_II assignedRoleId = dataTypeFactory.newSET_II("9.989898.5.49.1", "ASSIGNED0002", true);
        Role role = 
         roleFactory.newAssignedEntity(dataTypeFactory.newCE("000174","2.16.840.1.113894.1004.100.100.2.5"), 
        organization, null, assignedRoleId);
        
 
        // Create the registry act. Registry acts are used to denote a
        // registration of a Role or Entity, in this case an ORG Entity.
        // The registry act will later be associated with the control act
        // using an act relationship
        SET_II regActId = dataTypeFactory.newSET_II("9.989898.5.42.1", "REG0012", true);
        Act regAct  = actFactory.newRegistryAct(ActMood.EVN, dataTypeFactory.nullCD
         (NullFlavor.NI), regActId);
 
        // Create a "SBJ" Participation between the registry act
        // and the identified role
        regAct.addParticipation(ParticipationType.SBJ, role);
 
        // Create the control act, providing an Id and a null trigger event
        SET_II ctrlActId = dataTypeFactory.newSET_II("9.989898.5.28.1", "CACT0012", true);
        ControlAct controlAct = actFactory.newControlActEvent(dataTypeFactory.nullCD
         (NullFlavor.NI), ctrlActId);
 
        // Create an outbound Act Relationship between the control act
        // and registry act
        controlAct.addOBActRelationship(ActRelationshipType.SUBJ, regAct);
 
        // Submit the control act. The returned control act will be
        // null unless a query act was specified in the act relationship
        // on the control act
        ControlAct returnedControlAct = rimService.submit(controlAct);

In addition to illustrating the basic structure of a submission, Example 7-16 highlights the following:

  • Construction of datatypes: AD, ADXP, CD, CS, ENXP, EN, II, ON, TEL.

  • Construction of sets of datatypes: SET_CS, SET_II.

  • Construction of NullFlavor objects as the appropriate datatype class.

  • Elements of Organizations that are necessary to pass TCA validation. For example: Organization Name use code of H; Telecom Scheme of TEL.

Reference Modifiers

In the prior example, all objects are newly created. To update an object, fetch it using the query mechanism and use the createNewVersion method to create a new version.

HDR also provides a mechanism to create a reference to an object that already exists and to permit an object to be created or updated without first querying the object. This is achieved by making a reference to an object using the ReferenceModifier class. This approach may also improve an application's performance because it eliminates the need to fetch the affected objects to the client tier prior to updating.

The simplest reference that can be created is the MustExist reference. A MustExist reference mandates that an object with a specified Instance Identifier has already been created. It is useful when creating ActRelationships or Participations to objects that have already been persisted.

Two other reference types worth discussing in more detail are the CreateOrOverlay and the CreateOrUpdate types. These reference types either create the object with the supplied attributes if it does not already exist, or they cause the creation of a new version of the object with attributes set in a manner consistent with the reference modifier used. For more information about the difference between the CreateOrOverlay and CreateOrUpdate methods, and for information about other reference types see the ReferenceModifier class description.

Example 7-17 Create an Encounter Using a CREATE_OR_UPDATE Reference to a Patient Object

// Create the Patient II
        SET_II patientId = dataTypeFactory.newSET_II("9.989898.5.2","PAT1001", true);
 
        // Use a Create Or Update reference for the Patient
        Patient patientRole = (Patient)roleFactory.makeReference(
            ReferenceModifier.CREATE_OR_UPDATE, RoleClass.PAT, 
            dataTypeFactory.nullCE(NullFlavor.NP),
            null, null, patientId, 0);
 
        // Create the Patient Encounter Event (Class Code:ENC)
        // The Encounter will later be associated with the control act
        // using an act relationship
        SET_II encActId = dataTypeFactory.newSET_II("9.989898.5.6.100","ENC1001", true);
 
        // Use "ActCode" for the codingscheme; UID is 2.16.840.1.113883.5.4
        Act encAct  = actFactory.newPatientEncounter(ActMood.EVN, 
            dataTypeFactory.newCD("IMP","2.16.840.1.113883.5.4"), encActId);
 
        // Create a "SBJ" Participation between the registry act
        // and the identified role
        encAct.addParticipation(ParticipationType.SBJ, patientRole);
 
        // Create the control act, providing an Id and a null trigger event
        SET_II ctrlActId = dataTypeFactory.newSET_II
            ("9.989898.5.28", "CACT001032", true);
        ControlAct controlAct = actFactory.newControlActEvent(
            dataTypeFactory.nullCD(NullFlavor.NP), ctrlActId);
 
        // Create an outbound Act Relationship between the control act   
        // and registry act
        controlAct.addOBActRelationship(ActRelationshipType.SUBJ, encAct);
 
        // Submit the control act. The returned control act will be
        // null unless a query act was specified in the act relationship
        // on the control act
        ControlAct returnedControlAct = rimService.submit(controlAct);

Exception Handling

Invalid objects submitted in a graph cause HDR to bundle validation exceptions. These bundles consist of one exception per validation error; there may be multiple exceptions relating to an object. The exceptions contain methods to return the Ids of the related invalid object.

Example 7-18 Pass an Invalid Code to Generate an Exception

// Create the Patient Encounter Event (Class Code:ENC)
        // The Encounter will later be associated with the control act
        // using an act relationship
        SET_II encActId = dataTypeFactory.newSET_II("9.989898.5.6.100", "ENC1001", true);
 
        // UNKNOWN_CODE is expected to cause validation to fail
        Act encAct  = actFactory.newPatientEncounter(ActMood.EVN, 
        dataTypeFactory.newCD("UNKNOWN_CODE","2.16.840.1.113883.5.4"), encActId);
 
        // Create the control act, providing an Id and a null trigger event
        SET_II ctrlActId = dataTypeFactory.newSET_II("9.989898.5.28", "CACT001032", true);
        ControlAct controlAct = actFactory.newControlActEvent(dataTypeFactory.nullCD
         (NullFlavor.NP), ctrlActId);
 
        // Create an outbound Act Relationship between the control act
        // and registry act
        controlAct.addOBActRelationship(ActRelationshipType.SUBJ, encAct);
        try 
        {
            // Submit the control act. The returned control act will be
            // null unless a query act was specified in the act relationship
            // on the control act
            ControlAct returnedControlAct = rimService.submit(controlAct);
        }
        catch (HDRRimException e)
        {
            CommonException[] exceptions = e.getBundledExceptions();
            for (int i=0; i<exceptions.length; i++)
            {
                if(exceptions[i] instanceof RimObjectException)
                {
                    System.out.println(
                        ((RimObjectException)exceptions[i]).getIds());          
                }
            }
            e.printStackTrace();
        }

This code generates the following output:

{9.989898.5-34789202; 9.989898.5.6.100-ENC1001}

...where 9.989898.5-34789202 is the internal Instance Indicator created on all objects by HDR and 9.989898.5.6.100-ENC1001 is the II submitted with the Encounter object. Additionally, the full exception stack trace is< printed, and the exception details attributes that fail validation.

Example 7-19 Rim Validation Exception Output

oracle.hsgbu.hdr.exception.HDRRimException
CODE = CMN_001: Multiple exception occured while processing. Please see the individual exceptions for details.
MESSAGE = HDR_CMN_001: Multiple exception occured while processing. Please see the individual exceptions for details.
      [1] oracle.hsgbu.hdr.base.persist.exception.CorePersistenceValidationException
            CODE = HDR_CORE_UNKNOWN_CODE
            MESSAGE = HDR_CPS_PVE006: Unknown Code for attributeName:CODE, code:UNKNOWN_CODE, codeOid:2.16.840.1.113883.5.4, codeSystemName:null, codeVersionName:2.01.4 and token:EncounterEventResource
 
...
Child Exceptions:
 
oracle.hsgbu.hdr.exception.HDRRimException
CODE = HDR_CORE_UNKNOWN_CODE
MESSAGE = HDR_CPS_PVE006: Unknown Code for attributeName:CODE, code:UNKNOWN_CODE, codeOid:2.16.840.1.113883.5.4, codeSystemName:null, codeVersionName:2.01.4 and token:EncounterEventResource
            
Original Stacktrace:
HDR_CPS_PVE006: Unknown Code for attributeName:CODE, code:UNKNOWN_CODE, codeOid:2.16.840.1.113883.5.4, codeSystemName:null, codeVersionName:2.01.4 and token:EncounterEventResource
...
...

Use Master Catalog API

Master Catalog Entries

During persistence all Acts, Entities, and Role objects are validated against the Master Catalog. Master Catalog defines the ETS values for class code, mood code, determiner code, code, player entity, and/or scoper entity that are allowed for these objects. HDR supports three types of ETS values: (1) explicit values specifying the ID of the concept, (2) null values when no values are required, or (3) any value when all ETS concepts are valid.

To ensure that Master Catalog entries exist for all objects being persisted prior to submission, HDR provides APIs to query and create Master Catalog data.

HDR provides MasterCatalogService APIs to create, update, and query Master Catalog entries.

See Also:

  • Oracle Healthcare Data Repository Implementation Guide (Implementing Master Catalog) for more information about Master Catalog API.

Outbound Message Processor (OMP) uses the Masters Catalog identifiers to create the Act Concept Configuration; see section 10.2.1 for more details.

Concepts

Master Catalog entry defines constraints based on:

  • Act: Class Code, Mood Code and Code.

  • Entity: Class Code, Determiner Code and Code.

  • Role: Class Code, Code and the Player and Scoper Master Catalog IDs.

All Master Catalog entries define a code type—ID, ANY, or NULL.

  • ID: Code attribute of the entity should be a valid ETS concept code.

  • ANY: Code attribute of the entity should be null.

  • NULL: Code attribute of the entity should be null.

For all Master Catalog getXxx() search operations, if the codeType is ID, then the getXxx() operation goes by the following order of precedence:

  • Looks for the exact concept code.

  • If the exact code not found, it looks for equivalent concept code.

  • If equivalent concept code not found, it looks for code type ANY.

The Master Catalog supports concept equivalence. It considers a concept valid if it is equivalent to a concept used in an entry. You need not update the Master Catalog when new a coding scheme or version is loaded in ETS, provided equivalence information is also loaded with the new coding scheme or version. Concept equivalence is also used to verify whether user is trying to set up a duplicate Master Catalog entry. If one Master Catalog entry exists for a concept, no other entry with its equivalent concepts is permitted.

See Also:

  • Oracle Healthcare Data Repository API Documenation for more information about Master Catalog interfaces.
  • Oracle Healthcare Data Repository Implementation Guide for more information about Master Catalog validations.

Example 7-20 Check for the Existence of a Master Catalog Entry Matching the Control Act

// Find the Master Catalog Entry with parameters:
        // class code = CACT (From the ActClass Domain)
        // mood code = EVN (From the ActMood Domain)
        // code = null
        // code type = "NULL"
        MasterCatalog mc = masterCatalogService.getMasterCatalogActEntry(ActClass.CACT, ActMood.EVN, 
         null, "NULL");
        if (mc.getMasterCatalogId() != null)
        { 
            System.out.println("Master Catalog Record found. ID: " + mc.getMasterCatalogId());
        }
        else 
        {
              System.out.println("No Master Catalog Record found");
        }

Example 7-21 Check for the Existence of a Master Catalog Entry Matching the Person

// Find the Master Catalog Entry with parameters:
        // class code = PSN (From EntityClass Domain)
        // determiner code = INSTANCE (From EntityDeterminer Domain)
        // code = null
        // code type = "NULL"
        MasterCatalog mc = masterCatalogService.getMasterCatalogEntityEntry
         (EntityClass.PSN, EntityDeterminer.INSTANCE, null, "NULL");
        if (mc.getMasterCatalogId() != null)
              { 
            System.out.println("Master Catalog Record found. ID: " + mc.getMasterCatalogId());
              }
        else 
             {
             System.out.println("No Master Catalog Record found");
             }
 
 
 
       If suitable entries do not exist, use the persistMasterCatalog API to create one.

Example 7-22 Create a Master Catalog Entry for a Diagnostic Image

// Create a Master Catalog Entry with parameters:
      // class code = DGIMG (From the ActClass Domain)
      // mood code = EVN (From the ActMood Domain)
      // code = null
      // code type = "NULL"
      MasterCatalog mc = masterCatalogFactory.newMasterCatalog();
      mc.setClassCode(ActClass.DGIMG);
      mc.setCodeType(MasterCatalog.NULL_CODE_TYPE);
      mc.setMoodCode(ActMood.EVN);
      mc.setEntryTypeCode(MasterCatalog.ACT_ENTRY_TYPE_CODE);
      mc.setActiveFlag(true);
 
      masterCatalogService.persistMasterCatalogEntry(mc);

Example 7-23 Create an Array of Master Catalog Entries

You can create or update an array of MasterCatalog entries using MC bulk persists API. For each entry in array, the API checks, if it is a valid entry, as follows and persists it. In the case of one or more invalid entries, the API rejects all of them.

MasterCatalog mc1 = masterCatalogFactory.newMasterCatalog();
 MasterCatalog mc2 = masterCatalogFactory.newMasterCatalog();
 
// For each master catalog entry defined above, to set the values follow the steps described in Example 7-32.
 
//Create an array of mastercatalog with the above mentioned entries
MasterCatalog [] mcArray = new MasterCatalog [] {mc1,mc2};
 
//Call bulk persist method
 masterCatalogService.persistMasterCatalogEntries(mcArray);   

Example 7-24 Search Master Catalog Entries Using Query Criteria

You can retrieve MasterCatalog entries based on MasterCatalogQueryCriteria using this API, which takes the MasterCatalogQueryCriteria as the parameter. MasterCatalogQueryCriteria defines methods that can be used to build a query for retrieving MasterCatalog records based on the criteria.

// Defining the MasterCatalogQueryCriteria to find Master Catalog Entry, for code type = "ID" and coding scheme
// name = "HDR Supplemental", coding scheme version name = "HDR Supplemental (2005-04-08)" and concept code = "001827"
 
// get an instance of the Master Catalog Criteria 
 
MasterCatalogQueryCriteria masterCatalogSearchCriteria = masterCatalogFactory().newMasterCatalogQueryCriteria(); 
SearchTerm searchTerm = masterCatalogSearchCriteria.equalsCode("HDR Supplemental", "HDR Supplemental (2005-04-08)", "001827"); 
 
// set the code type to ID 
searchTerm = masterCatalogSearchCriteria.and(searchTerm, masterCatalogSearchCriteria.equalsCodeType(MasterCatalog.ID_CODE_TYPE));
 
// set the root search term 
masterCatalogSearchCriteria.setRootSearchTerm(searchTerm); 
 
// retrieve master catalog entry 
MasterCatalog [] fetchedMasterCatalog = masterCatalogService.findMasterCatalogEntries(masterCatalogSearchCriteria); 

Example 7-25 Remove Master Catalog Entries from Cache

The Master Catalog API uses the CTBCacheService for caching the Master Catalog and Master Catalog Focal Class State Transition entries. The following table lists the cache names used to store the object:

Cache Names

Cache Name Description Key
CtbCoreMcActEntriesCache Cache name for Master Catalog Act entries ClassCode
CtbCoreMcEntityEntriesCache Cache name for Master Catalog Entity entries ClassCode
CtbCoreMcRoleEntriesCache Cache name for Master Catalog Role entries ClassCode
CtbCoreMcStTrnstnsCache Cache name for Master Catalog Focal Class State Transition entries ControlActMasterCatalogId

Example 7-26 Remove Master Catalog Entries from Cache

There are 2 APIs, which you can use to remove Master Catalog entries from the cache.

//This will remove all the entries from the Act Master Catalog cache, here we only supply the cache name as parameter.
 
cacheService.invalidate("CtbCoreMcActEntriesCache");
 
//There is also an option to selectively delete entries from the cache using the key. 
//Here the class code is being used as a key for the Act Master Catalog entries cache. 
//This will remove all the act master catalog entries having that class code from the cache. 
 
cacheService.invalidate("CtbCoreMcActEntriesCache", "OBS");

Focal Class State Transitions

Focal Class State Transitions define the valid state transitions for a given combination of the Control Act Master Catalog ID and the Focal Class Master Catalog ID. These transitions must be a subset of the valid transitions for the RIM object type (Act, Entity, and Role). These transitions should be valid according to the generic state transition rules. The following are the possible state transition scenarios during creation or update of Act, Entity, and Role objects.

  • null -> null (Always allowed and is never validated)

  • not null -> not null (Allowed only after validation)

  • null -> not null (Allowed only after validation)

  • not null -> null (Not Allowed)

The examples below illustrate how to query for the existence of a Focal Class State Transition, and how to create a required Focal Class State Transition.

See Also:

  • Oracle Healthcare Data Repository API Documenation for focal class description.
  • Oracle Healthcare Data Repository Implementation Guide for more information about Focal Class State Transitions.

Example 7-27 Check for Existence of a Focal Class State Transition (for Control Act and Focal Class)

String controlActMasterCatalogId = "";
        String focalClassMasterCatalogId = "";
 
        // Find the Master Catalog Entry for the Control Act
        MasterCatalog mc = masterCatalogService.getMasterCatalogActEntry(
            ActClass.CACT, ActMood.EVN, null, "NULL");
        controlActMasterCatalogId = mc.getMasterCatalogId();
 
        // Find the Master Catalog Entry for the Focal Class
        mc = masterCatalogService.getMasterCatalogEntityEntry(
            EntityClass.PSN, EntityDeterminer.INSTANCE, null, "NULL");
        focalClassMasterCatalogId = mc.getMasterCatalogId();
 
        // Retrieve the Focal Class State Transition for the given
        // Control Act, Focal Class where 
        // Focal Class start state = "null" and 
        // Focal Class end state = "active"        
              MasterCatalogFocalClassStateTransition mcfcst = 
            masterCatalogService.getFocalClassStateTransitionEntry(
            controlActMasterCatalogId, focalClassMasterCatalogId,
            "null","active");
        if (mcfcst != null)
        {
            System.out.println("Valid Focal Class State Transition found.");
        }
              else
              {
            System.out.println("Focal Class State Transition not found.");
              } 

Example 7-28 Create a Focal Class State Transition

// Create a Focal Class State Transition for the
        // Master Catalog entry for DGIMG, EVN, NULL
      
        // Find the Control Act Master Catalog Entry
              MasterCatalog mcCact = masterCatalogService.getMasterCatalogActEntry(
            ActClass.CACT, 
              ActMood.EVN, null, 
            "NULL");
        // Find the DGIMG Act Master Catalog Entry
              MasterCatalog mcDgimg = masterCatalogService.getMasterCatalogActEntry(
            ActClass.DGIMG, 
              ActMood.EVN, null, 
            "NULL");
 
        MasterCatalogFocalClassStateTransition mcfcst = 
            masterCatalogFactory.newMasterCatalogFocalClassStateTransition();
        mcfcst.setControlActMasterCatalogId(mcCact.getMasterCatalogId());
        mcfcst.setFocalClassMasterCatalogId(mcDgimg.getMasterCatalogId());
        mcfcst.setActiveFlag(true);
        mcfcst.setStartState("any");
        mcfcst.setEndState("any");
 
        masterCatalogService.persistFocalClassStateTransitionEntry(mcfcst);
 
        // Now check it was persisted
        mcfcst = 
            masterCatalogService.getFocalClassStateTransitionEntry(
                mcCact.getMasterCatalogId(),
                mcDgimg.getMasterCatalogId(),
                "any", "any");
        if (mcfcst == null) throw new HDRConfigException(
              "Master Catalog Focal Class State Transition not found");

Example 7-29 Create an Array of Focal Class State Transition Entries

You can create or update an array of MasterCatalogFocalClassStateTransition entries using MC bulk persists API. For each entry in the array, the API checks if it is a valid entry as follows and persist it. If the API finds one or more invalid entries, it rejects all of them.

MasterCatalogFocalClassStateTransition mcfcst1 = masterCatalogFactory.newMasterCatalogFocalClassStateTransition(); MasterCatalogFocalClassStateTransition mcfcst2 = masterCatalogFactory.newMasterCatalogFocalClassStateTransition(); // For each mastercatalogfocalstatetransition entry defined above, to set the values follow the steps

// described in Example 7-37. //Create an array of mastercatalogfocalstatetransition with the above mentioned entries MasterCatalogFocalClassStateTransition [] mcfcstArray = MasterCatalogFocalClassStateTransition[] { mcfcst1, mcfcst1 }; //Call bulk persist method masterCatalogService.persistFocalClassStateTransitionEntries(mcfcstArray);

HDR HL7 Data Types

This package contains an implementation of a subset of the HL7 Data Types specification, to meet HDR RIM interface requirements. The attributes (id, class, status,...) of the HL7 version 3 RIM objects are defined in terms of these Data Types, as are the parameters and return types of the RIM API. In accordance with the specification, these data type objects are immutable—their value cannot be changed once created.

You can do the following:

See Also:

The UML class diagram at the HL7 website for information about available Data Types; refer to the following tips to view the diagram:
  • Select View > Full Screen [F11] to expand to a full screen.

  • Choose the Expand button to view the diagram; use the Windows scroll bars to navigate.

  • Use the Windows back-arrow to return.

Use the DataTypeFactory

New Data Type objects should always be instantiated using the DataTypeFactory methods exclusively. Most of the factory methods throw CommonException or ETSException if there is a problem creating the new instance.

Creating Constants

As the factory methods throw checked exceptions, we do not recommend defining static final constants for Data Type values. If you find it useful to define constants, it is preferable to declare them as final member variables that can be initialized in the constructor (where exceptions can be handled more easily).

The CNE Domain Constants (defined in the package oracle.hsgbu.hdr.hl7.domain) define values for the CS type RIM coded attributes.

Abstract Types (ANY, BIN, QTY)

There are no factory methods for the ANY Data Type, because it is an abstract type. No value can be just an ANY without belonging to one of the concrete Data Types. For RIM attributes of type ANY (such as Observation.value, call the factory method for the appropriate concrete type (ST, ED, CD, GTS, etc.) and pass that type as the parameter to the RIM API.

Similarly, there is no factory method available for the Data Type BIN. It is a protected type that is only declared within the HL7 Data Type Specification. For properties of type BIN, you can substitute either ED or ST as the parameter to the factory method.

QTY is another example of an abstract type with no factory method. The specific subtype of Quantity (PQ, INT, REAL, and so on.) should be substituted instead.

HL7 Null Flavors

The Data Types Specification defines a hierarchy of different kinds of exceptional values, or null values. You can use the isNull method to determine whether a Data Type is one of these exceptional values; the nullFlavor method returns a CS code that specifies what kind of exceptional value it is.

In general, a Java null should never be passed to any of the parameters of the Data Types methods. You should use the DataTypeFactory to create an object with the appropriate HL7 null flavor instead. NI is the default null flavor, and should be used if you are uncertain about whether any of the more specific flavors of null are applicable.

The null flavor factory methods are guaranteed to return a valid Data Type with a null flavor, and never throw an exception. The CS codes for the null flavor values themselves are provided as convenience constants in the HL7.domain package.

Unsupported Operations

The present implementation of the HL7 Data Types Specification is only partially complete. Several methods throw a runtime UnsupportedOperationException, such as the arithmetic and comparison operations on Quantities, and many of the properties of the Timing Specification (GTS, PIVL, ...).

Coded Types

The HL7 Coded Types (CD, CE, CV and so on.) are stored in both HDR and ETS. Accordingly, several types of factory methods are provided for each coded type:

  • Methods that accept any of the HL7 properties (Examples: newCE(ST code, UID codeSystem, ST codeSystemName, ST codeSystemVersion, ED originalText)) (Example 7-41).

  • Methods that simply accept an ETS ID (Examples: newCE(String etsID)). The DataTypeFactory uses the ServiceLocator to retrieve the corresponding properties from ETS (Example 7-42); note that use of this method should be avoided because of the additional communication overhead with the server.

  • Convenience methods that accept only the mandatory attributes, and default all of the others to null flavors (Examples: newCE(String code, String codeSystem). Note that the second parameter of this method is the code system OID, and not the code system name (Example 7-43).

The complete mapping of code system names to OIDs can be retrieved in the following ways:

  • By viewing corresponding coding schemes in ETS UI (preferred).

  • For code systems registered with HL7, an online OID repository is provided as a free service.

These code samples help you do the following:

Example 7-30 Create Coded Data Type through Full Set of Properties (Recommended)

DataTypeFactory dtf = DataTypeFactory.getInstance();
 CD code = df.newCD(df.newST("233604007"), df.newUID("2.16.840.1.113883.6.96"),
    df.newST("SNOMED-CT"), df.newST("v1"), df.newST("Pneumonia"));

Example 7-31 Create Coded Data Type through ETS ID (Not Recommended)

DataTypeFactory dtf = DataTypeFactory.getInstance(); CD code = df.newCD("CON-2217");

Example 7-32 Create Coded Data Type through Code and Code System OID

DataTypeFactory dtf = DataTypeFactory.getInstance(); CD code = df.newCD("233604007", "2.16.840.1.113883.6.96");

Example 7-33 Create Coded Data Type through Code and Code System Name

DataTypeFactory dtf = DataTypeFactory.getInstance();
 CD code = df.newCD(df.newST("233604007"), df.nullUID(NullFlavor.NI),
    df.newST("SNOMED-CT"), df.newST("v1"), df.newST("Pneumonia"));

Collections (SET, BAG, LIST, IVL)

The factory methods for aggregate Data Types accept an array of elements (such as newSET_II(II[] identifiers)). The promotion operation is also provided, from a single Data Type into a trivial collection containing only that one element: newSET_II(II element).

HL7 Timing Specification (GTS, PIVL, EIVL, IVL<TS>, TS)

The factory methods for the time-related Data Types accept a literal string formatted according to the syntax defined in the HL7 specification. This literal is parsed to extract the properties (boundaries of an Interval, elements of a GTS) of the Data Type. If there is a syntax error in the string, a CommonException is thrown by the factory method.

RIM Service Examples

The code samples below help you do the following:

Use CD Qualifiers

Example 7-34 Use CD Qualifiers

// Creates an Observation Event showing the use of qualifiers
        // on coded data to provide additional information about the code
        // Uses the SNOMED-CT coding scheme, which must be loaded to pass validation
 
        // Use Act Code of DISDX/ActCode. 
        // DISDX represents a "Discharge Diagnosis"
        // ActCode OID is 2.16.840.1.113883.5.4
        CD actCode = dataTypeFactory.newCD("DISDX", "2.16.840.1.113883.5.4");
        Observation obs = actFactory.newObservation(ActMood.EVN, actCode, 
            dataTypeFactory.nullSET_II(NullFlavor.NA));
 
        obs.setText(dataTypeFactory.newST("Acute sudden-onset severe appendicitis, first episode."));
 
 
        // Construct a code for observation value with qualifiers
        // Code is Appendicitis/SNOMED-CT
        // Qualifiers represent the following name - value information -
        // Severity (246112005) - Severe (24484000)
        // Clinical Course (263502005) - Acute Onset (373933003)
        // Episodicity (246456000) - First Episode (255217005)
        // All qualifiers use the SNOMED-CT coding scheme
 
        // It is expected that qualifiers will normally be taken from the same
        // coding scheme as the code. However, HDR does not validate this.
 
        CR[] qualifiers = 
        {
            dataTypeFactory.newCR(
                dataTypeFactory.newCV("246112005", "2.16.840.1.113883.6.96"),
                dataTypeFactory.newCD("24484000", "2.16.840.1.113883.6.96"),
                dataTypeFactory.newBN(false)),
            dataTypeFactory.newCR(
                dataTypeFactory.newCV("263502005", "2.16.840.1.113883.6.96"),
                dataTypeFactory.newCD("373933003", "2.16.840.1.113883.6.96"),
                dataTypeFactory.newBN(false)),
            dataTypeFactory.newCR(
                dataTypeFactory.newCV("246456000", "2.16.840.1.113883.6.96"),
                dataTypeFactory.newCD("255217005", "2.16.840.1.113883.6.96"),
                dataTypeFactory.newBN(false))
        };
 
 
        // use Appendicitis (74400008) from SNOMED-CT coding scheme
        CD code = dataTypeFactory.newCD(
            dataTypeFactory.newST("74400008"),
            dataTypeFactory.newUID("2.16.840.1.113883.6.96"),
            dataTypeFactory.nullST(NullFlavor.NA), 
            dataTypeFactory.nullST(NullFlavor.NA),
            dataTypeFactory.nullED(NullFlavor.NA),
            dataTypeFactory.newLIST<CR>(qualifiers));
        obs.setValue(code);
 
        // Add participations to a Medical Practitioner and to a Patient
        // Participation to the Patient is typically SBJ
        // Participation to the Provider is typically AUT
 
        // Omitting the Person (player) and Organization (scoper)
        // for the purposes of the example
        Patient pat = roleFactory.newPatient(dataTypeFactory.nullCE(NullFlavor.NA),
            null, null, dataTypeFactory.nullSET_II(NullFlavor.NA));
        LicensedEntity prov = roleFactory.newHealthcareProvider(
            dataTypeFactory.nullCE(NullFlavor.NA),
            null, null, dataTypeFactory.nullSET_II(NullFlavor.NA));
 
        obs.addParticipation(ParticipationType.SBJ,pat);
        obs.addParticipation(ParticipationType.AUT,prov);
 
        // Attach the Observation to a Control Act and submit
        ControlAct cact = actFactory.newControlActEvent(
            dataTypeFactory.nullCD(NullFlavor.NA),
            dataTypeFactory.nullSET_II(NullFlavor.NA));
        cact.addOBActRelationship(ActRelationshipType.SUBJ,obs);
 
        rimService.submit(cact);

Query Based on Observation Value Attribute

The data type specification defines a hierarchy of various exceptional values or null values. You can use the isNull method to determine whether a data type is an exceptional value. The nullFlavor method returns a CS code that specifies the type of exceptional value.

Example 7-35 Query PQ Values

Query for all patients with a "Post-Prandial Blood Glucose Measurement" greater than 180 mg/dL (OBS.EVN.302788006//SNOMED-CT with Observation.value (PQ) = greater than 180 mg/dL).

// Show how to perform a query on Observation Value.
        // It is normal to specifiy the Class Code, Mood code, code and value
        // attributes for such queries
 
        // Build a Role Fetch to bring back the Patient
        RoleFetch rf = queryComponentFactory.newRoleFetch();
 
        // Decide which attributes to retrieve on the Patient Role
        rf.retrieveId(true);
 
        // Build a Participation Fetch,with a ParticipationCriteria
        // specifying that the participation type is SBJ
        ParticipationAttributeCriteria pc = queryComponentFactory.newParticipationAttributeCriteria();
        pc.setTypeCode(ParticipationCriteria.EQUALS,ParticipationType.SBJ);
        ParticipationFetch pf = queryComponentFactory.newParticipationFetch(pc,queryComponentFactory.VERSION_DEPENDENT);
        pf.addRoleFetch(rf);
 
        // Put together act critera, specifying class code, mood code, code
        // and value attributes
        ActAttributeCriteria ac = queryComponentFactory.newActAttributeCriteria();
        ac.setClassCode(ActCriteria.EQUALS,ActClass.OBS);
        ac.setMoodCode(ActCriteria.EQUALS,ActMood.EVN);
 
        // Build code and value criteria objects
        CodedTypeAttributeCriteria ctac = queryComponentFactory.newCodedTypeAttributeCriteria();
        ctac.setCode(dataTypeFactory.newST("302788006"));
        ctac.setCodeSystem(dataTypeFactory.newUID("2.16.840.1.113883.6.96"));
        ac.setCode(ctac);
 
        PQAttributeCriteria pqac = queryComponentFactory.newPQAttributeCriteria();
        pqac.setValue(PQAttributeCriteria.GREATER_THAN,dataTypeFactory.newREAL("180"));
        pqac.setUnit(PQAttributeCriteria.EQUALS,dataTypeFactory.newCS("mg/dL"));
        ac.setValue(pqac);
 
        ActFetch af = queryComponentFactory.newActFetch(ac, queryComponentFactory.VERSION_DEPENDENT);
        af.addParticipationFetch(pf);
        af.retrieveAll();
 
        Iterator iter = rimService.queryActs(serviceLocator,af);
        while (iter.hasNext())
        {
            Observation obs = (Observation)iter.next();
            System.out.println("== Observation ==");
            System.out.println("== id ==>" + obs.getId());
            System.out.println("== code ==>" + obs.getCode());
            System.out.println("== value ==>" + ((PQ)obs.getValue()).literal());
            Iterator partIter = obs.getParticipations();
            while (partIter.hasNext())
            {
                Role role = ((Participation)partIter.next()).getRole();
                System.out.println("== Role id ===> " + role.getId());
            }
        }

Example 7-36 Query CE/CD Values

Query for all patients with a diagnosis of "Asthma" or "Pneumonia" (OBS.EVN.DISDX//ActCode with Observation.value (CE) = 195967001// SNOMED-CT or 233604007// SNOMED-CT).

// use the same fetch and criteria objects as before.
        // change the code and value attributes for the different criteria
        ctac = queryComponentFactory.newCodedTypeAttributeCriteria();
        ctac.setCode(dataTypeFactory.newST("DISDX"));
        ctac.setCodeSystem(dataTypeFactory.newUID("2.16.840.1.113883.5.4"));
        ac.setCode(ctac);
        
        CodedTypeAttributeCriteria asthmaCriteria = queryComponentFactory.newCodedTypeAttributeCriteria();
        asthmaCriteria.setCode(dataTypeFactory.newST("195967001"));
        asthmaCriteria.setCodeSystem(dataTypeFactory.newUID("2.16.840.1.113883.6.96"));
 
        CodedTypeAttributeCriteria pneumoniaCriteria = queryComponentFactory.newCodedTypeAttributeCriteria();
        pneumoniaCriteria.setCode(dataTypeFactory.newST("233604007"));
        pneumoniaCriteria.setCodeSystem(dataTypeFactory.newUID("2.16.840.1.113883.6.96"));
        ac.setValue((CodedTypeAttributeCriteria)queryComponentFactory.or(asthmaCriteria, pneumoniaCriteria));
 
        af = queryComponentFactory.newActFetch(ac, queryComponentFactory.VERSION_DEPENDENT);
        af.addParticipationFetch(pf);
        af.retrieveAll();
 
        iter = rimService.queryActs(serviceLocator,af);
        while (iter.hasNext())
        {
            Observation obs = (Observation)iter.next();
            System.out.println("== Observation ==");
            System.out.println("== id ==>" + obs.getId());
            System.out.println("== code ==>" + obs.getCode());
            System.out.println("== value ==>" + obs.getValue());
            Iterator partIter = obs.getParticipations();
            while (partIter.hasNext())
            {
                Role role = ((Participation)partIter.next()).getRole();
                System.out.println("== Role id ===> " + role.getId());
            }
        }

Example 7-37 Query BL Values

Query for all patients with a positive "Mantoux Test" (OBS.EVN.268376005//SNOMED-CT with Observation.value (BL) = true).

ctac = queryComponentFactory.newCodedTypeAttributeCriteria();
        ctac.setCode(dataTypeFactory.newST("268376005"));
        ctac.setCodeSystem(dataTypeFactory.newUID("2.16.840.1.113883.6.96"));
        ac.setCode(ctac);
        
        
        ac.setValue(ActAttributeCriteria.EQUALS,dataTypeFactory.newBL(true));
 
        af = queryComponentFactory.newActFetch(ac, queryComponentFactory.VERSION_DEPENDENT);
        af.addParticipationFetch(pf);
        af.retrieveAll();
 
        iter = rimService.queryActs(serviceLocator,af);
        while (iter.hasNext())
        {
            Observation obs = (Observation)iter.next();
            System.out.println("== Observation ==");
            System.out.println("== id ==>" + obs.getId());
            System.out.println("== code ==>" + obs.getCode());
            System.out.println("== value ==>" + ((BL)obs.getValue()).literal());
            Iterator partIter = obs.getParticipations();
            while (partIter.hasNext())
            {
                Role role = ((Participation)partIter.next()).getRole();
                System.out.println("== Role id ===> " + role.getId());
            }
        }

Example 7-38 Query INT values

Query for all patients with a zero "Missing Tooth Count" (OBS.EVN.251317003//SNOMED-CT with Observation.value (INT) = 0).

ctac = queryComponentFactory.newCodedTypeAttributeCriteria();
        ctac.setCode(dataTypeFactory.newST("251317003"));
        ctac.setCodeSystem(dataTypeFactory.newUID("2.16.840.1.113883.6.96"));
        ac.setCode(ctac);
        
        
        ac.setValue(ActAttributeCriteria.EQUALS,dataTypeFactory.newINT(0));
 
        af = queryComponentFactory.newActFetch(ac, queryComponentFactory.VERSION_DEPENDENT);
        af.addParticipationFetch(pf);
        af.retrieveAll();
 
        iter = rimService.queryActs(serviceLocator,af);
        while (iter.hasNext())
        {
            Observation obs = (Observation)iter.next();
            System.out.println("== Observation ==");
            System.out.println("== id ==>" + obs.getId());
            System.out.println("== code ==>" + obs.getCode());
            System.out.println("== value ==>" + ((INT)obs.getValue()).literal());
            Iterator partIter = obs.getParticipations();
            while (partIter.hasNext())
            {
                Role role = ((Participation)partIter.next()).getRole();
                System.out.println("== Role id ===> " + role.getId());
            }
        }

Example 7-39 Query TS values

Query for all patients with a "Time of Onset" greater than or equal to 00:02:01 (OBS.EVN.263501003//SNOMED-CT with Observation.value (TS) = 00:02:01).

ctac = queryComponentFactory.newCodedTypeAttributeCriteria();
        ctac.setCode(dataTypeFactory.newST("263501003"));
        ctac.setCodeSystem(dataTypeFactory.newUID("2.16.840.1.113883.6.96"));
        ac.setCode(ctac);
        
        
        try 
        {
            ac.setValue(ActAttributeCriteria.EQUALS,dataTypeFactory.newTS(new SimpleDateFormat("yyMMddHHmmss").parse("080101000201")));
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
 
        af = queryComponentFactory.newActFetch(ac, queryComponentFactory.VERSION_DEPENDENT);
        af.addParticipationFetch(pf);
        af.retrieveAll();
 
        iter = rimService.queryActs(serviceLocator,af);
        while (iter.hasNext())
        {
            Observation obs = (Observation)iter.next();
            System.out.println("== Observation ==");
            System.out.println("== id ==>" + obs.getId());
            System.out.println("== code ==>" + obs.getCode());
            System.out.println("== value ==>" + ((TS)obs.getValue()).literal());
            Iterator partIter = obs.getParticipations();
            while (partIter.hasNext())
            {
                Role role = ((Participation)partIter.next()).getRole();
                System.out.println("== Role id ===> " + role.getId());
            }
        }

Constraints on the HL7 V3 RIM Model

The constraints to some of the HL7 V3 data types allow HDR to have a physical data model that gives a significant boost to the API performance.

HL7 V3 Datatype Constraints

ED.Reference.Use

HDR allows only one use code for ED.Reference instead of many. ED.Reference is generally used to store the external URL of an image or document represented by this ED. Since URL is a type of addressing mechanism, HL7 allows Use based on the base definition of an address. HDR allows just a single Use to be specified on the ED.Reference to cater to any use cases where an Use may be needed on ED.Reference.

AD.Use

HDR allows only 3 use codes for AD.Use. A single address may be used as home, office, and the third one can be used for another purpose.

AD.ADXP

The following additional constraints are placed on the number of ADXP values used in AD datatype:

  1. Only 5 street address lines (ADXP with part type SAL) are supported. Each street address line can have a maximum of 240 characters.

  2. There can be only one ADXP each with part type other than SAL. For example, there can be only one building number or one country in the address.

EN.Use

HDR allows only 3 use codes for EN.Use. A single name may be used as legal, call-by, and the third one can be used for another purpose.

EN.ENXP

There can be only one ENXP each with any part type. For example, there can be only one given name in the name. Each name part can have a maximum length of 1000 characters.

RIM Query API Constraints

  • The top-level RIM fetch object must have criteria with RIM structural codes specified.

  • Criteria is optional in child fetches but is strongly recommended in all cases where the queried RIM object model is well defined.

  • Criteria on any fetch object cannot be connective criteria specifying different structural attributes, for example: a different class code. The recommended approach to restructure such queries is to create different fetch objects for each class code. Connective criteria can still be used at any level provided the RIM structural codes are same on each of the attribute criteria. Each structural code represents a particular type of clinical information such as encounter or an observation and HDR mandates that one fetch is used for each type of clinical data retrieved.