/*******************************************************************************
* Copyright (c) 2006-2010, 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, adapted from JavaAgenda
*
*******************************************************************************/
package ch.elexis.actions;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Hashtable;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.elexis.agenda.Messages;
import ch.elexis.agenda.data.Termin;
import ch.elexis.agenda.preferences.PreferenceConstants;
import ch.elexis.core.data.activator.CoreHub;
import ch.elexis.core.data.events.ElexisEventDispatcher;
import ch.elexis.core.data.preferences.CorePreferenceInitializer;
import ch.elexis.core.ui.Hub;
import ch.elexis.core.ui.preferences.PreferenceInitializer;
import ch.elexis.data.Patient;
import ch.elexis.data.PersistentObject;
import ch.elexis.data.Query;
import ch.rgw.tools.ExHandler;
import ch.rgw.tools.JdbcLink;
import ch.rgw.tools.JdbcLink.Stm;
import ch.rgw.tools.StringTool;
import ch.rgw.tools.TimeTool;
/**
* Der Synchronizer synchronisiert die lokalen Daten mit dem Agenda-Server. Ausserdem kann optional
* eine externe Agenda synchronisiert werden.
*
* @author gerry
*
*/
@Deprecated
public class Synchronizer {
private static final Logger log = LoggerFactory.getLogger(Synchronizer.class);
JdbcLink sync;
int lastSync;
static boolean pingPause = false;
private Hashtable<String, String> map;
Activator agenda;
Query<Patient> qPat = new Query<Patient>(Patient.class);
/**
* Einen neuen Synchronizer erstellen Wenn unter agenda/sync eine gültige Verbindung besteht,
* und enable auf true ist, dann erfolgt bei jedem Heartbeat eine Synchronisation (ausser, wenn
* pingPause auf true gesetzt wurde).
*/
public Synchronizer(){
if (CoreHub.globalCfg.get(PreferenceConstants.AG_SYNC_ENABLED, false) == true) {
String base = CorePreferenceInitializer.getDefaultDBPath();
String typ = CoreHub.globalCfg.get(PreferenceConstants.AG_SYNC_TYPE, "hsqldb"); //$NON-NLS-1$
String connect =
CoreHub.globalCfg.get(PreferenceConstants.AG_SYNC_CONNECTOR,
"jdbc:hsqldb:" + base + "/db"); //$NON-NLS-1$ //$NON-NLS-2$
String dbhost = CoreHub.globalCfg.get(PreferenceConstants.AG_SYNC_HOST, "localhost"); //$NON-NLS-1$
if (typ.equalsIgnoreCase("mysql")) { //$NON-NLS-1$
sync = JdbcLink.createMySqlLink(dbhost, connect);
} else if (typ.equalsIgnoreCase("postgresql")) { //$NON-NLS-1$
sync = JdbcLink.createPostgreSQLLink(dbhost, connect);
} else if (typ.equalsIgnoreCase("odbc")) { //$NON-NLS-1$
sync = JdbcLink.createODBCLink(dbhost);
} else {
sync = null;
}
if (sync != null) {
if (!sync.connect(CoreHub.globalCfg.get(PreferenceConstants.AG_SYNC_DBUSER, "sa"), //$NON-NLS-1$
CoreHub.globalCfg.get(PreferenceConstants.AG_SYNC_DBPWD, ""))) { //$NON-NLS-1$
log.warn(Messages.Synchronizer_connctNotSuccessful + sync.lastErrorString);
sync = null;
} else {
map = getBereichMapping();
}
}
}
// Sicherstellen, dass die Datenbank existiert
Termin.load("1"); //$NON-NLS-1$
lastSync = TimeTool.getTimeInSeconds();
}
/**
* Sync unterbrechen
*
* @param p
*/
static public void pause(final boolean p){
pingPause = p;
}
/**
* Synchronisation durchführen. Falls eine Verbidnung zu einer externen JavaAgenda besteht,
* werden 1. Neue Daten der externen Agenda hierher repliziert 2. Neue Daten der hiesigen Agenda
* auf die externe repliziert
*
* Danach wird in jedem Fall ein updateEvent gestartet, um die Anzeige der Agenda aufzufrischen
*/
public void doSync(){
if (pingPause) {
return;
}
pingPause = true;
if (sync != null) {
Stm stmOther = sync.getStatement();
Stm stmMine = PersistentObject.getConnection().getStatement();
PreparedStatement psInsert;
PreparedStatement psUpdate;
StringBuilder sql = new StringBuilder(200);
sql.append("SELECT * FROM agnTermine WHERE deleted='0' AND Tag=").append(JdbcLink.wrap(agenda.getActDate().toString(TimeTool.DATE_COMPACT))) //$NON-NLS-1$
.append(" AND BeiWem=").append(JdbcLink.wrap(map.get(agenda.getActResource()))); //$NON-NLS-1$
try {
// 1. Synchronisation von remote nach lokal
ResultSet res = stmOther.query(sql.toString());
while (res.next()) {
int von = res.getInt("Beginn"); //$NON-NLS-1$
int dauer = res.getInt("Dauer"); //$NON-NLS-1$
int bis = von + dauer;
int d = res.getInt("deleted"); //$NON-NLS-1$
String id = res.getString("ID"); //$NON-NLS-1$
Termin t = Termin.load(id); // Existiert dieser Termin schon
// lokal?
if ((t == null) || (t.state() < PersistentObject.EXISTS)) {
if (d != 0) { // Wenn nein, ist er sowieso gelöscht,
// dann nicht synchronisieren
continue;
}
if ((t == null) || (t.state() < PersistentObject.DELETED)) {
t = new Termin( // Sonst lokal neu erstellen
id, agenda.getActResource(), res.getString("Tag"), von, bis, //$NON-NLS-1$
res.getString("TerminTyp"), //$NON-NLS-1$
res.getString("TerminStatus") //$NON-NLS-1$
);
}
setTermin(t, res);
} else { // Termin existiert schon lokal
if (d != 0) { // remote gelöscht, dann lokal auch
// löschen.
t.delete();
} else { // Sonst nur Änderungen übertragen
int lasteditSeconds = res.getInt("lastedit"); //$NON-NLS-1$
int lasteditMinutes = lasteditSeconds / 60;
int my_lasteditMinutes = t.getLastedit();
// int my_lasteditSeconds=my_lasteditMinutes*60;
// System.out.println(t.getPersonalia()+" - "+res.getString("Personalien"));
if (my_lasteditMinutes < lasteditMinutes) { // Wenn
// remot
// neuer
// ist
t.set(
new String[] {
"Tag", "Typ", "Status", "Beginn", "Dauer", "BeiWem", "lastedit"}, new String[] { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ //$NON-NLS-7$
res.getString("Tag"), res.getString("TerminTyp"), res.getString("TerminStatus"), //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
Integer.toString(von), Integer.toString(dauer),
agenda.getActResource(), Integer.toString(lasteditMinutes)
});
setTermin(t, res);
}
}
}
}
res.close();
// 2. Synchronisation von lokal nach remote
sql.setLength(0);
// Lokale Termine
sql.append("SELECT * FROM AGNTERMINE WHERE deleted='0' AND Tag=").append(JdbcLink.wrap(agenda.getActDate().toString(TimeTool.DATE_COMPACT))) //$NON-NLS-1$
.append(" AND Bereich=").append(JdbcLink.wrap(agenda.getActResource())); //$NON-NLS-1$
res = stmMine.query(sql.toString());
psInsert =
sync.getConnection()
.prepareStatement(
"INSERT INTO agnTermine (Tag, Beginn, Dauer, BeiWem, PatID, Personalien, Grund, TerminTyp, TerminStatus , Angelegt, Lastedit, ID) VALUES (?,?,?,?,?,?,?,?,?,?,?,?);"); //$NON-NLS-1$
psUpdate =
sync.getConnection()
.prepareStatement(
"UPDATE agnTermine SET Tag=?,Beginn=?,Dauer=?,BeiWem=?,PatID=?,Personalien=?,Grund=?,TerminTyp=?,TerminStatus=?,Angelegt=?,Lastedit=? WHERE ID=?"); //$NON-NLS-1$
PreparedStatement ps;
while (res.next()) {
int myLasteditMinutes = res.getInt("lastedit"); //$NON-NLS-1$
int myLasteditSeconds = myLasteditMinutes * 60;
int otherLastSeconds =
stmOther
.queryInt("SELECT lastedit FROM agnTermine WHERE ID='" + res.getString("ID") + "'"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
int otherLastMinutes = otherLastSeconds / 60;
if (otherLastSeconds == -1) { // Termin existiert remote
// noch nicht -> erstellen
ps = psInsert;
ps.setInt(10, Integer.parseInt(Termin.createTimeStamp()));
} else { // Termin existiert remote schon -> ggf. updaten
if (myLasteditMinutes <= (otherLastMinutes)) {
continue;
}
ps = psUpdate;
ps.setInt(10, res.getInt("Angelegt")); //$NON-NLS-1$
}
String mandant = map.get(res.getString("Bereich")); //$NON-NLS-1$
if (mandant == null) {
continue;
}
ps.setString(1, res.getString("Tag")); //$NON-NLS-1$
ps.setInt(2, res.getInt("Beginn")); //$NON-NLS-1$
ps.setInt(3, res.getInt("Dauer")); //$NON-NLS-1$
ps.setString(4, mandant);
String pers = res.getString("PatID"); //$NON-NLS-1$
Patient pat = Patient.load(pers);
int nr = 0;
if (pat.state() > PersistentObject.INVALID_ID) {
nr = Integer.parseInt(pat.getPatCode());
pers = pat.getLabel();
}
ps.setInt(5, nr);
ps.setString(6, pers);
ps.setString(7, res.getString("Grund")); //$NON-NLS-1$
ps.setString(8, res.getString("TerminTyp")); //$NON-NLS-1$
ps.setString(9, res.getString("TerminStatus")); //$NON-NLS-1$
ps.setInt(11, myLasteditSeconds);
ps.setString(12, res.getString("ID")); //$NON-NLS-1$
ps.execute();
}
} catch (Exception ex) {
ExHandler.handle(ex);
} finally {
sync.releaseStatement(stmOther);
PersistentObject.getConnection().releaseStatement(stmMine);
pingPause = false;
}
}
lastSync = TimeTool.getTimeInSeconds();
pingPause = false;
ElexisEventDispatcher.reload(Termin.class);
}
private void setTermin(final Termin t, final ResultSet res) throws SQLException{
t.set("Grund", res.getString("Grund")); //$NON-NLS-1$ //$NON-NLS-2$
String pers = res.getString("Personalien"); //$NON-NLS-1$
String[] px = Termin.findID(pers);
px[1] = px[1].replaceFirst("\\([mw]\\)", ""); //$NON-NLS-1$ //$NON-NLS-2$
qPat.clear();
List<Patient> list = qPat.queryFields(new String[] {
"Name", "Vorname", "Geburtsdatum"}, px, true); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
if ((list == null) || (list.size() != 1)) {
t.set("Wer", pers); //$NON-NLS-1$
} else {
t.set("Wer", ((PersistentObject) list.get(0)).getId()); //$NON-NLS-1$
}
}
@SuppressWarnings("unchecked")
public static Hashtable<String, String> getBereichMapping(){
Hashtable<String, String> ret =
StringTool.foldStrings(CoreHub.globalCfg.get(PreferenceConstants.AG_SYNC_MAPPING, null));
if (ret == null) {
ret = new Hashtable<String, String>();
}
return ret;
}
public static void setBereichMapping(final Hashtable<String, String> map){
CoreHub.globalCfg.set(PreferenceConstants.AG_SYNC_MAPPING, StringTool.flattenStrings(map));
}
}