private void synchronize(ChangeRecord record) throws IOException { try { switch (record.getOperation()) { case LOCAL_INSERT: { // Get remote id for the parent folder File local = DriveUtils.absolutePath(record.getLocalFile()); String remoteParent = stub.storage().localToRemote().get(DriveUtils.relativePath(local.getParentFile())); if (!StringUtils.isEmpty(remoteParent) && !stub.storage().localToRemote().containsKey(record.getLocalFile())) { // Ignore insert request that doesn't have a parent or // already have a mapping. // The insert operation will be accomplished by the topmost // folder String remoteId = stub.transmit().upload(remoteParent, local); record.setRemoteFileId(remoteId); } break; } case LOCAL_DELETE: { if (!StringUtils.isEmpty(record.getRemoteFileId())) { stub.transmit().delete(record.getRemoteFileId()); } else { logger.warn( "Local deletion has no remote reference, make sure the storage is correct."); } break; } case LOCAL_CHANGE: { if (!StringUtils.isEmpty(record.getRemoteFileId())) { File local = DriveUtils.absolutePath(record.getLocalFile()); stub.transmit().update(record.getRemoteFileId(), local); } else { logger.warn( "Local change has no remote reference, make sure the storage is correct."); logger.warn("Trying to insert the new record"); // Modify it to a local insert record.setOperation(Operation.LOCAL_INSERT); synchronize(record); } break; } case LOCAL_RENAME: { if (!StringUtils.isEmpty(record.getRemoteFileId())) { stub.transmit().rename(record.getRemoteFileId(), (String) record.getContext()[0]); } else { logger.warn( "Local rename has no remote reference, make sure the storage is correct."); logger.warn("Trying to insert the new record"); // Modify it to be a local insert record.setOperation(Operation.LOCAL_INSERT); synchronize(record); } break; } case REMOTE_INSERT: { if (stub.storage().remoteToLocal().containsKey(record.getRemoteFileId())) { // This file/folder already had been created break; } com.google.api.services.drive.model.File file = record.getContext(0); // Depth search of parent that has a local root List<ParentReference> path = new ArrayList<ParentReference>(); File local = pathToLocal(record.getRemoteFileId(), path); if (null == local) { // Check whether this file is trashed if (file.getLabels().getTrashed()) { return; } if (file.getShared()) { return; } else { throw new IllegalArgumentException("Non-trash file has no known parent"); } } File parent = local; for (ParentReference node : path) { stub.transmit().download(node.getId(), parent); parent = DriveUtils.absolutePath(stub.storage().remoteToLocal().get(node.getId())); } stub.transmit().download(record.getRemoteFileId(), parent); record.setLocalFile(stub.storage().remoteToLocal().get(record.getRemoteFileId())); if (StringUtils.isEmpty(record.getLocalFile())) { break; } break; } case REMOTE_DELETE: { if (StringUtils.isEmpty(record.getLocalFile())) { // No local file, remote file should be a trashed one. if (logger.isDebugEnabled()) { logger.debug( "No corresponding local file for deletion. Remote file may be trashed"); } break; } File localFile = DriveUtils.absolutePath(record.getLocalFile()); String localParent = DriveUtils.relativePath(localFile.getParentFile()); // Preserve the original context record.setContext(new Object[] {record.getContext(0), localParent}); deleteLocalFile(localFile); if (localFile.exists()) { if (logger.isDebugEnabled()) { logger.debug( MessageFormat.format( "Failed to delete file {0}. File may have been deleted.", record.getLocalFile())); } } stub.storage().localToRemote().remove(record.getLocalFile()); stub.storage().remoteToLocal().remove(record.getRemoteFileId()); break; } case REMOTE_CHANGE: { File local = DriveUtils.absolutePath(record.getLocalFile()); File localParent = local.getParentFile(); com.google.api.services.drive.model.File remote = record.getContext(0); if (!remote.getTitle().equals(local.getName())) { local.delete(); stub.storage().localToRemote().remove(record.getLocalFile()); stub.storage().remoteToLocal().remove(record.getRemoteFileId()); } stub.transmit().download(record.getRemoteFileId(), localParent); break; } case REMOTE_RENAME: { File local = DriveUtils.absolutePath(record.getLocalFile()); com.google.api.services.drive.model.File remote = record.getContext(0); String remoteName = remote.getTitle(); File newName = new File(local.getParentFile().getAbsolutePath() + File.separator + remoteName); String relNewName = DriveUtils.relativePath(newName); record.setContext(new Object[] {record.getContext()[0], relNewName}); local.renameTo(newName); stub.storage() .remoteToLocal() .put(record.getRemoteFileId(), DriveUtils.relativePath(newName)); stub.storage().localToRemote().remove(DriveUtils.relativePath(local)); stub.storage() .localToRemote() .put(DriveUtils.relativePath(newName), record.getRemoteFileId()); break; } } } catch (Exception e) { logger.warn(MessageFormat.format("Exception on Change {0}. Retry later", record), e); FailedRecord fr = new FailedRecord(record); if (e instanceof GoogleJsonResponseException) { GoogleJsonResponseException gjre = (GoogleJsonResponseException) e; fr.setError(String.valueOf(gjre.getDetails().getCode())); } else { fr.setError(e.getMessage()); } stub.storage().failedLog().add(fr); } }
private void syncNotes(final String syncAccountName, final String accessToken) { final Drive drive = getDriveService(syncAccountName, accessToken); ContentResolver cr = getContentResolver(); try { // loop over saved files and add any new notes to drive Cursor savedNotes = cr.query(NotesProvider.CONTENT_URI, NotesSyncQuery.PROJECTION, null, null, null); if (savedNotes.moveToFirst()) { do { final String driveId = savedNotes.getString(NotesSyncQuery.DRIVE_ID); if (TextUtils.isEmpty(driveId)) { // exists locally but not in drive Ð upload it File newNote = new File(); newNote.setTitle(savedNotes.getString(NotesSyncQuery.TITLE)); newNote.setMimeType(NOTE_MIME_TYPE); File inserted = drive .files() .insert( newNote, ByteArrayContent.fromString( NOTE_MIME_TYPE, savedNotes.getString(NotesSyncQuery.BODY))) .execute(); // save the drive id to the db ContentValues cv = new ContentValues(); cv.put(NotesProvider.KEY_DRIVE_ID, inserted.getId()); Uri noteUri = ContentUris.withAppendedId( NotesProvider.CONTENT_URI, savedNotes.getLong(NotesSyncQuery.ID)); cr.update(noteUri, cv, null, null); } else { // TODO compare timestamps etc. } } while (savedNotes.moveToNext()); } // loop over all files in drive and see if any need to be // synced locally FileList driveFilesList = drive.files().list().execute(); for (File remote : driveFilesList.getItems()) { if (remote.getLabels().getTrashed()) { // skip deleted files continue; } final String where = NotesProvider.KEY_DRIVE_ID + "=?"; final String[] arguments = new String[] {remote.getId()}; Cursor c = cr.query( NotesProvider.CONTENT_URI, NotesDownloadQuery.PROJECTION, where, arguments, null); if (c.getCount() == 0) { // exists in drive but not locally Ð download it final String title = remote.getTitle(); final String body = getFileContents(drive, remote.getDownloadUrl()); final ContentValues cv = new ContentValues(); cv.put(NotesProvider.KEY_TITLE, title); cv.put(NotesProvider.KEY_BODY, body); cv.put(NotesProvider.KEY_DRIVE_ID, remote.getId()); cv.put(NotesProvider.KEY_LAST_MODIFIED, remote.getModifiedDate().getValue()); cr.insert(NotesProvider.CONTENT_URI, cv); } else { // TODO compare timestamps etc. } } } catch (IOException e) { // FIXME error handling Log.e(getClass().getSimpleName(), "Drive esplode", e); } }