/** * SlingBeans - NetBeans Sling plugin * https://github.com/jkan997/SlingBeans * Licensed under Apache 2.0 license * http://www.apache.org/licenses/LICENSE-2.0 */ package org.jkan997.slingbeans.sync; import org.jkan997.slingbeans.slingfs.FileObject; import org.jkan997.slingbeans.slingfs.FileSystem; import org.jkan997.slingbeans.helper.IOHelper; import org.jkan997.slingbeans.helper.LogHelper; import java.beans.XMLDecoder; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.text.SimpleDateFormat; import java.util.Date; import java.util.LinkedHashMap; import java.util.Map; import org.jkan997.slingbeans.helper.XMLHelper; import org.jkan997.slingbeans.slingfs.FileSystemConnector; import org.openide.util.Exceptions; /** * * @author jkan997 */ public class Synchronizer { public final static String SYNC_DESCRIPTOR = "sling_sync.xml"; private FileObject remoteRoot; private Map<String, Object> fileRemoteChanges; private Map<String, Object> folderRemoteChanges; private File localRoot; SyncDescriptor descriptor = null; SyncDescriptor oldDescriptor = null; FileSystem fileSystem; private SimpleDateFormat hourSdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); private FileSystemConnector fsc = null; private Writer logWriter; public void setLogWriter(Writer logWriter) { this.logWriter = logWriter; } public void setLogOutputStream(OutputStream os) { this.logWriter = new OutputStreamWriter(os); } public Synchronizer(FileSystemConnector fsc, File localRoot) { this(fsc, null, null, null, localRoot); } public SyncDescriptor getDescriptor() { return descriptor; } public Synchronizer(FileSystemConnector fsc, String fileSystemId, String remotePath, String bndPath, File localRoot) { this.fsc = fsc; String syncDescFile = localRoot.getPath() + "/" + SYNC_DESCRIPTOR; File f = new File(syncDescFile); if (f.exists()) { descriptor = this.deserializeXMLToObject(syncDescFile); descriptor.clear(); oldDescriptor = this.deserializeXMLToObject(syncDescFile); } else { oldDescriptor = new SyncDescriptor(); descriptor = new SyncDescriptor(); descriptor.setRemoteFsId(fileSystemId); descriptor.setRemotePath(remotePath); descriptor.setBundlePath(bndPath); logSyncInfo("Remote file system: %s, remote path: %s", fileSystemId, remotePath); } this.localRoot = localRoot; } public FileObject getRemoteRoot() { if (remoteRoot == null) { String remoteFsId = descriptor.getRemoteFsId(); String remotePath = descriptor.getRemotePath(); FileSystem fs = fsc.connectToFileSystem(remoteFsId); if (fs != null) { this.remoteRoot = fs.getFileObject(remotePath, 99); } else { logSyncInfo("Unable to connect filesystem %s", remoteFsId); } } return remoteRoot; } public long lastSync() { return oldDescriptor != null ? oldDescriptor.getLastSync() : 0; } public SyncDescriptor check() { FileObject remoteRoot = getRemoteRoot(); System.out.println("LAST SYNC " + hourSdf.format(new Date(descriptor.getLastSync()))); SyncScanner fos = new SyncScanner(); fos.scan(remoteRoot, descriptor); fos.scan(localRoot, descriptor); SyncEntry[] entries = descriptor.entries(); long lastSync = lastSync(); for (SyncEntry se : entries) { if (!se.isFolder()) { if (se.getModifiedLocally() > lastSync) { se.addAction(SyncAction.COPY_TO_REMOTE); } if (se.getModifiedRemote() > lastSync) { se.addAction(SyncAction.COPY_TO_LOCAL); } } else { if (se.getModifiedLocally() == -1) { se.addAction(SyncAction.CREATE_FOLDER_LOCAL); } if (se.getModifiedRemote() == -1) { se.addAction(SyncAction.CREATE_FOLDER_REMOTE); } } if ((se.getModifiedLocally() == -1) && (se.getModifiedRemote() < lastSync)) { se.addAction(SyncAction.REMOVE_REMOTE); } if ((se.getModifiedRemote() == -1) && (se.getModifiedLocally() < lastSync)) { se.addAction(SyncAction.REMOVE_LOCAL); } } logSyncInfo("Checking for changes"); return descriptor; } public boolean hasConflict() { SyncEntry[] entries = descriptor.entries(); for (SyncEntry se : entries) { if (se.getActionCount() > 1) { return true; } } return false; } public boolean hasRemovals() { SyncEntry[] entries = descriptor.entries(); for (SyncEntry se : entries) { for (SyncAction action : se.getActions()) { if (SyncActionHelper.isRemovalAction(action)) { return true; } } } return false; } private void removeLocal(SyncEntry se) { try { String localPath = localRoot.getPath() + "/" + se.getPath(); File f = new File(localPath); f.delete(); } catch (Exception ex) { LogHelper.logError(ex); } } private void removeRemote(SyncEntry se) { try { FileObject remoteRoot = getRemoteRoot(); String remotePath = remoteRoot.getPath() + "/" + se.getPath(); FileSystem.remove(remotePath, fileRemoteChanges); } catch (Exception ex) { LogHelper.logError(ex); } } private void copyToLocal(SyncEntry se) { try { FileObject remoteRoot = getRemoteRoot(); String remotePath = remoteRoot.getPath() + "/" + se.getPath(); FileObject fo = remoteRoot.getFileSystem().getFileObject(remotePath); String localPath = localRoot.getPath() + "/" + se.getPath(); InputStream is = fo.getInputStream(); FileOutputStream fos = new FileOutputStream(localPath); IOHelper.readInputStreamToOutputStream(is, fos); fos.close(); is.close(); } catch (Exception ex) { LogHelper.logError(ex); } } private void copyToRemote(SyncEntry se) { try { FileObject remoteRoot = getRemoteRoot(); String localPath = localRoot.getPath() + "/" + se.getPath(); InputStream is = new FileInputStream(localPath); byte[] content = IOHelper.readInputStreamToBytes(is); is.close(); boolean createNew = (se.getModifiedRemote() <= 0); String remotePath = remoteRoot.getPath() + "/" + se.getPath(); FileSystem.addFileContentChanges(remotePath, content, createNew, fileRemoteChanges); } catch (Exception ex) { LogHelper.logError(ex); } } private void createFolderLocal(SyncEntry se) { try { String localPath = localRoot.getPath() + "/" + se.getPath(); File folderFile = new File(localPath); folderFile.mkdir(); } catch (Exception ex) { LogHelper.logError(ex); } } private void createFolderRemote(SyncEntry se) { try { FileObject remoteRoot = getRemoteRoot(); String remotePath = remoteRoot.getPath() + "/" + se.getPath(); FileSystem.createFolder(remotePath, folderRemoteChanges); } catch (Exception ex) { LogHelper.logError(ex); } } public FileSystem getFileSystem() { try { FileObject remoteRoot = getRemoteRoot(); return remoteRoot.getFileSystem(); } catch (Exception ex) { LogHelper.logError(ex); } return null; } public void synchronize(SyncMode mode) { if (mode == null) { mode = SyncMode.MERGE; } logSyncInfo("Sync mode %s", mode); SyncEntry[] entries = descriptor.entries(); folderRemoteChanges = new LinkedHashMap<String, Object>(); fileRemoteChanges = new LinkedHashMap<String, Object>(); for (SyncEntry se : entries) { SyncAction action = se.getAction(mode); logSyncInfo("Checking entry %s, action: %s", se.getPath(), se.getActionsStr()); if (action != null) { logSyncInfo("Executing action %s, file: %s", action, se.getPath()); if (action == SyncAction.COPY_TO_LOCAL) { copyToLocal(se); } if (action == SyncAction.CREATE_FOLDER_LOCAL) { createFolderLocal(se); } if (action == SyncAction.COPY_TO_REMOTE) { copyToRemote(se); } if (action == SyncAction.CREATE_FOLDER_REMOTE) { createFolderRemote(se); } if (action == SyncAction.REMOVE_LOCAL) { removeLocal(se); } if (action == SyncAction.REMOVE_REMOTE) { removeRemote(se); } } } FileSystem fs = getFileSystem(); for (Map.Entry<String, Object> me : folderRemoteChanges.entrySet()) { System.out.println(me.getKey() + "=" + me.getValue()); logSyncInfo("Folder update %s=%s", me.getKey(), me.getValue()); } fs.sendPost(folderRemoteChanges); for (Map.Entry<String, Object> me : fileRemoteChanges.entrySet()) { logSyncInfo("File update %s=%s", me.getKey(), me.getValue()); } fs.sendPost(fileRemoteChanges); descriptor.setLastSync(System.currentTimeMillis()); String syncDescFile = localRoot.getPath() + "/" + SYNC_DESCRIPTOR; serializeObjectToXML(syncDescFile, descriptor); /* for (Map.Entry<String,Object> me : remoteChanges.entrySet()) { System.out.println(me.getKey()+"="+me.getValue()); }*/ } public void serializeObjectToXML(String xmlFileLocation, SyncDescriptor objectToSerialize) { FileWriter fw = null; LogHelper.logInfo(this, "Serializing to file " + xmlFileLocation); try { LogHelper.logInfo(this, "Serializing to file 1"); XMLHelper xmlh = XMLHelper.getInstance(); LogHelper.logInfo(this, "Serializing to file 1a"); fw = new FileWriter(xmlFileLocation); LogHelper.logInfo(this, "Serializing to file 3"); xmlh.serialize(objectToSerialize, fw); LogHelper.logInfo(this, "Serializing to file 4"); } catch (Exception ex) { LogHelper.logError(ex); } finally { try { fw.close(); } catch (IOException ex) { LogHelper.logError(ex); } } } /** * Reads Java Bean Object From XML File */ public final SyncDescriptor deserializeXMLToObject(String xmlFileLocation) { FileReader fr = null; try { fr = new FileReader(xmlFileLocation); XMLHelper xmlh = XMLHelper.getInstance(); SyncDescriptor res = (SyncDescriptor) xmlh.deserialize(fr); return res; } catch (FileNotFoundException ex) { Exceptions.printStackTrace(ex); } finally { try { fr.close(); } catch (IOException ex) { Exceptions.printStackTrace(ex); } } return null; } private void logSyncInfo(String msg, Object... params) { LogHelper.logInfo(this, msg, params); if (logWriter != null) { String fmtMsg = String.format(msg, params); try { logWriter.append(fmtMsg); logWriter.append("\n"); } catch (IOException iOException) { } } } }