caEHR Software Architecture Document

Document Sample
caEHR Software Architecture Document Powered By Docstoc
					        caEHR Software Architecture
                Document

                                        DRAFT
                                           Version 0.0.5

                                            07/10/2010

Authors                                  Joshua Phillips - SemanticBits
                                         Dan Kokoktov - 5AM Solutions
                                         Hannes Niedner - 5AM Solutions
                                         Clark Shaw - Agilex Technologies
                                         Brian Pickeral - 5AM Solutions
                                         Manav Kher - SemanticBits
Editor
Reviewers                                Todd Parnell - 5AM Solutions
Architecture Inception Team



Version         Date                         Contributor                         Description
Number
                                             Joshua Phillips                     Initial draft
0.0.1           03/26/2010
0.0.2           4/26/2010                    Joshua Phillips                     Updated based on I1S2

0.0.3           5/28/2010                    Clark Shaw                          Updated based on Architecture Team's
                                                                                 artifacts for I2S2
0.0.4           6/19/2010                    Brian Pickeral                      Update for I3

0.0.5           7/16/2010                    Manav Kher, R. Hannes               Updated AOP based bean Validation, Add
                                             Niedner, Igor Merenko               Strategy to handle Cd and Cs field
                                                                                 conversion.
                                                                                 Updated bidirectional Strategy, Added JPA
                                                                                 and ISO21090 mapping strategies


             caEHR Software Architecture Document ............................................. 1
               1 Introduction .................................................................................... 2
               2 Target Platforms .............................................................................. 3
                 2.1 Baseline Platform ....................................................................... 3
                 2.1.1 Deployment ............................................................................ 3
                 2.1.2 Package Structure/Architectural Layers ...................................... 4
                 2.1.3 Components ........................................................................... 6
                    2.1.4 Persistence Strategy Details ...................................................... 8
                      2.1.4.1 Placing of the JPA/Hibernate Annotations .............................. 8
                      2.1.4.2 Bi-Directional Relationships ................................................. 8
                      2.1.4.3 Implementation of equals, hashCode and compareTo. ............11
                    2.1.5 Separation of Message Model and Internal Domain Model.............11
                    2.1.6 Transformation of Message Formats to Domain Objects ...............12
                    2.6.2 Standard Dozer Idioms............................................................ 18
                3   Requirements................................................................................. 19
                    3.1 Functional Requirements ............................................................ 19
                    3.2 Non-Functional Requirements .....................................................19
                      Remote Access ............................................................................ 19
                      Interoperability............................................................................ 19
                      Conformance to Standards ............................................................ 20
                      Security...................................................................................... 20
                      Auditing...................................................................................... 21
                4   Infrastructure Dependencies ............................................................ 22
                5   Appendix ....................................................................................... 22
                    5.1 Component Wiring..................................................................... 22
                    5.2 Dependency Injection Idioms ......................................................25
                      5.2.1 For Bean definitions, prefer Java to XML files ...........................25
                      5.2.2 Group Bean definitions into @Configuration-annotated
                      configuration modules .................................................................. 25
                      5.2.3 Use interface-implementation pairs of configuration modules
                      where necessary .......................................................................... 25
                      5.2.4 Use XML definitions when an XML DSL is available....................26
                      5.2.5 Use @Value annotations with an XML-configured properties source
                      for build-time placeholder replacements ..........................................27
                      5.2.6 Prefer Constructor-based injection .........................................27
                      5.2.7 Use Setter-based injection when instantiation is handled by a
                      separate framework ..................................................................... 28
                      5.2.8 Avoid exposing getters and setters for dependencies ................28
                      5.2.9 Express dependencies on the most general interface possible ....28
                      5.2.10 Use @Qualifier to select among multiple implementations of an
                      interface ..................................................................................... 28
                      5.2.11 Use the TestContext framework for unit and integration tests ..28
                      5.2.12 Consider creating @Configuration modules that define Mockito-
                      mocked versions of dependencies ..................................................29
                      5.2.13 Only execute integration tests with @Transactional semantics ..29
                    5.3 Aspect Oriented Programming (AOP)............................................29
                6   References..................................................................................... 29



1 Introduction

The purpose of this document is to capture and convey the architectural decisions that were
made to satisfy the functional and non-function requirements of the system in the context
of the target platforms. This document is complementary to documents created by the
Architecture Stream. In particular, the scope of this document is restricted to architectural
decisions that are specifically motivated by the target Platform Specific Models (PSM). Only
technology decisions about components that have been implemented (at least to some
extent) will be described here.
2 Target Platforms
We anticipate that there will be multiple target platforms and deployment scenarios in order
to accommodate the heterogeneous environments of the NCCCP sites. This document will
contain sub sections for each target platform. Each sub section will describe architecturally
significant features of the implementation that are motivated by the target platform/
deployment scenario.

2.1 Baseline Platform

We do not have any information about the NCCCP sites. Therefore, the only target platform
that we will be identifying is our Baseline Platform, which is essentially the platform that
the ESD team has specified based on the following factors:
     • Skill-sets/Expertise/Preferences of the ESD team
     • Industry Best Practices
     • Assumptions about target platforms

The set of baseline technologies that we have selected (including discussion of alternatives)
is documented in the here. A brief summarization of the technologies being used are listed
below for convenience.



Technology            Description

Apache CXF            This is a strong web service platform and provides implementations
                      of both JAX-RS and JAX-WS

Tomcat 6.0            The Tomcat server will be used to deploy this service to help
                      maintain a lightweight service goal.
Dozer 5.2.1               A Java Bean to Java Bean mapper that copies data from one
                          object to another (used for transforming external object
                          representations to internal representations for later processing
                          and persistence).
Hibernate Validator 4.0.2 A Java Bean validation tool that primarily uses java annotations
GA                        used for validating inbound and outbound data.

2.1.1 Deployment

The ReferredTo functional profile of the ReferralConsult service specification is implemented
as a Web Service component, ReferralService.
Figure 1. ReferralService component deployment.

The ReferralService component is implemented as a POJO annotated with JSR-181 Web
Service Metadata annotations. The Apache CXF container provides services necessary to
support the JAX-WS 2.0 programming model (e.g. SOAP-related services). Currently, the
service interface for this component is described using auto-generated WSDL 1.1 with SOAP
1.1 binding to HTTP/1.1. The Java Servlet container provides HTTP and HTTPS services. The
Spring container provides dependency injection - wiring the service component to other
system components - primarily DAOs.

The JDBC API is used to abstract the driver-specific wire protocol between between the
Application Server and and Database Server. Remote devices communicate with the
Application Service using SOAP over HTTP/HTTPS.


2.1.2 Package Structure/Architectural Layers


The code base has the following structure.
The above image needs to be updated. the package name for the localized iso datatypes
is gov.nih.nci.caehr.domain.iso21090 -Roland H. Niedner 7/14/10 12:30 PM

Figure 2. caEHR Packages

The caEHR code base is organized into four architecturally significant layers that are
reflected in the above package structure:
      • Web Service Layer (gov.nih.nci.caerh.websvc)
      • Service Layer (gov.nih.nci.caehr.service)
      • DAO Layer (gov.nih.nci.caehr.dao)
      • Domain Object/Persistence Layer (gov.nih.nci.caehr.domain)

gov.nih.nci.caerh.websvc

The primary purpose of this layer is to transform wire-format objects (from the org.hl7.v3
package) into our domain model. Classes in this layer may also provide additional validation
of the wire-format objects. The org.hl7.r2.datatypes contains wire-format objects for the
ISO 21090 datatypes.

gov.nih.nci.caehr.service

Contains interfaces and implementations of the ReferralService component (and future
service components). These interfaces in this package use the domain objects
(org.nih.nci.caehr.domain) and provide business validation.

gov.nih.nci.caehr.dao

Contains interfaces and implementations of DAOs. The DAOs provide high-level operations
over domain objects and some de-coupling of service layer from the persistence layer.
gov.nih.nci.caehr.domain

Contains JPA-annotated domain objects. These classes use the NCI localizations of ISO
21090 found in the gov.nih.nci.hl7.r2. package for "Type II" mappings, according to the ISO
21090 PIM. For "Type I" mappings, the datatypes are mapped directly to domain object
attributes.


2.1.3 Components

caEHR consists of multiple components that represent capabilities. Each component is
composed of multple sub components that work together to implement the functional
profiles. The ReferralConsult component has the following structure, as depicted in Figure 3.
This general pattern is used to implement the other caEHR capabilities as well.




Figure 3. caEHR Components

ReferralConsult

This component exposes multiple Web Service interfaces. Figure 3 shows the
ReferredToPortType interface. This interface delegates to the ReferralWebService
component.

ReferralWebService
This component implements ReferredToPortType. It is reponsible for transforming wire-
format messages into domain objects and passing those to the ReferralService component
to perform the business logic. It delegates to the MessageValidation component to provide
validation of wire-format messages.

ReferralService

This component is reponsible for peforming the business logic. It delegates to the
DomainObjectValidation component to perform validation before executing the business
logic.

Referral

Exposes a ReferralDao interface to the ReferralService component to enable persistent
management of Referral-related domain objects.

Persistence

Uses JPA to provide an EntityManager interface too the Referral component for managing
access to the relational database. caEHR is currently using a Hibernate JPA provider. But,
since the JPA standard is used, this COTS component could be switched out for another JPA
provider.

Figure 4 depicts the interfaces and implementations that support the above
components for the Referral




Figure 4. Component interfaces and implementations

     • gov.nih.nci.caerh.websvc.ReferralWebService: defines the ReferredToPortType.
     • gov.nih.nci.caerh.websvc.ReferralWebServiceImpl: provides the implementation of
       the ReferralWebService component.
     • gov.nih.nci.caerh.service.ReferralService: provides the ReferredTo interface of the
       ReferralService component.
     • gov.nih.nci.caehr.service.ReferralServiceImpl: provides implementation of
       ReferralService component.
     • gov.nih.nci.caehr.dao.ReferralDao: provides ReferralDao interface of the Referral
       component.
     • gov.nih.nci.caerh.dao.ReferralDaoImpl: provides implementation of Referral
       component.

caEHR uses a Hibernate JPA provider to implement the Persistence component.
javax.persistence.EntityManager provides the interface to this component.
org.hibernate.ejb.EntityManagerImpl is one of the implementations of this component. The
Spring container constructs all components via annotation and XML configuration files.
Apache CXF also uses those Spring configurations to configure itself and find service
instances to delegate to. For details about component wiring, see section 5.1 of the
Appendix.


2.1.4 Persistence Strategy Details

2.1.4.1 Placing of the JPA/Hibernate Annotations

StackOverflow also has some interesting comments on the placement of JPA/Hibernate
           http://stackoverflow.com/questions/305880/hibernate-annotation-
annotations:
placement-question.
Our initial decision to place JPA/Hibernate Annotations on the member variables (fields) led
to persistence problems such that Cascade setting and Enumeration types where ignored. In
consequence and after testing the approach ALL property level JPA/Hibernate
Annotations must be placed on the getter method, unless field access is explicitly
declared or implicit for a particular member variable. In those special cases the annotation
must be placed on the field.



2.1.4.2 Bi-Directional Relationships

Our core principle is that an association is only bidirectional if needed and if both ends are
meaningful. At this point all Entity association in the internal domain model (UML) clearly
indicate whether or not they are bidirectional.
All the bi-directional hibernate relations OneToMany/ManyToOne stick to the approach that
objects should be added and removed from both sides:



       @Entity
       public class EntityA {

          private EntityB entityB;

         /**
          * @return EntityB
          */
          @ManyToOne
          public EntityB getEntityB() {
        return entityB;
    }


  /**
   * Method provides adding objects from the both sides. It removes itself from the
current EntityB, sets EntityB,
   * and then adds itself to the collection of EntityB.
   * @param entityB - instance of EntityB
   */
    public void setEntityB(EntityB entityB) {
        if (this.entityB != null) {
          this.entityB.getEntitiesA().remove(this);
      }


        this.entityB = entityB;
        if (this.entityB!= null) {
           this.entityB.getEntitiesA().add(this);
        }
    }
}


@Entity
public class EntityB {
  //must be initialized during declaration so that we never have
NullPointerException. This is mandatory!
    private Set<EntityA> entitiesA = new HashSet<EntityA>();


    /**
     * @return set of EntityA
     */
 @OneToMany(cascade = CascadeType.NecessaryType, mappedBy =
NECESSARY_FIELD)
 public Set<EntityA> getEntitiesA() {
    return entitiesA;
 }

  /**
   * Adds EntityA to collection. Invokes set on EntityA instance in order to link
objects from the both sides.
   */
    public void addEntityA(EntityA entityA) {
       if (entityA == null) {
        throw new IllegalArgumentException("entityA cannot be null in addEntityA");
      }
      performer.setPatientCareProvisionRequest(this);
  }

  /**
   * Adds new entities to existing ones. Links the child objects back to the parent
object.
   */
  public void addAllEntitiesA(Set<EntityA> entitiesA) {
    if (entitiesA == null) {
        throw new IllegalArgumentException("entitiesA cannot be null in
addAllEntitiesA");
     }
     for (final EntityA newEntityA : entitiesA) {
        newEntityA.setEntityB(this);
     }
  }

  /**
   * Removes the entityA from the collection, sets null on other side.
   */
  public void removeEntityA(EntityA entityA) {
    if (entityA == null) {
       throw new IllegalArgumentException("entityA cannot be null in
removeEntityA");
    }
    entityA.setEntityB(null);
  }

  /**
   * Clears the collection. Also sets the link from child to parent to null.
   */
  public void removeAllEntitiesA() {
    // Create new Set to prevent ConcurrentModificationException
        final Set<EntityA> newEntityASet = new HashSet<EntityA>(entitiesA);
        for (final EntityA newEntityA : newEntityASet) {
          newEntityA.setEntityB(null);
        }
  }

  /**
   * Works like replace. First removes all objects, then adds entities.
   */
  public void setEntitiesA(Set<EntityA> entitiesA) {
    if (entitiesA == null) {
               throw new IllegalArgumentException("entitiesA cannot be null in
       setEntitiesA");
            }
            removeAllEntitiesA();
            addAllEntitiesA(entitiesA);
          }
       }



2.1.4.3 Implementation of equals, hashCode and compareTo.

Persistent entities and embedded beans should generally override the hashCode and equals
method. We recommend using the EqualsBuilder and HashCodeBuilder classes from the
Apache Commons lang library to assist in the implementation of these methods.

For ISO21090-derived datatype the implementation of equals must be based on the
definition of equality from the 21090 specification itself, adjusted appropriately for our
localizations of these types. For further information see the NCI 21090 information wiki
page.

For persistent entities, use the "business" or "natural" key in the equals implementation. For
example, for an Organization this may be its name. The generated (artifical primary key) id
should NOT be used to drive equality. If a persistent entity does not have a suitable natural
key, then it should likely not override equals and stick with object identity as equality.

When equals is overridden, hashCode must be overridden to be consistent with the equality
definition, as defined in the Javadocs for java.lang.Object. Generally, this is accomplished
by using the same fields in both methods.

If your entity or embedded type needs to be used in a SortedSet, or instances of it need to
be compared, you should implement Comparable and override the compareTo method. It is
important that this be consistent with equals, as described in the Javadocs for
java.lang.Comparable. Again, this is generally just a matter of using the same fields (or a
subset thereof).

It is important that the equals and hashCode methods are adequately tested.

Please see the following articles for additional inspiration:

     • http://www.mifos.org/developers/wiki/EqualsHashCodeIssues
     • http://community.jboss.org/wiki/EqualsandHashCode
     • http://stackoverflow.com/questions/188311/how-should-one-unit-test-the-
       hashcode-equals-contract
     • http://blog.coryfoy.com/2008/05/unit-testing-equals-and-hashcode-of-java-beans/


2.1.5 Separation of Message Model and Internal Domain Model

caEHR distinguishes between the message model (the "external" model) and the internal
domain model.
The message model is intended to capture the contents, with associated semantics, of the
messages that are exchanged over the wire via the set of implemented services. It consists
of JAXB-generated classes derived from the XSDs provided by the A&A team as part of the
service specification. Because the messages for different services may include closely
related but somewhat different elements to represent the same concept, there will be
multiple closely related classes in the message model. An example is Patient - there are
different representations of a patient in the message model for different service methods,
with corresponding classes.

The internal domain model, on the other hand, captures the long-lived state of the various
entities in the caEHR domain. The classes in this model must, accordingly, be able to
capture all attributes of an entity, and be able to represent all its long-lived states. Thus, for
example, we would expect to have a single Patient entity in the internal domain model.

Another guiding principle of the internal domain model is that it be as simple as possible
and intuitively capture the entities and relationships in the domain, with no extraneous
attributes, associations and intermediate classes. In particular, while it should be capable of
capturing and returning all the information specified by the various caEHR services, it need
not be based on the HL7 metamodel. Whereas the message model will have many
"placeholder" classes corresponding to HL7 constructs that are mandatory, but whose
values in the context of a particular service method's messages are constrained to constant
values, in the internal model any attributes with constant values will be omitted. Association
container classes will, whenever possible, be collapsed, with any attributes moved into the
association target's class.

As an example, consider the various Component ActRelationship entities from the referral
model. In the message model these will be represented by REPCMT000001USComponent,
REPCMT000003USComponent, and so on. However, in the internal domain model these can
generally be omitted entirely. Instead, Order can be associated directly to
PatientCareProvisionRequest.

As discussed in more detail later in this document, different validation will be applied to
entities in the message model and the internal domain model. Message model validation will
ensure that the passed in message complies with the rules specific to the context of the
service method being called. For example, in the createReferral service method,
REPCMT000001USPatientCareProvisionRequest must have its statusCode be one of a few
specific values. On the other hand, internal model validation will verify invariants that must
be true for an entity at any time in its existence. For example, a
PatientCareProvisionRequest must always have a non-null identifier.

2.1.6 Transformation of Message Formats to Domain Objects

TODO: add HL7 required/mandatory/multiplicity/default wiki link + discussion -Guest 5/24/
10 12:20 PM

We are using ISO 21090 (Hl7v3 R2) specification for the storage and persistence of
information in caEHR. See the HL7 Wiki for collaborative information by the HL7 community.

The chosen software architecture reflects the assumption that the system exposing this
service is not necessarily based on the same information model as the service itself. This is
especially relevant since the service message formats that are consumed and produced by
the Referral , the Consult and other NCI Enterprise Services components are fully defined in
the Refined Message Information Model (RMIM). The service specific XML schema (XSD) are
directly generated from the caEHR information model captured in Model Interchange Format
(MIF) files using HL7v3 tooling. The core datatypes of the caEHR information model is based
on the ISO 21090 (Hl7v3 R2) specification. Because the HL7v3 based information model is
equivalent to a prescriptive XSD, exceeding the expected limitation the platform
independent specification has on the platform specific specification (with respect to SAIF/
ECCF), a loose coupling between internal (system business layer) and external (service
interface layer) data models is required to enable adoption by healthcare providers with
frequently extensive legacy system (e.g. not HL7v3 based).

Many of the external message attributes identify the service, the service provider and the
message category and are invariant from the perspective of the individual service provider
system. We maintain these constant attributes separately from the variable data which are
persisted to the RDBMS via DTOs (i.e. the domain objects found in the
gov.nih.nci.caehr.domain package). The system has a non-functional requirement to
support exchange of the NCI localization of ISO 21090 datatypes which defines rules on how
to transform external messages to their localized internal representations. These rules are
specified within the ISO 21090 PIM and in a more up-to-date wiki entry here. The localized
internal message datatypes are specified in the PSM and our mapping and conversion
strategy is outlined below in section 2.1.5.5.

The different handling of ISO 21090 datatypes can be demonstrated via the
PatientCareProvisionRequest.id and the Patient.id. Both are mapped to an II with both are
handled via Type 2 mapping. Since II is of type 2, all attributes of II such as II.extension,
II.identifierName, II.reliability, II.root, II.scope are variant from the perspective of the
same system. In the case of the Patient.id the Referred To provider system needs to treat
all attributes as variables, because all attributes of II identifies the patients maintained by
many distinct Referred From provider systems and there are potentially different values for
different attributes of II.

In order to provide decoupling of message formats from our persistence layer, we are using
a two-step approach. In the first step, XML messages are marshaled to Java objects using
the JAXB libraries bundled with Java 1.6. The class definitions for these objects have been
created directly from the XML schemas mentioned above via xjc code generation. In the
second step, Dozer is used to transform those objects into JPA-annotated domain objects
(DTOs). The DTO layer will also contain the internal representation of the ISO 21090
datatypes (defined in the gov.nih.nci.hl7.r2.datatypes package), such as type 2 mapped II
and CD types, which can then be embedded within the relevant DTOs.
Figure 6. Transformation of message formats to domain objects.

2.1.6.1. Dozer Transformation
     • Dozer is used to transform external objects to internal domain objects and vice
       versa.
     • Each Dozer converter should extend AbstractCaEHRDozerConverter<S, D>.
     • Converters used globally are defined in globalConfigMapping.xml
     • Dozer mapping files reside in the caehr-esd-war resources directory and contain
       "Mapping" in the file name (case sensitive).
     • We want to eventually create an abstract mapping test that automatically tests a
       Dozer mapping when providing an internal object, external object, and validation
       methods.

2.1.6.2. Transformation Rules

In order to create optimized internal domain model from a given external domain (incoming
message) and to be consistent throughout the project the following transformation rules
have to be followed:
     • Every external domain class that has identifier of ISO 21090 type II becomes a
        Persistent Entity of the internal domain model
     • Every external domain class that doesn't have identifier becomes an Embeddable
        component of the internal domain model
     • If there are several related external domain classes (e.g.
        REPCMT000003USClusterIntent2 and REPCMT000003USClusterIntent) then class
        hierarchy of internal domain classes should be created with all common attributes
        represented in parent classe(s).
     • If one-to-many association is unidirectional then in order to make many side the
        owner of the relationship it's needed to make the association bidirectional
     • If one-to-many association refers to an Embeddable component on the many side
        and that component doesn't have any attributes besides reference to another entity,
        then such Embeddable component shall be removed from the association and
        replaced with the referenced entity itself.
2.1.6.3. Domain Objects validation

This paragraph no longer relates to the previous section. -Joshua Phillips 7/15/10 1:04 PM
In addition, by removing fields that don't change, one can correctly specify invariants and
validation on the domain model - improving testability. There are 3 levels of message
validation in our system architecture. The first level is the implicit validation of the message
against the aforementioned XSD, directly derived from the caEHR information model. The
second level validates some values of the unmarshaled JAXB objects, especially checking
the values that are considered invariant from the system's perspective. Upon successful
validation of the JAXB objects, the Dozer transformation is then invoked and the DTOs are
subject to the final validation step via Hibernate Validator framework. Key focus of this last
validation step are business requirements that cannot be expressed with a XSD such as for
example cross validation of different attributes or checking for the presence or absence of
particular records in the database. Some of the Hibernate validations include maximum
length for Strings, maximum length for lists, and required values. The default maximum
length of a String field should be 255.




Figure 7. Validation of messages.

Since validation is a cross-cutting concern, Spring AOP interceptors are used to validate
both the external (org.hl7.v3 package) and the internal (gov.nih.nci.caehr.domain) objects,
before invoking the business logic that is implemented by ReferralServiceImpl. The sole
responsibility of ReferralWebServiceImpl is to invoke the Dozer transformation from the
external representation to the internal representation.
Figure 8 Logical components of an AOP-based validation architecture.

The ValidationPointCuts aspect defines pointcuts that select joinpoints where validation
should occur. In Spring AOP, these will always be methods. We can use several approaches
to indicate what methods should be validated (e.g. packages, class naming, type
hierarchies, annotations, etc.) according to the AOP grammar that Spring supports.
However, it may reduce the complexity of pointcut authoring to use an annotation-based
approach. In this approach, we just identify methods to be validated using an annotation.

The ValidationAdvice aspect class reuses/composes poincut expressions from
ValidationPointCuts, and defines advice. These two classes represent a logical separation of
pointcuts and advice. Ideally, the ValidationAdvice class should just define the kind of
advice (e.g. Before, After, Around, etc.) and then delegate to validation components. This
allows the actual validation logic to be independent of an AOP-based approach.

The implementation can be found in gov.nih.nci.caehr.validation.aop package. The
BeanValidationAdvice.java is the ValidationAdvice aspect that uses the provided Validator
(defaults to Hibernate Validator), to validate the arguments to the joinpoint.


2.1.6.4. Strategy for mapping and conversion CD and CS types

This section outlines our approach to represent coded values. We deploy 2 basic tactics that
are determined by whether the code is part of an enumerated and quasi constant code list
used to constrain a value domain or not. In the first case we represent the code as an
Enum, transcribed from an A&A-provided artifact and in the second case as a embedded
CdValue bean, via which all fields of the CD (CS) are persisted to the database in the
context of the parent object.

Enum Mapping

The artifacts handed down by the A&A team contain a Terminology_Worksheet.xml
which lists all Value Sets and Code Systems that are used in the service. The following
nomenclature applies:
Parent Domain: This specifies the top level realm for a collection of codes and it contains
one or more Value Sets.
Value Set: A Value Set constrains the value domain for coded field in the message model
and consists of one or more Code Systems.
Code System: A Code System defines the semantic source/origin of a collection of code. A
Code System can contain one or many codes.

In the HL7 message model coded fields are represented either as CD (Concept Descriptor)
or CS (Code String) types, that both share the code attribute. In our internal mode these
codes are represented as Enums. In order to decouple the enum constant name from the
actual code value (to avoid conflicts with Java keywords and other problems) and also to
store the context information such as Code System and Value Set along side the code we
introduced the CdEnum and CsEnum interfaces. Currently all Value Sets on the
Terminology Worksheet where the field: Codes Provided below are: indicates Complete
List, can be represented as CdEnum independent of whether the are mapped and converted
to a CD or CS type, hence all Enum representing Value Sets have to extend the
CdEnum interface. A good example is ActStatus.
Steps for mapping from Terminology Worksheet to the CD fields.
      • Locate the Value Set by name in the Vocabulary Summary tab in the Concept
        Domain/Value Set Name column and click on the link:
      • Then transcribe the values as follows:
              ◦ Value Set OID -> ValueSet
              ◦ Value Set Date -> ValueSetVersion

Listing of the codes in the lower section

     • Code         -> code
     • Display Name -> displayName
     • Code Sytem -> codeSystem

the Code System can vary on a code by code basis

     • Now look up the Code System (listed under the same name on that tab) in the Code
       Systems & OIDs tab in the Code System Name column
     • For each Code System create a new Enum constant in the CodeSystem enum
     • Then transcribe the values as follows:
            ◦ HL7v3-registered OID -> Code System
            ◦ Code System Name         -> CodeSystemName
            ◦ Version Date            -> CodeSystemVersion

Some CD or CS fields might actually have a value domain that corresponds to a Parent
Domain rather than a Value Set. In this case, the Value Set is a variable for each code.
The CDAndCdEnumConverter and the CSAndCsEnumConverter are responsible for the
conversion of CDs and CSs defined in the Terminology Worksheet. The externalToInternal
conversion currently relies on the fact that all Enums implement the CdEnum interface.

CdValue Mapping

As mentioned above some CD/CS types fields map to potentially all values of one or
several Code Systems. In this case an enumeration does not fit the data model and we use
the embedded CdValue bean to store all code related fields in the database. Since the
individual codes are defined in Code System, we use a Terminology Service (currently only
implemented as a rudimentary stub) to validate the incoming code. We envision that the
TerminologyService will access all relevant Code System (such as SNOMED-CT, LOINC,
ICD-10) via web service like for example LexEVS or a Common Terminology Service 2
implementation. A good example for code values handled this way is DiagnosisValue.
Beyond that we may also need to support custom codes which map to local Code Systems.
The TerminologyServices should be shown in some architecture diagram. -Joshua Phillips
7/15/10 1:15 PM

Current deficiencies

We currently have no mechanism in place to computationally validate the transcribed data,
which is especially relavant for the CdEums with more that just a dozen constants like
ClinicalOrganizationRoleType. It is highly desirable that A&A would change the format of the
specs for enumerated code lists (Complete List) to a column based format that lists all valid
codes. A possible layout that would enable automatic validation is:

code | displayName | valueSet | codeSystem

Such a format would also make it easier to recognize changes throughout the progression of
A&A artifact drops.

2.1.6.5. Strategy for mapping and of the other ISO21090/HL7-R2 types to NCI
localized beans

After evaluating the reuse of the localized beans from NCI's ISO21090 project at it was
decided not to use them for the caEHR project. The main reason is that within the caEHR
project these beans are a fundamental part of the persistence strategy for the internal
domain model. Imported classes do not allow us to place JPA/Hibernate annotations and we
would have had to create custom Hibernate UserTypes. In addition the current HL7-R2/
ISO21090 artifact (xml schemas) provided by A&A have diverged significantly from the
standard that NCI's ISO21090 project was developed against. Instead we will implement
our own (caEHR) set of localized ISO21090 Datatype beans that are "inspired" by the NCI's
ISO21090 project beans but not depend on it.

  iso beans will have the required JPA annotations such as:
All
 • @MappedSuperclass for all abstract types
 • @Embeddable for all non-abstract beans
 • @Embedded to the getter for all fields that are @Embeddable
 • @ElementCollection to the getter for all collection types of @Embeddable
 • @Enumeration(EnumType.STRING) to the getter for all enum fields (Compression ,
   NullFlavor)
 • possibly other annotations such as @Column if needed
 • add Hibernate Validation annotations if needed - see specs.

In addition there will be dedicated BeanHelper implementations of all external to localized
internal type pairing as described in the ESD-470 and ESD-747 Jira tickets, as well as
a Dozer converter and a relevant test.


2.6.2 Standard Dozer Idioms

Dozer mapping file standards:
    • stop-on-errors="true" (we always want transforms to error out if a conversion
       doesn't work)
    • type="bi-directional" (always both ways)
     • wildcard="false" (we want to explicitly map each field and not rely on wildcard
       mapping)


3 Requirements

Reconsidering this section. We need a list of functional and non-functional requirements
from the A&A team. They need to be identified in such a way that we can refer to them.
This is currently captured in this JIRA ticket


3.1 Functional Requirements

We do not yet have any formally defined functional requirements. However, we know that
our initial focus is on the Referral and Outcomes capabilities. The documents below provide
a starting point for understanding these capabilities.
      • Referrals:
               ◦ Overview
               ◦ CFSS
               ◦ Model
      • Outcomes:
               ◦ CFSS
               ◦ PIM
               ◦ PSM

3.2 Non-Functional Requirements

We do not yet have any formally defined non-functional requirements. The following table
records our assumptions that have guided our selections of technology so far.

Remote Access

              Short
Identifier                         Description                  Source ReleaseComments
              Name
             HTTP   All service operations must be accessible
NF-100                                                        Assumption
             Access remotely over HTTP(S).




Interoperability

                Short
Identifier                          Description                Source ReleaseComments
                Name
             NES        caEHR services must interoperate with caEHR
NF-200
             Interop    NES.                                  RFP
Conformance to Standards

Do we have any initial list?
           Short
Identifier        Description       SourceRelease                  Comments
           Name
                                                    We can probably list a whole bunch here
                                                    today already. HTTP, HTTPS, SSL, X509,
NF-300                                              ISO 21090, etc, etc. This strikes me as a
                                                    "more the merrier" section. -Todd Parnell
                                                    3/12/10 1:08 PM
                 The system must
                 exchange of the
           NCI
NF-301           NCI localization
           21090
                 of ISO 21090
                 datatypes.

Security


     These assertions all talk about "the system." We need to identify system
     boundaries for these to make sense. -Todd Parnell 3/12/10 1:10 PM


Identifier Short Name      Description      Source       Release         Comments


                                                                      What level of
                                                                      assurance? (e.g.
                                                                      LOA2, LOA3) -
                                                                      Joshua Phillips

                          The system must
                          be able to verify                           Are things like
NF-400     Authentication                   Assumption
                          the identity of                             federation a
                          the user.                                   concern? Do we
                                                                      need to worry
                                                                      about trust
                                                                      relationships at
                                                                      all? -Todd Parnell
                                                                      3/12/10 1:05 PM




                                                                      Based upon the
                         The system must
                                                                      security doc, I
                         be able to
                                                                      think we need to
                         enforce role-
                                                                      change this to
NF-401     Authorization based or        Assumption
                                                                      "role- or
                         attribute based
                                                                      attribute- based
                         authorization
                                                                      authorization
                         policy.
                                                                      policy." We
                                                               should confirm
                                                               with Arch. -Todd
                                                               Parnell 3/12/10
                                                               1:05 PM




                                                               Need to consider
                                                               if secure point-
                                                               to-point is
                                                               sufficient or if
                                                               message-level
                                                               privacy is
                                                               needed. - Joshua
                           Confidentiality of                  Phillips
                           all messages
                           exchanges
NF-402     Confidentiality between client     Assumption
                           and service
                           components
                           must be ensured.                    This decision
                                                               impacts the
                                                               ability of
                                                               infrastructure
                                                               components to
                                                               audit. -Todd
                                                               Parnell 3/12/10
                                                               1:07 PM


                         The system must
                         be able to verify
                         that a message
NF-403     Integrity     has not been      Assumption
                         modified or
                         tampered with in
                         transit.
                         The system must
                         ensure that an
                                                               This relates to
                         action taken by a
                                                               level of
           Non-          user of the
NF-404                                     Assumption          assurance and
           repudiation   system cannot
                                                               auditing. -Joshua
                         (easily) be
                                                               Phillips
                         refuted by that
                         user.

Auditing


     The system must audit all message exchanges. Between what? Services?
     Components? Servers? Jurisdiction domains? -Todd Parnell 3/12/10 1:11 PM
      To what extent? What regulations apply? -Joshua Phillips




4 Infrastructure Dependencies
Here we list categories of functionality that are sufficiently general as to be most
appropriately implemented by an "infrastructure" team. For example, the ESD team will
implement services that authenticate users and enforce authorization policy, but we will not
implement identity/trust/policy management functionality. Therefore, we have infrastructure
dependencies on that functionality. For each category, we will (collaboration with the
architecture team) identify the functional proviles that we will use to interact with the
infrastructure components that provide this functionality.

     • Identity Management: caEHR services need to be able to authenticate users.
     • Trust Management: caEHR services need to be able to validate assertions (e.g.
       about identity or policy).
     • Policy Management: caEHR services need to be able to retrieve relevant policies.
     • Terminology Management: For example, the Outcomes business capability requires
       use of controlled terminology in search.



5 Appendix

5.1 Component Wiring

caEHR uses Spring's dependency injection services to wire together components. Both XML
configuration files and Java annotations are used, and annotations are preferred
Figure 9. Wiring of components

web.xml

CXFServlet is configured in web.xml. When the Servlet container loads the caEHR web
application, the CXFServlet is initialized. This servlet looks for Spring configurations that are
specified in web.xml. The caERH web.xml references only annotated CaEhrConfig java class
to load all Spring managed beans defined in caEHR.

applicationContext-caehr.xml

There are cases when Spring managed bean must be defined in xml only. This happens
sometime because of limitations in Spring framework. For example : there is no java
equivalent of <tx:annotationDriven />, or <aop:aspectj-autoproxy /> in Spring 3.0.
We define these beans in applicationContext-caehr.xml.

Spring also uses applicationContext-caehr.xml to configure CXF to create a JAXWS service
endpoint based on the gov.nih.nci.caehr.service.ReferralServce interface. CXF uses
annotations to scan the classpath and locate the appropriate service implementation:
gov.nih.nci.caehr.service.ReferralServiceImpl.
gov.nih.nci.caerh.caEHRConfig

Spring config skeleton for caEHR which loads all Spring configrations both Java and xml.
web.xml uses this class to load all Spring managed beans in caEHR. It also defines a
propertyPlaceholderConfigurer bean for build time property placeholder replacement from
caher.properties file.

Imports gov.nih.nci.caehr.service.ServiceConfig, gov.nih.nci.caehr.dao.DefaultDaoConfig,
gov.nih.nci.caehr.aop.AopConfig, gov.nih.nci.caehr.JpaConfig
and gov.nih.nci.caehr.util.BaseMapperConfig and
gov.nih.nci.caehr.validation.ValidationConfig

Also imports applicationContext-caehr.xml.


gov.nih.nci.caehr.JpaConfig

Configure the Persistence component. It sets up JPA annotation based transaction manager.
For example, ReferralServiceImpl has a Transaction annotation at the class level. So, all
methods on that class will be wrapped in transactions. It assumes that
<tx:annotationDriven /> is defined in the applicationContext-caehr.xml for annotation
based transactions to work.

It also constructs and configures an EntityManagerFactory which will initialize the JPA
persistence context. It also inializes the Liquibase bean and supplies it with the appropriate
changeLog file (caehr-db-changelog.xml)

gov.nih.nci.caehr.aop.AopConfig

Configures the AOP classes such as LoggingAspect. All aspect beans should be defined in
this AopConfig.

gov.nih.nci.caehr.service.ServiceConfig

Configures the web services beans such as I2S2ReferralToService, TerminologyService.

gov.nih.nci.caehr.util.BaseMapperConfig

Configures the dozer components and domain bean factory. It also loads all dozer mapping
files. Any dozer related component eith java mapping bean or xml mapping file must be
defined in this class.

gov.nih.nci.caehr.dao.DefaultDaoConfig

Configures all dao beans.

gov.nih.nci.caehr.validation.ValidationConfig

Configures all validations beans.

persistence.xml
Configures the caehr-esd JPA persistence unit, configures the JPA provider, and declares
persistence entities. These entities are the domain objects within the
gov.nci.nih.caerh.domain package.

5.2 Dependency Injection Idioms

5.2.1 For Bean definitions, prefer Java to XML files

The first preference should be to avoid XML configuration, and derive Bean definitions from
the Java code itself. There are a couple of ways this is done:
     • @Bean annotations on methods. These methods then act as provider/factory
         methods for the bean. Generally, as the next idiom describes, these should be
         placed in @Configuration-annotated classes.
     • Annotating classes with stereotype annotations: @Service, @Repository, etc, and
         telling Spring to use component scanning to detect them, as described in Spring
         Reference 3.11.2.3.

The idioms that follow go into further detail on these two methods.

5.2.2 Group Bean definitions into @Configuration-annotated configuration modules

Related bean definitions should be placed in an @Configuration-annotated module class,
with each bean defined by an @Bean-annotated method. Each such module class should
encapsulate a specific unit of functionality, e.g. the DAO layer, or the set of service and
helper classes for the ReferredTo profile.

Modules should express dependencies on each other via @Autowire annotations, as
described in Spring Reference 3.11.3.1. It is preferable to express dependencies on other
modules, rather than directly on the beans, as this promotes a modular and component-
centric development approach.

5.2.3 Use interface-implementation pairs of configuration modules where
necessary

Continuing from the preceding idiom, it is sometimes useful to define an interface and a
corresponding implementation for an @Configuration module, and express dependency on
the module in terms of the interface. This makes it simple to swap out a different
implementation of a module, for example one that wires up mock objects. This step can be
skipped if by its nature a module will only ever have one implementation.

This approach is illustrated below. Note that you need the "master" config which selects the
implementation of your module to use. You can have different master classes for deployed
system, integration tests, unit tests, etc.

// the module interface
@Configuration
public interface DaoConfig {
    @Bean PatientDao patientDao();
}
// the module implementation
@Configuration
public class MockDaoConfig implements DaoConfig {
public @Bean PatientDao patientDao() {
return Mockito.mock(PatientDao.class);
    }
}

// a module that depends on the Dao module
@Configuration
public class ServiceConfig {
private @Autowired DaoConfig daoConfig;

public @Bean ReferralService referralServiceService() {
return new ReferralServiceImpl(daoConfig.patientDao());
    }
}

// the master config
@Configuration
@Import({ServiceConfig.class, MockDaoConfig.class}) // import the concrete
config!
public class UnitTestConfig {
    // additional bean defs could go here
}

5.2.4 Use XML definitions when an XML DSL is available

There will be occasions when defining beans in XML is preferred. In particular, one such
case is when there is a special XML namespace and DSL for the beans in question. An
example is configuring the CXF bus, as in this snippet below. Because this takes advantage
of Spring's custom namespace support, it provides a concise and expressive syntax that
would be more verbose and confusing if replicated in Java:

<cxf:bus>
    <cxf:features>
        <cxf:logging />
    </cxf:features>
</cxf:bus>

In such cases, use XML bean definitions.
5.2.5 Use @Value annotations with an XML-configured properties source for build-
time placeholder replacements

A common pattern is when some simple values (Strings, dates, etc) to be injected into a
Bean need to come from build-time properties. The canonical example is defining a data
source whose connection parameters come from build-time properties.

This can be done while sticking to the stated preference for Java bean definitions and
configuration files, but with a little XML mixed in. Use the @Value annotation with the
Spring EL, while defining the properties source in XML using the special DSL:

@Configuration
public class AppConfig {
private @Value("${jdbcProperties.url}") String url;
private @Value("${jdbcProperties.username}") String username;
private @Value("${jdbcProperties.password}") String password;

public @Bean DataSource dataSource() {
return new DriverManagerDataSource(url, username, password);
    }
}

@Bean
public PropertyPlaceholderConfigurer propertyPlaceholderConfigurer() {
        final PropertyPlaceholderConfigurer configurer = new
PropertyPlaceholderConfigurer();
        configurer.setLocation(new ClassPathResource("caehr.properties"));
        return configurer;
}

5.2.6 Prefer Constructor-based injection

Spring supports multiple injection paradigms: field, setter, and constructor. Our preferred
paradigm is constructor injection. Each Spring-managed bean should provide a constructor
that accepts all of its dependencies.

On rare occasions, you will find that classes A and B have dependencies on each other,
which cannot be handled by constructor-based injection. Usually, this is a sign that your
class model should be refactored, by introducing a third helper class C on which A and B
both depend. http://misko.hevery.com/2008/08/01/circular-dependency-in-constructors-
and-dependency-injection has a good set of steps to go through to figure out what that
class should look like.

However, in certain cases a circular dependency cannot be avoided - perhaps some of the
classes are from a third-party framework and cannot be refactored. In this case, it is
acceptable for one of the classes to use setter injection. A known example in ESD code are
the dozer converters, which needed to both be injected into the dozer Mapper and have the
Mapper be injected into them.
5.2.7 Use Setter-based injection when instantiation is handled by a separate
framework

The exception to the above recommendation is if the beans are instantiated by some third-
party framework, but are still injected by Spring. It is likely that the framework requires an
empty constructor. In that case, use setter-based injection.

5.2.8 Avoid exposing getters and setters for dependencies

Rule: Do not create public getters and setters for dependencies unless they are part of the
class's public API. Such dependencies are an implementation detail and there is no need to
expose them to clients. Eliminating setters also reduces the number of states a bean can
have, enforces scope semantics, and enhances testablitiy.

Exception: When you have a class hierarchy managed by Spring, it is useful to provide
protected dependency getters, so that you don't need to have fields for them in every
subclass. Of course, if using setter-based injection, then public setters are necessary

5.2.9 Express dependencies on the most general interface possible

Beans should take as dependencies the most general superclass or interface that provides
the functionality they depend on. This reduces the footprint of the dependency, making
mock-based unit testing easier.

If following this recommendation causes ambiguity in @Autowire-based injection, then use
qualifiers as described below to ensure the correct implementation of an interface is injected

5.2.10 Use @Qualifier to select among multiple implementations of an interface

Sometimes multiple implementations of an interface are available, making simple
@Autowired annotations ambiguous. In that case, use @Qualifier to select the needed
implementation, as described in Spring Reference 3.9.3 (for the dependency side) and
3.10.7 (for the definition side).

Generally the base @Qualifier annotation with a String name is sufficient. For commonly
used and semantically meaningful qualifiers, however, you should define a custom
annotation, as described in the Spring reference.

5.2.11 Use the TestContext framework for unit and integration tests

Annotate your unit tests with @RunWith(SpringJUnit4ClassRunner.class) and
@ContextConfiguration(locations = "classpath:applicationContext-caehr-test.xml"). This
allows Spring to detect @Autowire annotations in the test classes and inject them
appropriately.

As opposed to normal classes, it is preferrable to use field-based injection in test classes,
just for simplicity.
5.2.12 Consider creating @Configuration modules that define Mockito-mocked
versions of dependencies

Because we prefer constructor injection, in unit tests that mock out dependencies we have a
choice. One approach is to construct the classes under test explicitly, not relying on Spring
injection at all. This will often be sufficient for classes whose dependency graph is small.

For more complex cases, it will often be preferrable to create an @Configuration module
which defines mock implementations of dependencies. This module would then be
referenced by an @ContextConfiguration replacing the version of the module that defines
the "normal" implementations. This permits using Spring to inject the class under test,
which would be already wired with the mocked dependencies. The dependencies themselves
can be injected as well, in order to make when() and verify() assertions on them.

5.2.13 Only execute integration tests with @Transactional semantics

Unit tests that use mock dependencies should not need to execute in a transactional
context, and so should not be annotated with @Transactional.


5.3 Aspect Oriented Programming (AOP)


Cross cutting concerns like - Validation, Logging, Access control are best applied through
the use of Aspects. This reduces code duplication. Aspect Oritented Programming (AOP) can
be used to describe patterns (PointCuts) that identify points in the execution of our code
(JoinPoints) where we should execute a cross-cutting concern (Advice) that is contained in
common components (Aspects).

With the use of the Spring container, AOP is already being used with the use of declarative
transaction management etc. We will use it further in applying custom aspects to implement
things like Validation and Logging. For this we will use Spring frameworks AOP
functionaility. Spring AOP is a pure java implementation of a subset of AspectJ. Using
@AspectJ annotation we will use Spring J2SE proxy support to declare aspects. More
information can be found at using AspectJ with Spring

Section 2.1.5.3. Domain Objects validation also describes the use of Spring AOP in caEHR.



6 References

				
DOCUMENT INFO
Shared By:
Categories:
Tags:
Stats:
views:23
posted:7/3/2011
language:English
pages:30