ch.elexis.befunde.Messwert.java Source code

Java tutorial

Introduction

Here is the source code for ch.elexis.befunde.Messwert.java

Source

/*******************************************************************************
 * Copyright (c) 2005-2011, G. Weirich and Elexis
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *    G. Weirich - initial implementation
 *******************************************************************************/

package ch.elexis.befunde;

import java.io.ByteArrayInputStream;
import java.util.Date;
import java.util.Map;

import org.eclipse.jface.dialogs.MessageDialog;

import ch.elexis.base.befunde.ACLContributor;
import ch.elexis.base.befunde.Messages;
import ch.elexis.core.data.activator.CoreHub;
import ch.elexis.data.Patient;
import ch.elexis.data.PersistentObject;
import ch.rgw.tools.ExHandler;
import ch.rgw.tools.JdbcLink;
import ch.rgw.tools.TimeTool;

//import java.io.ByteArrayInputStream;
//import java.util.Map;
//
//import org.eclipse.jface.dialogs.MessageDialog;
//
//import ch.elexis.base.befunde.Messages;
//import ch.elexis.data.Patient;
//import ch.elexis.data.PersistentObject;
//import ch.rgw.tools.ExHandler;
//import ch.rgw.tools.JdbcLink;

/**
 * Here we define our own data type for our "measurements"-Plugin. The Type is derived from
 * ch.elexis.data.PersistentObject, and thereby the management of the object persistence is
 * completely delegated to elexis. The Method getSetup() creates (if necessary) a new table for our
 * type. Some methods are required for every class derived from PersistentObject to work properly.
 * Those methods are hereafter marked with -required-
 * 
 * Hier wird ein eigener Datentyp fr unser "Messwerte"-Plugin definiert. Der Datentyp wird von
 * PersistentObject abgeleitet, was das Persistenzmanagement an Elexis delegiert. In der Methode
 * getSetup() wird wenn ntig eine neue Tabelle zur Speicherung der Daten dieses Datentyps erstellt.
 * Einige Methoden _mssen_ vorhanden sein, damit eine von PersistentObject abgeleitete Klasse
 * korrekt funktioniert. Diese sind im Folgenden mit -Zwingend- markiert.
 * 
 * @author Gerry
 * 
 */
public class Messwert extends PersistentObject {
    public static final String HASH_NAMES = "names"; //$NON-NLS-1$
    public static final String _FIELDS = "_FIELDS"; //$NON-NLS-1$
    public static final String FLD_BEFUNDE = "Befunde"; //$NON-NLS-1$
    public static final String FLD_NAME = "Name"; //$NON-NLS-1$
    public static final String FLD_PATIENT_ID = "PatientID"; //$NON-NLS-1$
    public static final int VERSION = 4;
    public static final String PLUGIN_ID = "ch.elexis.befunde"; //$NON-NLS-1$
    public static final String SETUP_SEPARATOR = ";;"; //$NON-NLS-1$
    public static final String SETUP_CHECKSEPARATOR = ":/:"; //$NON-NLS-1$
    /**
     * Name of the table. By convention, every tablename has to have its plugin ID as prefix, to
     * avoid naming conflicts. Unfortunately, this plugin was created before that convention was
     * declared and therefore the tablename ist not quite correct. We leave it for compatibility
     * reasons. If this plugin was made today, the name of the table ought to be something like
     * CH_ELEXIS_BEFUNDE_MESSWERTE
     * 
     * Name der Tabelle. Die Konvention sieht jetzt vor, dass jede Tabelle mit der Prfix ihres
     * Plugins benannt werden muss, um Namenskonflikte zu vermeiden. Wir belassen hier jetzt dennoch
     * diesen eigentlich unerwnschten Namen, um existierende Datenbanken nicht zu zerstren. Wrde
     * dieses Plugin jetzt neu erstellt, msste seine Tabelle heissen: CH_ELEXIS_BEFUNDE_MESSWERTE
     * (oder so hnlich)
     */
    private static final String TABLENAME = "ELEXISBEFUNDE"; //$NON-NLS-1$

    /**
     * -required- Here we define the mapping of table fields to class members. The first String has
     * always to be the name of the table, the other Strings are table fields, that we need as
     * members. This mapping makes ist possible to access every declared field simply by e.g.
     * get("Name") and set("Name","blabla") instead of having to fiddle around with SQL-statements.
     * Elexis convention encourrages every plugin developer strongly to use this mechanism, because
     * this ensures also the ability of elexis to run without change on different database engines.
     * 
     * The declaration of a mapping can be a simple String (as below in "Name"). In that case, the
     * name of the field is identical to the name of the member. It could as well be a modification
     * of the form "Name=TBL_USR" In that case, the member "Name" would be mapped to the table field
     * "TBL_USR". And the declaration can also be of the form "Datum=S:D:Datum". In that case,
     * PersistentObject modifies the field before passing it to the database. In this case, every
     * Date will be converted to the form yyyymmdd (TimeTool.DATE_COMPACT). Other modifyers include
     * compression of fields etc. See documentation of PersistentObject.
     * 
     * -Zwingend- Hier wird die Zuordnung von Tabellenfeldern zu Klassenmembern definiert. Der erste
     * String ist der Name der Tabelle, die weiteren Strings sind Tabellenfelder, die als Member
     * bentigt werden. Diese knnen entweder als einfaches Wort aufgefhrt werden, dann wird der
     * Member genauso heissen, wie das Tabellenfeld, und die Daten aus der Tabelle werden als
     * einfacher Text interpretiert. Oder es kann ein String der Form Name=Feld eingesetzt werden,
     * dann kann der Member anders heissen, als das Feld, und der Feldinhalt kann beim Lesen udn
     * Schreiben in bestimmter Weise umgeformt werden (Als Datum interpretiert, Komprimiert etc).
     * Nheres dazu in der Dokumenation von PersistentObject.
     */
    static {
        addMapping(TABLENAME, FLD_PATIENT_ID, FLD_NAME, DATE_COMPOUND, FLD_BEFUNDE);
    }

    /**
     * This is the only public constructor. The parameterless constructor should never be used, as
     * it does not create the object in the database. The constructor with a single string parameter
     * should never be called from outside the class itself.
     * 
     * Dies ist der einzige ffentliche Konstruktor. Der parameterlose Konstruktor sollte nie
     * verwendet werden, da er das Objekt nicht persistiert, und der Konstruktor mit einem einzelnen
     * String Element sollte nie direkt aufgerufen werden (s. dort)
     * 
     * @param pat
     *            Der Patient, dem dieser Messwert zugeordnet werden soll
     * @param name
     *            Name des Messwerts
     * @param date
     *            Datum des Messwerts
     * @param bf
     *            Der Messwert in beliebige komplexer Form, wird als Black Box betrachtet
     */
    public Messwert(Patient pat, String name, String date, Map bf) {
        create(null);
        set(new String[] { FLD_PATIENT_ID, FLD_NAME, PersistentObject.FLD_DATE }, pat.getId(), name, date); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
        setMap(FLD_BEFUNDE, bf); //$NON-NLS-1$
    }

    public String getDate() {
        return get(FLD_DATE);
    }

    public void setDate(Date date) {
        TimeTool tt = new TimeTool();
        tt.setTime(date);
        set(FLD_DATE, tt.toString(TimeTool.DATE_COMPACT));
        clearCache();
    }

    /**
     * a concise, human readable indentification for the measurement. Subclasses should always
     * override this, because the abse implementation of PersistentObject gives only an empty
     * string.
     * 
     * Eine kurze menschenlesbare Identifikation fr den Messwert liefern. Sollte berschrieben
     * werden; die Standardimplementation von PersistentObject liefert einfach einen Leerstring
     * zurck.
     */
    @Override
    public String getLabel() {
        return get(FLD_NAME); //$NON-NLS-1$
    }

    @SuppressWarnings("unchecked")
    public String getResult(String field) {
        Map<String, String> hash = getMap(FLD_BEFUNDE);
        return hash.get(field);
    }

    /**
     * -required- Name of the table, where objects of this class should be persisted. See remarks
     * above near the field TABLENAME
     * 
     * -Zwingend- Name der Tabelle, in der Objekte dieser Klasse persistiert werden sollen
     */
    @Override
    protected String getTableName() {
        return TABLENAME;
    }

    /**
     * Here are configuration details read. If reading fails, the method assumes, that the table
     * does not exist yet an creates it.
     * 
     * 
     * Hier werden Konfigurationseinzelheiten eingelesen. Wenn das Lesen fehlschlgt, nimmt die
     * Methode an, dass die Tabelle noch nicht existiert und legt sie neu an.
     * 
     * @return
     */
    @SuppressWarnings("unchecked")
    public static Messwert getSetup() {
        JdbcLink j = getConnection();
        Messwert setup = new Messwert("__SETUP__"); //$NON-NLS-1$

        if (!setup.exists()) {
            try {
                ByteArrayInputStream bais = new ByteArrayInputStream(create.getBytes("UTF-8")); //$NON-NLS-1$
                if (j.execScript(bais, true, false) == false) {
                    MessageDialog.openError(null, Messages.getString("Messwert.valuesError"), //$NON-NLS-1$
                            Messages.getString("Messwert.couldNotCreateTable")); //$NON-NLS-1$
                    return null;
                }
                Map names = setup.getMap(FLD_BEFUNDE);
                names.put("VERSION", Integer.toString(VERSION)); //$NON-NLS-1$
                setup.setMap(FLD_BEFUNDE, names);

                new ACLContributor().initializeDefaults(CoreHub.acl);
            } catch (Exception ex) {
                ExHandler.handle(ex);
            }
        } else {
            // Update from earlier format if necessary
            Map names = setup.getMap(FLD_BEFUNDE);
            String v = (String) names.get("VERSION"); //$NON-NLS-1$
            if (v == null || Integer.parseInt(v) < VERSION) {
                if (Integer.parseInt(v) < 4) {
                    createOrModifyTable("ALTER TABLE " + TABLENAME + " ADD lastupdate BIGINT;"); //$NON-NLS-1$ //$NON-NLS-2$
                }
                if (Integer.parseInt(v) < 3) {
                    if (j.DBFlavor.equalsIgnoreCase("postgresql")) { //$NON-NLS-1$
                        j.exec("ALTER TABLE " + TABLENAME + " ALTER Name TYPE VARCHAR(80);"); //$NON-NLS-1$ //$NON-NLS-2$
                    } else if (j.DBFlavor.equalsIgnoreCase("mysql")) { //$NON-NLS-1$
                        j.exec("ALTER TABLE " + TABLENAME + " MODIFY Name VARCHAR(80);"); //$NON-NLS-1$ //$NON-NLS-2$
                    }
                }
                if (Integer.parseInt(v) < 2) { // version 1 auf 2
                    j.exec("ALTER TABLE " + TABLENAME + " ADD deleted CHAR(1) default '0';"); //$NON-NLS-1$ //$NON-NLS-2$
                } else { // version 0 auf 1
                    StringBuilder titles = new StringBuilder();
                    Map.Entry[] entryset = (Map.Entry[]) names.entrySet().toArray(new Map.Entry[0]);
                    for (Map.Entry entry : entryset) {
                        String param = (String) entry.getKey();
                        if (param.equals(HASH_NAMES) || param.equals("VERSION") //$NON-NLS-1$
                                || param.matches(".+_FIELDS")) { //$NON-NLS-1$
                            continue;
                        }
                        titles.append(param).append(SETUP_SEPARATOR);
                        String vals = (String) entry.getValue();
                        StringBuilder flds = new StringBuilder();
                        for (String s : vals.split(",")) { //$NON-NLS-1$
                            flds.append(s).append(SETUP_CHECKSEPARATOR).append("s").append( //$NON-NLS-1$
                                    SETUP_SEPARATOR);
                        }
                        if (flds.length() > SETUP_CHECKSEPARATOR.length()) {
                            flds.setLength(flds.length() - SETUP_CHECKSEPARATOR.length());
                            names.put(param + _FIELDS, flds.toString());
                        }
                    }
                    if (titles.length() > SETUP_SEPARATOR.length()) {
                        titles.setLength(titles.length() - SETUP_SEPARATOR.length());
                        names.put(HASH_NAMES, titles.toString());
                    }
                }
                names.put("VERSION", Integer.toString(VERSION)); //$NON-NLS-1$
                setup.setMap(FLD_BEFUNDE, names);
            }
        }
        return setup;
    }

    /**
     * -required- This is the standard method to construct a PersistentObject from its
     * representation in the database. For semantic reasons we intenionally do not use the "new"
     * constructor for that purpose. "New" should only be used to create really "new" Objects and
     * not to load existing objects from the database. Internally, however, load simply calls
     * new(String). The static method load(String) must exist in every sublclass of
     * PersistentObject, but it can always be written just exacly as here. The method needs not to
     * guarantee that the returned object exists. It can, if desired, return a null value to
     * indicate a inexistent object. Here we return just whatever the superclass gives us.
     * 
     * -Zwingend- Dies ist die Standardmethode zum Konstruieren eines PersistentObjects aus der
     * Datenbank. Aus semantischen Grnden wurde hierfr bewusst nicht der "new" Konstruktor
     * verwendet. "New" bleibt gegen aussen fr die Erstellung "neuer" Objekte reserviert. Intern
     * allerdings ruft load einfach new(String) auf. Das kann immer exakt so formuliert werden.
     * 
     * @param id
     *            ID des zu ladenden Objektes
     * @return Das Objekt (kann auch null oder inexistent sein)
     */
    public static Messwert load(String id) {
        return new Messwert(id);
    }

    /**
     * The empty constructor is only needed by the factory and should never be public.
     * 
     * Der parameterlose Konstruktor wird nur von der Factory gebraucht und sollte nie public sein.
     */
    protected Messwert() {
    }

    /**
     * The constructror with a single String is used to load objects from the database and should
     * never be called directly. For that purpose is instead the static method load() to be used.
     * This constructor should always be defined exactly the same way as shown below. It loads the
     * object "lazily", what means that an access to the database will not occur until a member of
     * the object is needed. This means, that the constructor will always succeed, even if the
     * accessed object does not exist or is not valid. The caller could check this with exists() or
     * isValid(), but this would mean an (in most cases unneccessary= database access.
     * 
     * Der Konstruktor mit einem String dient dem Einlesen von Objekten aus der Datenbank und sollte
     * nie direkt aufgerufen werden. Hierfr dient die statische Methode load(). Dieser Konstruktor
     * sollte immer genauso definiert werden, wie hier gezeigt. Er ldt das Objekt "lazy", das
     * heisst, ein tatschlicher Zugriff auf die Datenbank erfolgt erst dann, wenn ein Member des
     * Objekts bentigt wird. Dies bedeutet aber auch, dass der Konstruktor scheinbar erfolgreich
     * war, das Objekt das er zurckliefert, aber nicht existieren oder nicht gltig sein muss. Dies
     * kann mit isValid() bzw. exists() geprft werden (Was allerdings einen meist unntigen
     * Datenbankzugriff bewirkt)
     * 
     * @param id
     */
    protected Messwert(String id) {
        super(id);
    }

    /**
     * Definition of the table in for of a create-script for JdbcLink
     * 
     * Definition de Tabelle in Form eines JdbcLink-Create-Scripts
     */
    private static final String create = "CREATE TABLE " + TABLENAME + " (" + //$NON-NLS-1$ //$NON-NLS-2$
            "ID         VARCHAR(25) primary key," + //$NON-NLS-1$
            "lastupdate BIGINT," + "deleted   CHAR(1) default '0'," + //$NON-NLS-1$ //$NON-NLS-2$
            "PatientID   VARCHAR(25)," + //$NON-NLS-1$
            "Name      VARCHAR(80)," + //$NON-NLS-1$
            "Datum      CHAR(8)," + //$NON-NLS-1$
            "Befunde    BLOB" + //$NON-NLS-1$
            ");" + //$NON-NLS-1$
            "create index idx_elbf1 on " + TABLENAME + "(Datum);" + //$NON-NLS-1$ //$NON-NLS-2$
            "create index idx_elbf2 on " + TABLENAME + "(PatientID);" + //$NON-NLS-1$ //$NON-NLS-2$
            "insert into " + TABLENAME + " (ID) values ('__SETUP__');"; //$NON-NLS-1$ //$NON-NLS-2$

}