@Override public void onUpdate(SyncAccount syncAccount, Map<String, Object> originalValues) { if (!originalValues.containsKey("active")) { return; } List<Long> activeSyncAccountIds = SyncAccountService.getActiveSyncAccountIds(); if ((Boolean) originalValues.get("active")) { activeSyncAccountIds.remove(syncAccount.getSyncAccountId()); try { SyncEngine.cancelSyncAccountTasks(syncAccount.getSyncAccountId()); } catch (Exception e) { _logger.error(e.getMessage(), e); } } else { activeSyncAccountIds.add(syncAccount.getSyncAccountId()); try { SyncEngine.scheduleSyncAccountTasks(syncAccount.getSyncAccountId()); } catch (Exception e) { _logger.error(e.getMessage(), e); } } SyncAccountService.setActiveSyncAccountIds(activeSyncAccountIds); }
protected static void doDeleteSyncFile(SyncFile syncFile, boolean notify) throws SQLException { if (syncFile.isFile()) { final Path filePath = IODeltaUtil.getChecksumsFilePath(syncFile); Runnable runnable = new Runnable() { @Override public void run() { try { Files.deleteIfExists(filePath); } catch (IOException ioe) { _logger.error(ioe.getMessage(), ioe); } } }; ExecutorService executorService = SyncEngine.getExecutorService(); executorService.execute(runnable); } _syncFilePersistence.delete(syncFile, notify); }
@Override public void onRemove(SyncAccount syncAccount) { List<Long> activeSyncAccountIds = SyncAccountService.getActiveSyncAccountIds(); activeSyncAccountIds.remove(syncAccount.getSyncAccountId()); SyncAccountService.setActiveSyncAccountIds(activeSyncAccountIds); try { SyncEngine.cancelSyncAccountTasks(syncAccount.getSyncAccountId()); } catch (Exception e) { _logger.error(e.getMessage(), e); } }
/** @author Michael Young */ public class SyncWatchEventProcessor implements Runnable { public SyncWatchEventProcessor(long syncAccountId) { _syncAccountId = syncAccountId; SyncFileModelListener syncFileModelListener = new SyncFileModelListener() { @Override public void onRemove(SyncFile syncFile) { _dependentSyncWatchEventsMaps.remove(syncFile.getFilePathName()); _pendingTypePKSyncFileIds.remove(syncFile.getTypePK()); } @Override public void onUpdate(SyncFile syncFile, Map<String, Object> originalValues) { if ((syncFile.getSyncAccountId() != _syncAccountId) || (syncFile.getTypePK() == 0) || (!originalValues.containsKey("state") && !originalValues.containsKey("typePK"))) { return; } List<SyncWatchEvent> syncWatchEvents = _dependentSyncWatchEventsMaps.remove(syncFile.getFilePathName()); if (syncWatchEvents == null) { return; } if (syncFile.getTypePK() > 0) { _pendingTypePKSyncFileIds.remove(syncFile.getSyncFileId()); } for (SyncWatchEvent syncWatchEvent : syncWatchEvents) { try { if (_logger.isDebugEnabled()) { _logger.debug( "Processing queued event {} {}", syncWatchEvent.getFilePathName(), syncWatchEvent.getEventType()); } processSyncWatchEvent(syncWatchEvent); } catch (Exception e) { _logger.error(e.getMessage(), e); } } } }; SyncFileService.registerModelListener(syncFileModelListener); } public boolean isInProgress() { if (SyncWatchEventService.hasSyncWatchEvents(_syncAccountId) || SyncFileService.hasSyncFiles(_syncAccountId, SyncFile.UI_EVENT_DOWNLOADING) || SyncFileService.hasSyncFiles(_syncAccountId, SyncFile.UI_EVENT_UPLOADING)) { return true; } return false; } @Override public void run() { try { SyncAccount syncAccount = SyncAccountService.fetchSyncAccount(_syncAccountId); if (syncAccount.getState() != SyncAccount.STATE_CONNECTED) { return; } doRun(); } catch (Exception e) { _logger.error(e.getMessage(), e); } BatchEventManager.fireBatchEvents(); } protected void addFile(SyncWatchEvent syncWatchEvent) throws Exception { final Path targetFilePath = Paths.get(syncWatchEvent.getFilePathName()); if (FileUtil.notExists(targetFilePath) || sanitizeFileName(targetFilePath) || isInErrorState(targetFilePath)) { return; } Path parentTargetFilePath = targetFilePath.getParent(); final SyncFile parentSyncFile = SyncFileService.fetchSyncFile(parentTargetFilePath.toString()); if ((parentSyncFile == null) || (!parentSyncFile.isSystem() && (parentSyncFile.getTypePK() == 0))) { queueSyncWatchEvent(parentTargetFilePath.toString(), syncWatchEvent); return; } SyncFile syncFile = SyncFileService.fetchSyncFile(targetFilePath.toString()); if (syncFile == null) { syncFile = SyncFileService.fetchSyncFile(FileKeyUtil.getFileKey(targetFilePath)); if (!verifySite(syncFile, parentSyncFile)) { syncFile = null; } } if (syncFile == null) { Runnable runnable = new Runnable() { @Override public void run() { try { SyncSite syncSite = SyncSiteService.fetchSyncSite(parentSyncFile.getRepositoryId(), _syncAccountId); if ((syncSite == null) || !syncSite.isActive() || !FileUtil.checkFilePath(targetFilePath)) { return; } SyncFileService.addFileSyncFile( targetFilePath, parentSyncFile.getTypePK(), parentSyncFile.getRepositoryId(), _syncAccountId); } catch (Exception e) { if (SyncFileService.fetchSyncFile(targetFilePath.toString()) == null) { _logger.error(e.getMessage(), e); } } } }; _executorService.execute(runnable); return; } Path sourceFilePath = Paths.get(syncFile.getFilePathName()); if (targetFilePath.equals(sourceFilePath)) { if (isPendingTypePK(syncFile) || (syncFile.getState() == SyncFile.STATE_IN_PROGRESS)) { queueSyncWatchEvent(syncFile.getFilePathName(), syncWatchEvent); return; } if (FileUtil.isModified(syncFile)) { SyncFileService.updateFileSyncFile(targetFilePath, _syncAccountId, syncFile); } } else if (FileUtil.exists(sourceFilePath)) { try { if ((Files.size(targetFilePath) == 0) || FileUtil.isModified(syncFile, targetFilePath) || isInErrorState(sourceFilePath)) { SyncFileService.addFileSyncFile( targetFilePath, parentSyncFile.getTypePK(), parentSyncFile.getRepositoryId(), _syncAccountId); } else { SyncFileService.copySyncFile( syncFile, targetFilePath, parentSyncFile.getTypePK(), parentSyncFile.getRepositoryId(), _syncAccountId); } } catch (Exception e) { if (SyncFileService.fetchSyncFile(targetFilePath.toString()) == null) { _logger.error(e.getMessage(), e); } } return; } else if (parentTargetFilePath.equals(sourceFilePath.getParent())) { if (isPendingTypePK(syncFile) || (syncFile.getState() == SyncFile.STATE_IN_PROGRESS)) { queueSyncWatchEvent(syncFile.getFilePathName(), syncWatchEvent); return; } SyncFileService.updateFileSyncFile(targetFilePath, _syncAccountId, syncFile); } else { if (isPendingTypePK(syncFile) || (syncFile.getState() == SyncFile.STATE_IN_PROGRESS)) { queueSyncWatchEvent(syncFile.getFilePathName(), syncWatchEvent); return; } SyncFileService.moveFileSyncFile( targetFilePath, parentSyncFile.getTypePK(), _syncAccountId, syncFile); Path sourceFileNameFilePath = sourceFilePath.getFileName(); if (!sourceFileNameFilePath.equals(targetFilePath.getFileName())) { SyncFileService.updateFileSyncFile(targetFilePath, _syncAccountId, syncFile); } } SyncAccount syncAccount = SyncAccountService.fetchSyncAccount(_syncAccountId); if (syncAccount.getState() == SyncAccount.STATE_CONNECTED) { SyncWatchEvent relatedSyncWatchEvent = SyncWatchEventService.fetchSyncWatchEvent( SyncWatchEvent.EVENT_TYPE_DELETE, syncWatchEvent.getFilePathName(), syncWatchEvent.getTimestamp()); if (relatedSyncWatchEvent != null) { _processedSyncWatchEventIds.add(relatedSyncWatchEvent.getSyncWatchEventId()); } } } protected void addFolder(SyncWatchEvent syncWatchEvent) throws Exception { Path targetFilePath = Paths.get(syncWatchEvent.getFilePathName()); if (sanitizeFileName(targetFilePath) || isInErrorState(targetFilePath)) { return; } Path parentTargetFilePath = targetFilePath.getParent(); SyncFile parentSyncFile = SyncFileService.fetchSyncFile(parentTargetFilePath.toString()); if ((parentSyncFile == null) || (!parentSyncFile.isSystem() && (parentSyncFile.getTypePK() == 0))) { queueSyncWatchEvent(parentTargetFilePath.toString(), syncWatchEvent); return; } SyncFile syncFile = SyncFileService.fetchSyncFile(targetFilePath.toString()); if (syncFile == null) { syncFile = SyncFileService.fetchSyncFile(FileKeyUtil.getFileKey(targetFilePath)); if (!verifySite(syncFile, parentSyncFile)) { syncFile = null; } } if (syncFile == null) { SyncFileService.addFolderSyncFile( targetFilePath, parentSyncFile.getTypePK(), parentSyncFile.getRepositoryId(), _syncAccountId); return; } Path sourceFilePath = Paths.get(syncFile.getFilePathName()); if (targetFilePath.equals(sourceFilePath)) { FileKeyUtil.writeFileKey(targetFilePath, String.valueOf(syncFile.getSyncFileId()), true); } else if (FileUtil.exists(sourceFilePath)) { SyncFileService.addFolderSyncFile( targetFilePath, parentSyncFile.getTypePK(), parentSyncFile.getRepositoryId(), _syncAccountId); return; } else if (parentTargetFilePath.equals(sourceFilePath.getParent())) { if (isPendingTypePK(syncFile)) { queueSyncWatchEvent(syncFile.getFilePathName(), syncWatchEvent); return; } SyncFileService.updateFolderSyncFile(targetFilePath, _syncAccountId, syncFile); } else { if (isPendingTypePK(syncFile)) { queueSyncWatchEvent(syncFile.getFilePathName(), syncWatchEvent); return; } SyncFileService.moveFolderSyncFile( targetFilePath, parentSyncFile.getTypePK(), _syncAccountId, syncFile); Path sourceFileNameFilePath = sourceFilePath.getFileName(); if (!sourceFileNameFilePath.equals(targetFilePath.getFileName())) { SyncFileService.updateFolderSyncFile(targetFilePath, _syncAccountId, syncFile); } } SyncAccount syncAccount = SyncAccountService.fetchSyncAccount(_syncAccountId); if (syncAccount.getState() == SyncAccount.STATE_CONNECTED) { SyncWatchEvent relatedSyncWatchEvent = SyncWatchEventService.fetchSyncWatchEvent( SyncWatchEvent.EVENT_TYPE_DELETE, syncWatchEvent.getFilePathName(), syncWatchEvent.getTimestamp()); if (relatedSyncWatchEvent != null) { _processedSyncWatchEventIds.add(relatedSyncWatchEvent.getSyncWatchEventId()); } } } protected void deleteFile(SyncWatchEvent syncWatchEvent) throws Exception { Path filePath = Paths.get(syncWatchEvent.getFilePathName()); SyncFile syncFile = SyncFileService.fetchSyncFile(filePath.toString()); if ((syncFile == null) || !FileUtil.notExists(Paths.get(syncFile.getFilePathName()))) { return; } else if ((syncFile.getState() == SyncFile.STATE_ERROR) || (syncFile.getState() == SyncFile.STATE_UNSYNCED)) { SyncFileService.deleteSyncFile(syncFile, false); return; } else if (syncFile.getState() == SyncFile.STATE_IN_PROGRESS) { Set<Event> events = FileEventManager.getEvents(syncFile.getSyncFileId()); for (Event event : events) { event.cancel(); } if (isPendingTypePK(syncFile)) { SyncFileService.deleteSyncFile(syncFile); return; } } else if (isPendingTypePK(syncFile)) { queueSyncWatchEvent(syncFile.getFilePathName(), syncWatchEvent); return; } String type = syncFile.getType(); if (type.equals(SyncFile.TYPE_FILE)) { FileEventUtil.deleteFile(_syncAccountId, syncFile); } else { FileEventUtil.deleteFolder(_syncAccountId, syncFile); } } protected void doRun() throws Exception { SyncWatchEvent lastSyncWatchEvent = SyncWatchEventService.getLastSyncWatchEvent(_syncAccountId); if (lastSyncWatchEvent == null) { return; } long delta = System.currentTimeMillis() - lastSyncWatchEvent.getTimestamp(); if (delta <= 500) { SyncEngineUtil.fireSyncEngineStateChanged( _syncAccountId, SyncEngineUtil.SYNC_ENGINE_STATE_PROCESSING); return; } if (_logger.isTraceEnabled()) { _logger.trace("Processing Sync watch events"); } _pendingTypePKSyncFileIds.clear(); List<SyncWatchEvent> syncWatchEvents = null; if (OSDetector.isApple()) { syncWatchEvents = SyncWatchEventService.findBySyncAccountId(_syncAccountId); } else { syncWatchEvents = SyncWatchEventService.findBySyncAccountId(_syncAccountId, "eventType", true); } for (SyncWatchEvent syncWatchEvent : syncWatchEvents) { processSyncWatchEvent(syncWatchEvent); } for (Map.Entry<String, List<SyncWatchEvent>> entry : _dependentSyncWatchEventsMaps.entrySet()) { SyncFile syncFile = SyncFileService.fetchSyncFile(entry.getKey()); if ((syncFile != null) && (syncFile.getTypePK() > 0)) { for (SyncWatchEvent syncWatchEvent : entry.getValue()) { processSyncWatchEvent(syncWatchEvent); } } } SyncEngineUtil.fireSyncEngineStateChanged( _syncAccountId, SyncEngineUtil.SYNC_ENGINE_STATE_PROCESSED); _processedSyncWatchEventIds.clear(); } protected boolean isInErrorState(Path filePath) { while (true) { if (filePath == null) { return false; } SyncFile syncFile = SyncFileService.fetchSyncFile(filePath.toString()); if (syncFile != null) { if (syncFile.isSystem()) { break; } if (syncFile.getState() == SyncFile.STATE_ERROR) { return true; } } filePath = filePath.getParent(); } return false; } protected boolean isPendingTypePK(SyncFile syncFile) { if (_pendingTypePKSyncFileIds.contains(syncFile.getSyncFileId())) { return true; } else if (syncFile.getTypePK() == 0) { _pendingTypePKSyncFileIds.add(syncFile.getSyncFileId()); return true; } return false; } protected void modifyFile(SyncWatchEvent syncWatchEvent) throws Exception { Path filePath = Paths.get(syncWatchEvent.getFilePathName()); SyncFile syncFile = SyncFileService.fetchSyncFile(filePath.toString()); if (syncFile == null) { return; } else if (isPendingTypePK(syncFile) || (syncFile.getState() == SyncFile.STATE_IN_PROGRESS)) { queueSyncWatchEvent(syncFile.getFilePathName(), syncWatchEvent); return; } else if (!FileUtil.isModified(syncFile)) { return; } SyncFileService.updateFileSyncFile(filePath, _syncAccountId, syncFile); } protected void moveFile(SyncWatchEvent syncWatchEvent) throws Exception { Path targetFilePath = Paths.get(syncWatchEvent.getFilePathName()); if (FileUtil.notExists(targetFilePath) || sanitizeFileName(targetFilePath) || isInErrorState(targetFilePath)) { return; } Path parentTargetFilePath = targetFilePath.getParent(); SyncFile parentSyncFile = SyncFileService.fetchSyncFile(parentTargetFilePath.toString()); if ((parentSyncFile == null) || (!parentSyncFile.isSystem() && (parentSyncFile.getTypePK() == 0))) { queueSyncWatchEvent(parentTargetFilePath.toString(), syncWatchEvent); return; } Path sourceFilePath = Paths.get(syncWatchEvent.getPreviousFilePathName()); SyncFile sourceSyncFile = SyncFileService.fetchSyncFile(sourceFilePath.toString()); SyncFile targetSyncFile = SyncFileService.fetchSyncFile(targetFilePath.toString()); if ((sourceSyncFile == null) || (targetSyncFile != null)) { if (Files.isDirectory(targetFilePath)) { addFolder(syncWatchEvent); } else { addFile(syncWatchEvent); } return; } else if (isPendingTypePK(sourceSyncFile)) { queueSyncWatchEvent(sourceSyncFile.getFilePathName(), syncWatchEvent); return; } String fileType = sourceSyncFile.getType(); if (fileType.equals(SyncFile.TYPE_FILE)) { SyncFileService.moveFileSyncFile( targetFilePath, parentSyncFile.getTypePK(), _syncAccountId, sourceSyncFile); } else { SyncFileService.moveFolderSyncFile( targetFilePath, parentSyncFile.getTypePK(), _syncAccountId, sourceSyncFile); } renameFile(syncWatchEvent); } protected synchronized void processSyncWatchEvent(SyncWatchEvent syncWatchEvent) throws Exception { SyncAccount syncAccount = SyncAccountService.fetchSyncAccount(_syncAccountId); if (syncAccount.getState() != SyncAccount.STATE_CONNECTED) { return; } if (_processedSyncWatchEventIds.contains(syncWatchEvent.getSyncWatchEventId())) { SyncWatchEventService.deleteSyncWatchEvent(syncWatchEvent.getSyncWatchEventId()); return; } String eventType = syncWatchEvent.getEventType(); if (eventType.equals(SyncWatchEvent.EVENT_TYPE_RENAME_FROM)) { eventType = SyncWatchEvent.EVENT_TYPE_DELETE; syncWatchEvent.setEventType(eventType); SyncWatchEventService.update(syncWatchEvent); } if (_logger.isDebugEnabled()) { _logger.debug("Processing Sync watch event {}", syncWatchEvent.toString()); } String fileType = syncWatchEvent.getFileType(); if (eventType.equals(SyncWatchEvent.EVENT_TYPE_CREATE)) { if (fileType.equals(SyncFile.TYPE_FILE)) { SyncWatchEvent duplicateSyncWatchEvent = null; if (OSDetector.isApple()) { duplicateSyncWatchEvent = SyncWatchEventService.fetchDuplicateSyncWatchEvent(syncWatchEvent); } if (duplicateSyncWatchEvent != null) { if (_logger.isDebugEnabled()) { _logger.debug("Skipping outdated Sync watch event"); } } else { addFile(syncWatchEvent); } } else { addFolder(syncWatchEvent); } } else if (eventType.equals(SyncWatchEvent.EVENT_TYPE_DELETE)) { deleteFile(syncWatchEvent); } else if (eventType.equals(SyncWatchEvent.EVENT_TYPE_MODIFY)) { SyncWatchEvent duplicateSyncWatchEvent = SyncWatchEventService.fetchDuplicateSyncWatchEvent(syncWatchEvent); if (duplicateSyncWatchEvent != null) { if (_logger.isDebugEnabled()) { _logger.debug("Skipping outdated Sync watch event"); } } else { modifyFile(syncWatchEvent); } } else if (eventType.equals(SyncWatchEvent.EVENT_TYPE_MOVE)) { moveFile(syncWatchEvent); } else if (eventType.equals(SyncWatchEvent.EVENT_TYPE_RENAME)) { renameFile(syncWatchEvent); } syncAccount = SyncAccountService.fetchSyncAccount(_syncAccountId); if (syncAccount.getState() == SyncAccount.STATE_CONNECTED) { SyncWatchEventService.deleteSyncWatchEvent(syncWatchEvent.getSyncWatchEventId()); } } protected void queueSyncWatchEvent(String parentFilePathName, SyncWatchEvent syncWatchEvent) { List<SyncWatchEvent> syncWatchEvents = _dependentSyncWatchEventsMaps.get(parentFilePathName); if (syncWatchEvents == null) { syncWatchEvents = new ArrayList<>(); _dependentSyncWatchEventsMaps.put(parentFilePathName, syncWatchEvents); } else { String eventType = syncWatchEvent.getEventType(); String filePathName = syncWatchEvent.getFilePathName(); SyncWatchEvent lastSyncWatchEvent = syncWatchEvents.get(syncWatchEvents.size() - 1); if (filePathName.equals(lastSyncWatchEvent.getFilePathName()) && eventType.equals(lastSyncWatchEvent.getEventType())) { return; } } if (_logger.isDebugEnabled()) { _logger.debug( "Queueing event {} {}", syncWatchEvent.getEventType(), syncWatchEvent.getFilePathName()); } if (!syncWatchEvents.contains(syncWatchEvent)) { syncWatchEvents.add(syncWatchEvent); } } protected void renameFile(SyncWatchEvent syncWatchEvent) throws Exception { Path sourceFilePath = Paths.get(syncWatchEvent.getPreviousFilePathName()); SyncFile syncFile = SyncFileService.fetchSyncFile(sourceFilePath.toString()); Path targetFilePath = Paths.get(syncWatchEvent.getFilePathName()); if (sanitizeFileName(targetFilePath)) { return; } if (syncFile == null) { if (Files.isDirectory(targetFilePath)) { addFolder(syncWatchEvent); } else { addFile(syncWatchEvent); } return; } else if (isPendingTypePK(syncFile)) { queueSyncWatchEvent(syncFile.getFilePathName(), syncWatchEvent); return; } String fileType = syncFile.getType(); if (fileType.equals(SyncFile.TYPE_FILE)) { SyncFileService.renameFileSyncFile(targetFilePath, _syncAccountId, syncFile); } else { SyncFileService.renameFolderSyncFile(targetFilePath, _syncAccountId, syncFile); } } protected boolean sanitizeFileName(Path filePath) { if (OSDetector.isWindows()) { return false; } String fileName = String.valueOf(filePath.getFileName()); String sanitizedFileName = FileUtil.getSanitizedFileName(fileName, FilenameUtils.getExtension(fileName)); if (!sanitizedFileName.equals(fileName)) { String sanitizedFilePathName = FileUtil.getFilePathName(String.valueOf(filePath.getParent()), sanitizedFileName); sanitizedFilePathName = FileUtil.getNextFilePathName(sanitizedFilePathName); FileUtil.checkFilePath(filePath); FileUtil.moveFile(filePath, Paths.get(sanitizedFilePathName)); return true; } return false; } protected boolean verifySite(SyncFile syncFile, SyncFile parentSyncFile) { if ((syncFile != null) && ((syncFile.getRepositoryId() != parentSyncFile.getRepositoryId()) || (syncFile.getSyncAccountId() != parentSyncFile.getSyncAccountId()))) { return false; } return true; } private static final Logger _logger = LoggerFactory.getLogger(SyncWatchEventProcessor.class); private static final ExecutorService _executorService = SyncEngine.getExecutorService(); private final Map<String, List<SyncWatchEvent>> _dependentSyncWatchEventsMaps = new ConcurrentHashMap<>(); private final Set<Long> _pendingTypePKSyncFileIds = new HashSet<>(); private final Set<Long> _processedSyncWatchEventIds = new HashSet<>(); private final long _syncAccountId; }