/**
* The contents of this file are subject to the OpenMRS Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://license.openmrs.org
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
* License for the specific language governing rights and limitations
* under the License.
*
* Copyright (C) OpenMRS, LLC. All Rights Reserved.
*/
package org.openmrs.module.sync;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openmrs.api.context.Context;
import org.openmrs.module.sync.api.SyncService;
import org.openmrs.module.sync.serialization.TimestampNormalizer;
import org.openmrs.module.sync.server.RemoteServer;
/**
* SyncSource to sync OpenMRS tables based on last_changed_local.
*/
public class SyncSourceJournal implements SyncSource {
private final Log log = LogFactory.getLog(getClass());
// constructor(s)
public SyncSourceJournal() {
}
// properties
// Public Methods
/**
* Std. method for retrieving last sync local; uses global prop, note in case of journal sync,
* we could just infer this from the status of the journal: last sync local is the date of the
* last entry with status of pending, or new
*/
public SyncPoint<Date> getLastSyncLocal() {
Date val = null;
String sVal = Context.getService(SyncService.class).getGlobalProperty(SyncConstants.LAST_SYNC_LOCAL);
try {
val = (sVal == null || "".equals(sVal)) ? null : new SimpleDateFormat(TimestampNormalizer.DATETIME_MASK)
.parse(sVal);
}
catch (ParseException e) {
log.error("Error DateFormat parsing " + sVal, e);
throw new SyncException("Error DateFormat parsing " + sVal, e);
}
return new SyncPoint<Date>(val);
}
public void setLastSyncLocal(SyncPoint p) {
String sVal = null;
sVal = (p.getValue() == null || "".equals(sVal)) ? null : new SimpleDateFormat(TimestampNormalizer.DATETIME_MASK)
.format(p.getValue());
// use getSynchronizationService to avoid logging this changes to the journal
Context.getService(SyncService.class).setGlobalProperty(SyncConstants.LAST_SYNC_LOCAL, sVal);
return;
}
/*
* Last sync remote: timestamp of the last data *received* from parent
*/
public SyncPoint<Date> getLastSyncRemote() {
Date val = null;
String sVal = Context.getService(SyncService.class).getGlobalProperty(SyncConstants.LAST_SYNC_REMOTE);
try {
val = (sVal == null || "".equals(sVal)) ? null : new SimpleDateFormat(TimestampNormalizer.DATETIME_MASK)
.parse(sVal);
}
catch (ParseException e) {
log.error("error DateFormat parsing " + sVal, e);
}
return new SyncPoint<Date>(val);
}
public void setLastSyncRemote(SyncPoint p) {
String sVal = null;
sVal = (p.getValue() == null || "".equals(sVal)) ? null : new SimpleDateFormat(TimestampNormalizer.DATETIME_MASK)
.format(p.getValue());
// use getSynchronizationService to avoid logging this changes to the journal
Context.getService(SyncService.class).setGlobalProperty(SyncConstants.LAST_SYNC_REMOTE, sVal);
return;
}
// gets the 'next' SyncPoint: in case of timestamp implementation, just get current date/time
public SyncPoint<Date> moveSyncPoint() {
return new SyncPoint<Date>(new Date());
}
// no op: journal has delete records; get 'changed' returns deleted also
public List<SyncRecord> getDeleted(SyncPoint from, SyncPoint to) throws SyncException {
List<SyncRecord> deleted = new ArrayList<SyncRecord>();
return deleted;
}
// state-based version
// no op: journal has delete records; get 'changed' returns deleted also
public List<SyncRecord> getDeleted() throws SyncException {
List<SyncRecord> deleted = new ArrayList<SyncRecord>();
return deleted;
}
// retrieve journal records > 'from' && <= 'to' && record status = 'new' or
// 'failed'
public List<SyncRecord> getChanged(SyncPoint from, SyncPoint to) throws SyncException {
List<SyncRecord> changed = new ArrayList<SyncRecord>();
try {
Date fromDate = (Date) from.getValue();
Date toDate = (Date) to.getValue();
//handle nulls
if (fromDate == null)
fromDate = new Date(0L);
if (toDate == null)
toDate = new Date(0L);
SyncService syncService = Context.getService(SyncService.class);
changed = syncService.getSyncRecordsBetween(fromDate, toDate);
}
catch (Exception e) {
// TODO
log.error("error in getChanged ", e);
}
return changed;
}
public List<SyncRecord> getChanged(Integer maxSyncRecords) throws SyncException {
List<SyncRecord> changed = new ArrayList<SyncRecord>();
try {
SyncService syncService = Context.getService(SyncService.class);
changed = syncService.getSyncRecords(SyncConstants.SYNC_TO_PARENT_STATES, maxSyncRecords, null);
}
catch (Exception e) {
// TODO
log.error("error in getChanged ", e);
}
return changed;
}
// state-based version that takes into consideration what should/shouldn't be sent to a given server
public List<SyncRecord> getChanged(RemoteServer server, Integer maxResults) throws SyncException {
List<SyncRecord> changed = new ArrayList<SyncRecord>();
try {
SyncService syncService = Context.getService(SyncService.class);
changed = syncService.getSyncRecords(SyncConstants.SYNC_TO_PARENT_STATES, server, maxResults, null);
}
catch (Exception e) {
// TODO
log.error("error in getChanged ", e);
}
return changed;
}
/*
* no-op for journal sync -- all changes (deletes, inserts, updates are received in transactional order
* via applyChanged
*/
public void applyDeleted(List<SyncRecord> records) throws SyncException {
return;
}
public void applyChanged(List<SyncRecord> records) throws SyncException {
//TODO - process the changeset
return;
}
public String getSyncSourceUuid() {
return Context.getService(SyncService.class).getGlobalProperty(SyncConstants.PROPERTY_SERVER_UUID);
}
public void setSyncSourceUuid(String uuid) {
Context.getService(SyncService.class).setGlobalProperty(SyncConstants.PROPERTY_SERVER_UUID, uuid);
return;
}
}