ch.elexis.Hub.java Source code

Java tutorial

Introduction

Here is the source code for ch.elexis.Hub.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;

import java.io.File;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;

import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;

import ch.elexis.actions.ElexisEvent;
import ch.elexis.actions.ElexisEventDispatcher;
import ch.elexis.actions.GlobalActions;
import ch.elexis.actions.Heartbeat;
import ch.elexis.actions.Heartbeat.HeartListener;
import ch.elexis.admin.AccessControl;
import ch.elexis.data.Anwender;
import ch.elexis.data.Mandant;
import ch.elexis.data.Patient;
import ch.elexis.data.PersistentObject;
import ch.elexis.data.PersistentObjectFactory;
import ch.elexis.data.Query;
import ch.elexis.data.Reminder;
import ch.elexis.elexisevent.PatientEventListener;
import ch.elexis.preferences.PreferenceConstants;
import ch.elexis.preferences.PreferenceInitializer;
import ch.elexis.util.FileUtility;
import ch.elexis.util.Log;
import ch.elexis.util.PlatformHelper;
import ch.elexis.util.SWTHelper;
import ch.rgw.io.LockFile;
import ch.rgw.io.Settings;
import ch.rgw.io.SqlSettings;
import ch.rgw.io.SysSettings;
import ch.rgw.tools.ExHandler;
import ch.rgw.tools.StringTool;
import ch.rgw.tools.TimeTool;
import ch.rgw.tools.VersionInfo;

/**
 * Diese Klasse ist der OSGi-Activator und steuert somit Start und Ende der Anwendung. Ganz frh
 * (vor dem Initialisieren der anwendung) und ganz spt (unmittelbar vor dem Entfernen der
 * Anwendung) notwendige Schritte mssen hier durchgefhrt werden. Ausserdem werden hier globale
 * Variablen und Konstanten angelegt.
 */
public class Hub extends AbstractUIPlugin {
    // Globale Konstanten
    public final boolean DEBUGMODE;
    public static final String APPLICATION_NAME = "Elexis"; //$NON-NLS-1$
    public static final String PLUGIN_ID = "ch.elexis.core.data"; //$NON-NLS-1$
    public static final String COMMAND_PREFIX = PLUGIN_ID + ".commands."; //$NON-NLS-1$
    static final String neededJRE = "1.6.0"; //$NON-NLS-1$
    public static final String Version = "2.3.0.dev-qualifier"; //$NON-NLS-1$
    public static final String DBVersion = "1.8.16"; //$NON-NLS-1$
    public static final String SWTBOTTEST_KEY = "ch.elexis.swtbottest.key"; //$NON-NLS-1$
    static final String[] mine = { "ch.elexis", "ch.rgw" }; //$NON-NLS-1$ //$NON-NLS-2$
    private static List<ShutdownJob> shutdownJobs = new LinkedList<ShutdownJob>();

    // Globale Variable
    /**
     * Suche externe Config - poor mans dependency -> see
     * ch.elexis.ElexisConfigurationConstants.java
     */
    public static boolean ecc = ElexisConfigurationConstants.init();

    /** Das Singleton-Objekt dieser Klasse */
    public static Hub plugin;

    /** Lokale Einstellungen (Werden in der Registry bzw. ~/.java gespeichert) */
    public static Settings localCfg;

    /** Globale Einstellungen (Werden in der Datenbank gespeichert) */
    public static Settings globalCfg;

    /** Anwenderspezifische Einstellungen (Werden in der Datenbank gespeichert) */
    public static Settings userCfg;

    /** Mandantspezifische EInstellungen (Werden in der Datenbank gespeichert) */
    public static Settings mandantCfg;

    /** Zentrale Logdatei */
    public static Log log;

    /** Globale Aktionen */
    public static GlobalActions mainActions;

    /** Der aktuell angemeldete Anwender */
    public static Anwender actUser;

    /** Der Mandant, auf dessen namen die aktuellen Handlungen gehen */
    public static Mandant actMandant;

    /** Die zentrale Zugriffskontrolle */
    public static final AccessControl acl = new AccessControl();

    /** Der Initialisierer fr die Voreinstellungen */
    public static final PreferenceInitializer pin = new PreferenceInitializer();;

    /** Factory fr interne PersistentObjects */
    public static final PersistentObjectFactory poFactory = new PersistentObjectFactory();

    /** Heartbeat */
    public static Heartbeat heart;

    /**
     * Beschreibbares Verzeichnis fr userspezifische Konfigurationsdaten etc. Achtung: "User" meint
     * hier: den eingeloggten Betriebssystem-User, nicht den Elexis-User. In Windows wird userDir
     * meist %USERPROFILE%\elexis sein, in Linux ~./elexis. Es kann mit getWritableUserDir() geholt
     * werden.
     * */
    private static File userDir;

    /**
     * The listener for patient events
     */
    private final PatientEventListener eeli_pat = new PatientEventListener();

    /**
     * Constructor. No Eclipse dependend initializations here because the Platform has not been
     * iniatialized fully yet
     */
    public Hub() {
        if ("true".equals(System.getProperty("DEBUGMODE"))) {
            DEBUGMODE = true;
        } else {
            DEBUGMODE = false;
        }
        log = Log.get("Elexis startup"); //$NON-NLS-1$
        getWritableUserDir();
        localCfg = new SysSettings(SysSettings.USER_SETTINGS, Desk.class);
        setUserDir(userDir);

    }

    /*
     * called in startup sequence after initialization of the platform but before initalization of
     * the workbench
     */
    private static void initializeLog(final Settings cfg) {
        // Not much to be done, as we use now ch.qos.logback and its configuration/logback.xml
        Log.setAlertLevel(cfg.get(PreferenceConstants.ABL_LOGALERT, Log.FATALS));
        ExHandler.setClasses(mine);

    }

    private static void initializeLock() {
        final int timeoutSeconds = 600;
        try {
            final LockFile lockfile = new LockFile(userDir, "elexislock", 4, timeoutSeconds); //$NON-NLS-1$
            final int n = lockfile.lock();
            if (n == 0) {
                SWTHelper.alert(Messages.Hub_toomanyinstances, Messages.Hub_nomoreinstances);
                System.exit(2);
            } else {
                HeartListener lockListener = new HeartListener() {
                    long timeSet;

                    public void heartbeat() {
                        long now = System.currentTimeMillis();
                        if ((now - timeSet) > timeoutSeconds) {
                            lockfile.updateLock(n);
                            timeSet = now;
                        }
                    }
                };
                heart.addListener(lockListener, Heartbeat.FREQUENCY_LOW);
            }
        } catch (IOException ex) {
            log.log("Can not aquire lock file in " + userDir + "; " + ex.getMessage(), Log.ERRORS); //$NON-NLS-1$
        }
    }

    public static int getSystemLogLevel() {
        return localCfg.get(PreferenceConstants.ABL_LOGLEVEL, Log.ERRORS);
    }

    @Override
    public void start(final BundleContext context) throws Exception {
        super.start(context);
        plugin = this;
        startUpBundle();
        ElexisEventDispatcher.getInstance().addListeners(eeli_pat);
        // ElexisEventCascade.getInstance().start();
    }

    @Override
    public void stop(final BundleContext context) throws Exception {
        // ElexisEventCascade.getInstance().stop();
        ElexisEventDispatcher.getInstance().removeListeners(eeli_pat);
        ElexisEventDispatcher.getInstance().dump();
        heart.stop();
        plugin = null;
        PersistentObject.disconnect();
        globalCfg = null;
        super.stop(context);
    }

    /**
     * Hier stehen Aktionen, die ganz frh, noch vor dem Starten der Workbench, durchgefhrt werden
     * sollen.
     */
    public void startUpBundle() {
        String[] args = Platform.getApplicationArgs();
        String config = "default"; //$NON-NLS-1$
        for (String s : args) {
            if (s.startsWith("--use-config=")) { //$NON-NLS-1$
                String[] c = s.split("="); //$NON-NLS-1$
                config = c[1];
                localCfg = localCfg.getBranch(config, true);
            } else if (s.startsWith("--plaf=")) { //$NON-NLS-1$
                String[] c = s.split("="); //$NON-NLS-1$
                String plaf = c[1];
                localCfg.set(PreferenceConstants.USR_PLAF, plaf);
                localCfg.flush();
            }
        }
        initializeLog(localCfg);
        log.log(Messages.Hub_12 + config, Log.INFOS);
        // Damit Anfragen auf userCfg und mandantCfg bei nicht eingeloggtem User
        // keine NPE werfen
        userCfg = localCfg;
        mandantCfg = localCfg;

        String basePath = FileUtility.getFilepath(PlatformHelper.getBasePath("ch.elexis")); //$NON-NLS-1$
        localCfg.set("elexis-basepath", FileUtility.getFilepath(basePath)); //$NON-NLS-1$

        // Java Version prfen
        VersionInfo vI = new VersionInfo(System.getProperty("java.version", "0.0.0")); //$NON-NLS-1$ //$NON-NLS-2$
        log.log(getId() + "; Java: " + vI.version() + "\nencoding: " + System.getProperty("file.encoding"),
                Log.SYNCMARK);

        if (vI.isOlder(neededJRE)) {
            String msg = Messages.Hub_21 + neededJRE;
            getLog().log(new Status(Status.ERROR, "ch.elexis", //$NON-NLS-1$
                    -1, msg, new Exception(msg)));
            SWTHelper.alert(Messages.Hub_23, msg);
            log.log(msg, Log.FATALS);
        }
        log.log(Messages.Hub_24 + getBasePath(), Log.INFOS);
        pin.initializeDefaultPreferences();

        heart = Heartbeat.getInstance();
        initializeLock();
    }

    /**
     * Programmende
     */
    public static void postShutdown() {
        // heart.stop();
        // JobPool.getJobPool().dispose();
        if (Hub.actUser != null) {
            Anwender.logoff();
        }
        if (globalCfg != null) {
            // We should not flush at this point, since this might
            // overwrite other client's
            // settings
            // acl.flush();
            // globalCfg.flush();
        }

        // shutdownjobs are executed after the workbench has been shut down.
        // So those jobs must not use any of the workbench's resources.
        if ((shutdownJobs != null) && (shutdownJobs.size() > 0)) {
            Shell shell = new Shell(Display.getDefault());
            MessageDialog dlg = new MessageDialog(shell, Messages.Hub_title_configuration, Dialog.getDefaultImage(),
                    Messages.Hub_message_configuration, SWT.ICON_INFORMATION, new String[] {}, 0);
            dlg.setBlockOnOpen(false);
            dlg.open();
            for (ShutdownJob job : shutdownJobs) {
                try {
                    job.doit();
                } catch (Exception e) {
                    log.log("Error starting job: " + e.getMessage(), Log.ERRORS);
                }
            }
            dlg.close();
        }
    }

    public static void setMandant(final Mandant m) {
        if (actMandant != null) {
            // Hub.mandantCfg.dump(null);
            mandantCfg.flush();
        }
        if (m == null) {
            if ((mainActions != null) && (mainActions.mainWindow != null)
                    && (mainActions.mainWindow.getShell() != null)) {
                mandantCfg = userCfg;
            }
        } else {
            mandantCfg = new SqlSettings(PersistentObject.getConnection(), "USERCONFIG", "Param", "Value", //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$
                    "UserID=" + m.getWrappedId()); //$NON-NLS-1$
        }
        actMandant = m;
        setWindowText(null);
        ElexisEventDispatcher.getInstance()
                .fire(new ElexisEvent(Hub.actMandant, Mandant.class, ElexisEvent.EVENT_MANDATOR_CHANGED));
    }

    public static void setWindowText(Patient pat) {
        StringBuilder sb = new StringBuilder();
        sb.append("Elexis ").append(Version).append(" - "); //$NON-NLS-1$ //$NON-NLS-2$
        if (Hub.actUser == null) {
            sb.append(Messages.Hub_nouserloggedin);
        } else {
            sb.append(" ").append(Hub.actUser.getLabel()); //$NON-NLS-1$
        }
        if (Hub.actMandant == null) {
            sb.append(Messages.Hub_nomandantor);

        } else {
            sb.append(" / ").append(Hub.actMandant.getLabel()); //$NON-NLS-1$
        }
        if (pat == null) {
            pat = (Patient) ElexisEventDispatcher.getSelected(Patient.class);
        }
        if (pat == null) {
            sb.append(Messages.Hub_nopatientselected);
        } else {
            String nr = pat.getPatCode();
            String alter = pat.getAlter();
            sb.append("  / ").append(pat.getLabel()).append("(").append(alter).append(") - ") //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                    .append("[").append(nr).append("]"); //$NON-NLS-1$ //$NON-NLS-2$

            if (Reminder.findForPatient(pat, Hub.actUser).size() != 0) {
                sb.append(Messages.Hub_message_reminders);
            }
            String act = new TimeTool().toString(TimeTool.DATE_COMPACT);
            TimeTool ttPatg = new TimeTool();
            if (ttPatg.set(pat.getGeburtsdatum())) {
                String patg = ttPatg.toString(TimeTool.DATE_COMPACT);
                if (act.substring(4).equals(patg.substring(4))) {
                    sb.append(Messages.Hub_message_birthday);
                }
            }
        }
        if (mainActions.mainWindow != null) {
            Shell shell = mainActions.mainWindow.getShell();
            if ((shell != null) && (!shell.isDisposed())) {
                mainActions.mainWindow.getShell().setText(sb.toString());
            }
        }
    }

    /**
     * Returns an image descriptor for the image file at the given plug-in relative path.
     * 
     * @param path
     *            the path
     * @return the image descriptor
     */
    public static ImageDescriptor getImageDescriptor(final String path) {
        return AbstractUIPlugin.imageDescriptorFromPlugin("ch.elexis", path); //$NON-NLS-1$
    }

    public static String getId() {
        StringBuilder sb = new StringBuilder();
        sb.append(APPLICATION_NAME).append(" v.").append(Version).append("\n").append(getRevision(true))
                .append("\n").append(System.getProperty("os.name")).append(StringConstants.SLASH)
                .append(System.getProperty("os.version")).append(StringConstants.SLASH)
                .append(System.getProperty("os.arch")); //$NON-NLS-1$
        return sb.toString();
    }

    public static String getRevision(final boolean withDate) {
        StringBuilder sb = new StringBuilder();
        Bundle bundle = plugin.getBundle();
        org.osgi.framework.Version v = bundle.getVersion();
        sb.append("[Bundle info: ").append(v.toString());
        String check = System.getProperty("inEclipse"); //$NON-NLS-1$
        if (check != null && check.equals("true")) { //$NON-NLS-1$
            sb.append(" (developer version)");
        }
        if (withDate) {
            long lastModify = bundle.getLastModified();
            TimeTool tt = new TimeTool(lastModify);
            sb.append("; ").append(tt.toString(TimeTool.DATE_ISO));
        }
        sb.append("]");
        return sb.toString();
    }

    /**
     * get the base directory of this currently running elexis application
     * 
     * @return the topmost directory of this application or null if this information could not be
     *         retrieved
     */
    public static String getBasePath() {
        return PlatformHelper.getBasePath(PLUGIN_ID);
    }

    /**
     * get a list af all users known to this system
     */
    public static List<Anwender> getUserList() {
        Query<Anwender> qbe = new Query<Anwender>(Anwender.class);
        return qbe.execute();
    }

    /**
     * get a list of all mandators known to this system
     */
    public static List<Mandant> getMandantenList() {
        Query<Mandant> qbe = new Query<Mandant>(Mandant.class);
        return qbe.execute();
    }

    /**
     * get the currently active Shell. If no such Shell exists, it will be created using dhe default
     * Display.
     * 
     * @return always a valid shell. Never null
     */
    public static Shell getActiveShell() {
        if (plugin != null) {
            IWorkbench wb = plugin.getWorkbench();
            if (wb != null) {
                IWorkbenchWindow win = wb.getActiveWorkbenchWindow();
                if (win != null) {
                    return win.getShell();
                }
            }
        }
        Display dis = Desk.getDisplay();
        if (dis == null) {
            dis = PlatformUI.createDisplay();
        }
        return new Shell(dis);
    }

    /**
     * A job that executes during stop() of the plugin (that means after the workbench is shut down
     * 
     * @author gerry
     * 
     */
    public interface ShutdownJob {
        /**
         * do whatever you like
         */
        public void doit() throws Exception;
    }

    /**
     * Add a ShutdownJob to the list of jobs that has to be done after the Elexis workbench was shut
     * down.
     * 
     * @param job
     */
    public static void addShutdownJob(final ShutdownJob job) {
        if (!shutdownJobs.contains(job)) {
            shutdownJobs.add(job);
        }
    }

    public void setUserDir(File dir) {
        userDir = dir;
        localCfg.set("elexis-userDir", dir.getAbsolutePath()); //$NON-NLS-1$
    }

    /**
     * return a directory suitable for plugin specific configuration data. If no such dir exists, it
     * will be created. If it could not be created, the application will refuse to start.
     * 
     * @return a directory that exists always and is always writable and readable for plugins of the
     *         currently running elexis instance. Caution: this directory is not necessarily shared
     *         among different OS-Users. In Windows it is normally %USERPROFILE%\elexis, in Linux
     *         ~./elexis
     */
    public static File getWritableUserDir() {
        if (userDir == null) {
            String userhome = null;

            if (localCfg != null) {
                userhome = localCfg.get("elexis-userDir", null); //$NON-NLS-1$
            }
            if (userhome == null) {
                userhome = System.getProperty("user.home"); //$NON-NLS-1$
            }
            if (StringTool.isNothing(userhome)) {
                userhome = System.getProperty("java.io.tempdir"); //$NON-NLS-1$
            }
            userDir = new File(userhome, "elexis"); //$NON-NLS-1$
        }
        if (!userDir.exists()) {
            if (!userDir.mkdirs()) {
                System.err.print("fatal: could not create Userdir"); //$NON-NLS-1$
                SWTHelper.alert("Panic exit", "could not create userdir " //$NON-NLS-1$ //$NON-NLS-2$
                        + userDir.getAbsolutePath());
                System.exit(-5);
            }
        }
        return userDir;
    }

    /**
     * Return a directory suitable for temporary files. Most probably this will be a default tempdir
     * provided by the os. If none such exists, it will be the user dir.
     * 
     * @return always a valid and writable directory.
     */
    public static File getTempDir() {
        File ret = null;
        String temp = System.getProperty("java.io.tmpdir"); //$NON-NLS-1$
        if (!StringTool.isNothing(temp)) {
            ret = new File(temp);
            if (ret.exists() && ret.isDirectory()) {
                return ret;
            } else {
                if (ret.mkdirs()) {
                    return ret;
                }
            }
        }
        return getWritableUserDir();
    }

    /**
     * Return the name of a config instance, the user chose. This is just the valuie of the
     * -Dconfig=xx runtime value or "default" if no -Dconfig was set
     */
    public static String getCfgVariant() {
        String config = System.getProperty("config");
        return config == null ? "default" : config;
    }
}