Technical Documentation

From TAPASWiki

Jump to: navigation, search

Contents

TAPAS Architecture Overview

The following diagram gives a high level overview of the TAPAS package architecture. The main packages are the tapas server package called casa, the tapas desktop client tapear, the tapas PDA client tapeta (package pdaems), and the data synchronization component jsyncmanager. The interface classes between server and clients (data classes and commands) are contained in package commons. The dashed lines denote dependencies. Some of these may not be manifested syntactically - but only logically, e.g., the dependencies between package conduit and package pdaems.

Image:tapas_arch.gif

The Commons package

The commons package contains a set of sub-packages that are commonly used by different TAPAS components. The figure below gives an overview on the commons package structure. The interface between clients (Tapear and Tapeta) and the server (CASA) is based on the command pattern (cf. Gamma et al. 94). Package command contains the command factory and the abstract command class. Package commandImpl" contains all commands (command stubs) that the server understands. The actual logic that implements these commands is encapsulated in package org.opentapas.casa.handlers (see section on CASA).

Image:commons_package.gif


The remote package contains the client/server communication stub; package security contain classes implementing the TAPAS access control model; package validation contains classes for data validation; package util' contain utility classes.

The RIM package contains the main classes for the object-oriented data model within TAPAS. RIM stands for ‘’Reference Information Model’’ and refers to an information model standard of [Health Level 7 (HL7)]. The main RIM classes are ‘’Entity’’, ‘’Act’’, ‘’Role’’, ‘’Participation’’, and ‘’ActRelationship’’. Different types of acts can be ‘’Procedures’’, ‘’SubstanceAdministration’’, and ‘’Observations’’. Acts can be related to each other by means of ‘’ActRelationships’’. Entities can play particular ‘’roles’’ when they ‘’participate’’ in acts. For example, a person can play the role of a ‘’patient’’ in a ‘’procedure’’.

Image:rim-classes.gif

The rim package contains several sub-packages, including

  1. tapasdomain, a set of facade classes to simplify data access to the rim class model,
  1. ems, a set of classes to support HL7 Clinical Document Architecture and the electronic medical summary ([(e-MS)].
  1. datatype, a set of HL7 RIM-based datatypes.

CASA (Clinical Application Server Architecture)

CASA (Clinical Application Server Architecture) is the central component of the TAPAS system. CASA is a J2EE web services oriented system which exposes the core functionality of the TAPAS business infrastructure through an RMI interface. Through implementation of J2EE technologies, CASA executes on any operating system that supports the Java Virtual Machine. CASA is responsible for coordinating core business logic, data validation and consistency checking as well as object persistence. One of the primary goals of this infrastructure is that of interoperability. The infrastructure is flexible enough to provide services to a variety of consumers, be it a mobile PDA client, a Rich Desktop client or a browser based thin client (the primary focus of the current project iteration is targeting PDA and Rich Client). The current iteration of the CASA infrastructure is based on a stack of industry standard open source components as follows: JBoss Hibernate ORM Persistence Layer JDBC Compliant RDBMS(PostgreSQL 8.0)

The following figure provides an overview on the CASA package structure and internal architecture. The internal package audit contains classes for the purpose of keeping audit trails for non-repudiation and information confidentiality. The session package contains the casa session facade. The persistence package contains all DataAccessObject classes (DAOs) as well as the object-relational mapping definitions for hibernate. The util package contains utilities, convenience methods, and the hibernate login module. The package handlers contains all command handlers along with the command factory. The document package contains classes to export medical records in e-ms and in EGADSS core data set format. Moreover, there is a component to import EGADSS recommendations. All these formats are based on the HL7 Clinical Document Architecture (CDA). The ws package contains the actual interface code to EGADSS.

Image:casa_arch.gif

The TAPAS Repository

The TAPAS repository is realized as an object-relational database. The data is stored in a relational database but accessed by an object-oriented access layer (realized in hibernate). The following two figure shows the current relational database schema. It was developed using the one-table-per-class-hierarchy approach. The tables are based on the HL7 Reference Information Model. Note that a limitation in hibernate does not allow us to inherit foreign keys, hence we needed to define new foreign keys for each logical subclass.

Image:ER-Diagram.png

The following diagram shows the current object model. This model has been produced by reverse engineering the hibernate mapping files. It has been subject to refactoring and simplification - so it may no longer be precisely up-to-date.

Enlarge

This image is a thumbnail. Click on it to download the larger image.

Tapear - the TAPAS Rich Client

The rich client has been developed in Java. It communicates with the CASA server using J2EE-based remote method invocation. The data is communicated using serialized POJOs (Plain Old Java Objects) fetched on the server by hibernate. These data objects are "detached" from the hibernate session while being modified on the client. They are re-attached when data is saved. Is has been the goal to make Tapear easily extensible with additional functionality. While we have not implemented a full-fletched plugin architecture yet, Tapear functions have to adhere to a particular framework. These framework classes are located in package org.opentapas.tapear.framwork. Let's have a look at a typical screen layout of the Tapear GUI in order to understand these framework classes. The following two figures show (1) the main framework classes and (2) the corresponding GUI design they represent.

Image:tapear-framework.gif

Image:GUI-panel-design.png

Class ‘’MainFrame’’ composes the main window including the pull-down menus, the button bar, the search bar, status bar, the main tab bar, and a panel called the ‘’FocusPanel’’. The main tab bar contains a tab for each patient case that has been opened. It also contains a tab selecting the clinician’s own workspace (messages, alerts etc.). The ‘’FocusPanel’’ contains information relevant to the current usage context. Any TAPAS function can register contents to the ‘’FocusPanel’’ that is shown when the function is active. Finally, as indicated in the GUI layout, the MainFrame contains the TapearPanel, which hosts the remaining display elements. The TapearPanel is implemented in class ‘’TapearPanel.java’’.

It contains a ‘’function tab bar’’, two ‘’side panels’’ and a ‘’function panel’’. Each TAPAS function is either classified as ‘’user-centric’’ or ‘’patient-centric’’. For example, the messaging function is user-centric, whereas the medical history of a patient is patient-centric. The distinction between user-centric and patient-centric functions allows tapas to know whether to add a function (plug-in) under the “Workspace” main tab (user-centric) or under any open patient main tab.

The Tapear framework defines several interfaces that need to be extended by functions. User-centric functions have to extend interface ‘’UserCentricFunction’’. Patient-centric functions have to extend ‘’PatientCentricFunction’’. Functions that want to display data in the focus panel have to extend interface ‘’FocusPanel’’. Each of Tapear’s functions is contained in a separate package under org.opentapas.tapear. Class ‘’Controller’’ responsible for registering the functions with the application, making them selectable with the function tab bar and switching between functions.

Client/Server Interface

Communication between the client and server is made possible by a simple and flexible set of components which were designed with the intention of adding new functionality or interface operations , with a minimum of configuration and coordination between the client developer and the server developer. This client/server framework is based on an adapted version of the "Gang of Four" command pattern, with the difference being that the command logic is distinct from the actual command. This distinction makes it possible to pass commands between the client and server, without introducing library dependencies between the software tiers.

Image:command.gif

Creating a Distributed Command in TAPAS


The following is a describes the process for developing client/server communication and logic distribution in TAPAS. [[ Client Side Development:]]

Step 1 Create a Command Subclass –

In order to create a distributed command, follow these steps:

   * Extend the org.tapas.commons.command.Command class. The convention is to name the class after the specific unit of work to be performed and append the word “Command” to the name. In this case we will create a command called GetPatientCommand, which as you would expect, is responsible for retrieving Patient objects.
 public class GetPatientCommand extends Command {
 }


Create a wrapper method around the inherited execute method.. In this case, create a method called “public Patient getPatient(String patientName)”.(Once again sticking with the naming convention). The purpose of this wrapper command is to enforce a specific interface. The actual work is performed by the inherited execute method, but since “execute” only returns generic Objects we want to enforce that this Command instance returns Patients in an enforceable manner. Furthermore, this wrapper method is also use to collect parameters specific to this unit of work. The parameter patient name in this case should be a property of the GetPatientCommand class. The following codes example illustrates the GetPatientCommand with a wrapper method:

public class GetPatientCommand extends Command {

 private String patientName;
 public GetPatientCommand() {
 }
 public List getPatient(String patientName){
   return (List)execute(this);
 }
 public void setPatientName(String patientName) {
   this.patientName = patientName;
 }
 public String getPatientName() {
   return patientName;
 }

}

You will note that this structure of this class is quite simple, and doesn’t appear to contain any business logic;that is because the purpose of a Command is to enforce an interface. The actual business logic is performed in a CommandHandler which the command will be decorated with, by the CommandFactory.


Step 2 Create a CommandHandler

   * Create a class called “TapearCommandHandler”(the convention is to append CommandHandlerto the name of the class.
   * Implement the org.tapas.commons.command.CommandHandler interface
   * Add business logic to the body of the executeMethod(Command cmd) method.
         o In this example the logic simply involves delegating the Command to the server, where it will be decorated with server side logic
     The following is the source code for the TapearCommand:

public class TapearCommandHandler implements CommandHandler {

 public TapearCommandHandler() {
 }
 public Object executeCommand(Command cmd) {
   RemoteFacade fac = RemoteFacade.getInstance();
   return fac.processCommand(cmd);
 }

}

Step 3 – Create a CommandFactory

NOTE: This section will be deprecated; in the future all configurations will be stored in a file called command-config.xml. so it won’t be necessary to subclass CommandFactory

   * Extend the class org.tapas.commons.command.CommandFactory
   * Override the initCommandRegistry() method
   * Register Commands and associated Handlers

The example source for the extended CommandFactory is as follows:

public class TapearCommandFactory

   extends CommandFactory {
 public TapearCommandFactory() {
   initCommandRegistry();
 }
 public void initCommandRegistry() {
   //just for kicks    move this junk to a properties file
   registerCommand(GetPatientCommand.class,
                   TapearCommandHandler.class);
   this.registerCommand(GetCECommand.class,
                        TapearCommandHandler.class);
 }

}

Personal tools