package ilarkesto.sync; import ilarkesto.concurrent.ATask; import ilarkesto.core.logging.Log; import ilarkesto.io.IO; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.HashSet; import java.util.Set; public class SyncTask extends ATask { private static final Log LOG = Log.get(SyncTask.class); private Set<String> synced; private Processor processor = new Processor(); private SyncSource master; private SyncSource slave; private Set<String> lastItems; private SyncItem currentItem; private int totalItemCount; // --- dependencies --- private SyncSource left; private SyncSource right; private File itemsFile; public SyncTask(SyncSource left, SyncSource right, File itemsFile) { this.left = left; this.right = right; this.itemsFile = itemsFile; } // --- --- @Override protected void perform() { loadLastItems(); totalItemCount = lastItems.size(); synced = new HashSet<String>(); sync(left, right); currentItem = null; sync(right, left); currentItem = null; } private void sync(SyncSource master, SyncSource slave) { this.master = master; this.slave = slave; master.iterate(processor); } private void sync(SyncItem m, SyncItem s) { String id = m.getId(); if (synced.contains(id)) return; if (s == null) { syncMissing(m, null); return; } long diff = m.getLastModified() - s.getLastModified(); if (diff > 0) { LOG.debug(id, ":", master, "->", slave); slave.updateSyncItem(s, m); } else if (diff < 0) { LOG.debug(id, ":", slave, "->", master); master.updateSyncItem(m, s); } if (!lastItems.contains(id)) { lastItems.add(id); saveLastItems(); } synced.add(id); } private void syncMissing(SyncItem m, SyncItem s) { String id = m.getId(); if (lastItems.contains(id)) { // item deleted LOG.debug(id, ": X", master); master.deleteSyncItem(m); lastItems.remove(id); } else { // item created LOG.debug(id, ":", master, "->", slave); slave.updateSyncItem(s, m); lastItems.add(id); } saveLastItems(); } private void saveLastItems() { PrintWriter out; try { out = new PrintWriter(new BufferedWriter(new FileWriter(itemsFile))); } catch (IOException ex) { throw new RuntimeException(ex); } for (String id : lastItems) { out.println(id); } IO.close(out); } private void loadLastItems() { lastItems = new HashSet<String>(); if (!itemsFile.exists()) { LOG.info("Items file does not exist. Must be first sync.", itemsFile.getPath()); return; } BufferedReader in; try { in = new BufferedReader(new FileReader(itemsFile)); String line; while ((line = in.readLine()) != null) { line = line.trim(); if (line.length() == 0) continue; lastItems.add(line); } } catch (IOException ex) { throw new RuntimeException(ex); } IO.close(in); return; } @Override public String getProgressMessage() { return currentItem == null ? super.getProgressMessage() : currentItem.getId(); } @Override public float getProgress() { if (totalItemCount == 0) return super.getProgress(); int count = synced.size(); return (float) count / (float) totalItemCount; } private class Processor implements SyncItemProcessor { @Override public void process(SyncItem m) { currentItem = m; SyncItem s = slave.getSyncItem(m.getId()); sync(m, s); } } }