public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId, 
            ContentChangeType localContent,
            ContentChangeType remoteContent)
        {
            var obj = this.Storage.GetObjectByRemoteId(remoteId.Id);
            string oldName = (remoteId as ICmisObject).Name;

            // Rename object
            try {
                (remoteId as ICmisObject).Rename(localFileSystemInfo.Name, true);
            } catch (CmisConstraintException e) {
                if (!Utils.IsValidISO885915(localFileSystemInfo.Name)) {
                    OperationsLogger.Warn(string.Format("Server denied to rename {0} to {1}, perhaps because it contains UTF-8 characters", oldName, localFileSystemInfo.Name));
                    throw new InteractionNeededException(string.Format("Server denied renaming of {0}", oldName), e) {
                        Title = string.Format("Server denied renaming of {0}", oldName),
                        Description = string.Format("Server denied to rename {0} to {1}, perhaps because it contains UTF-8 characters", oldName, localFileSystemInfo.Name)
                    };
                }

                throw;
            } catch (CmisPermissionDeniedException) {
                OperationsLogger.Warn(string.Format("Unable to renamed remote object from {0} to {1}: Permission Denied", oldName, localFileSystemInfo.Name));
                return;
            }

            obj.Name = localFileSystemInfo.Name;
            obj.Ignored = (remoteId as ICmisObject).AreAllChildrenIgnored();
            this.Storage.SaveMappedObject(obj);
            this.changeChangeSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
        }
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent,
            ContentChangeType remoteContent)
        {
            var savedObject = this.Storage.GetObjectByRemoteId(remoteId.Id);
            string newPath = remoteId is IFolder ? this.Storage.Matcher.CreateLocalPath(remoteId as IFolder) : this.Storage.Matcher.CreateLocalPath(remoteId as IDocument);
            if (remoteId is IFolder) {
                IDirectoryInfo dirInfo = localFileSystemInfo as IDirectoryInfo;
                string oldPath = dirInfo.FullName;
                if (!dirInfo.FullName.Equals(newPath)) {
                    dirInfo.MoveTo(newPath);
                    OperationsLogger.Info(string.Format("Moved local folder {0} to {1}", oldPath, newPath));
                } else {
                    return;
                }
            } else if (remoteId is IDocument) {
                IFileInfo fileInfo = localFileSystemInfo as IFileInfo;
                string oldPath = fileInfo.FullName;
                fileInfo.MoveTo(newPath);
                OperationsLogger.Info(string.Format("Moved local file {0} to {1}", oldPath, newPath));
            }

            savedObject.Name = (remoteId as ICmisObject).Name;
            savedObject.Ignored = (remoteId as ICmisObject).AreAllChildrenIgnored();
            savedObject.ParentId = remoteId is IFolder ? (remoteId as IFolder).ParentId : (remoteId as IDocument).Parents[0].Id;
            this.Storage.SaveMappedObject(savedObject);

            this.changeChangeSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
        }
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent,
            ContentChangeType remoteContent)
        {
            var obj = this.Storage.GetObjectByRemoteId(remoteId.Id);
            var localParent = localFileSystemInfo is IFileInfo ? (localFileSystemInfo as IFileInfo).Directory : (localFileSystemInfo as IDirectoryInfo).Parent;
            var mappedLocalParent = this.Storage.GetObjectByGuid((Guid)localParent.Uuid);
            var remoteObject = remoteId as IFileableCmisObject;
            var targetId = mappedLocalParent.RemoteObjectId;
            var src = this.Session.GetObject(obj.ParentId);
            var target = this.Session.GetObject(targetId);
            try {
                OperationsLogger.Info(string.Format("Moving remote object {2} from folder {0} to folder {1}", src.Name, target.Name, remoteId.Id));
                remoteObject = remoteObject.Move(src, target);
            } catch (CmisPermissionDeniedException) {
                OperationsLogger.Info(string.Format("Moving remote object failed {0}: Permission Denied", localFileSystemInfo.FullName));
                return;
            }

            obj.ParentId = targetId;
            obj.Ignored = remoteObject.AreAllChildrenIgnored();
            this.Storage.SaveMappedObject(obj);

            if (obj.Name != localFileSystemInfo.Name) {
                this.renameChangeSolver.Solve(localFileSystemInfo, remoteObject, localContent, remoteContent);
            } else {
                this.changeChangeSolver.Solve(localFileSystemInfo, remoteObject, localContent, remoteContent);
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="ContentValueChangedActionItem"/> class.
 /// </summary>
 /// <param name="name">The name of this action item.</param>
 /// <param name="content">The <see cref="IContent"/> instance that has changed.</param>
 /// <param name="changeType">The type of change that occurred.</param>
 /// <param name="index">The index of the change if the change occurred on an item of a collection. <c>null</c> otherwise.</param>
 /// <param name="previousValue">The previous value of the content (or the item if the change occurred on an item of a collection).</param>
 /// <param name="dirtiables">The dirtiable objects associated to this action item.</param>
 public ContentValueChangedActionItem(string name, IContent content, ContentChangeType changeType, object index, object previousValue, IEnumerable<IDirtiable> dirtiables)
     : base(name, dirtiables)
 {
     Content = content;
     ChangeType = changeType;
     PreviousValue = previousValue;
     Index = index;
 }
        public void AssertGotSingleFileEvent(MetaDataChangeType metaType, ContentChangeType contentType) {
            Assert.That(this.List.Count, Is.EqualTo(1));
            Assert.That(this.List[0], Is.TypeOf(typeof(FileEvent)));
            var fileEvent = this.List[0] as FileEvent;

            Assert.That(fileEvent.Remote, Is.EqualTo(metaType), "MetaDataChangeType incorrect");
            Assert.That(fileEvent.RemoteContent, Is.EqualTo(contentType), "ContentChangeType incorrect");
        }
 /// <summary>
 /// Does nothing
 /// </summary>
 /// <param name='localFile'>
 /// Local file.
 /// </param>
 /// <param name='remoteId'>
 /// Remote identifier.
 /// </param>
 /// <param name="localContent">Hint if the local content has been changed.</param>
 /// <param name="remoteContent">Information if the remote content has been changed.</param>
 public virtual void Solve(
     IFileSystemInfo localFile,
     IObjectId remoteId,
     ContentChangeType localContent,
     ContentChangeType remoteContent)
 {
     // No Operation Needed
 }
 /// <summary>
 /// Initializes a new instance of the <see cref="ContentChangeEventArgs"/> class.
 /// </summary>
 /// <param name="content">The content that has changed.</param>
 /// <param name="index">The index in the content where the change occurred, if applicable. <c>null</c> otherwise.</param>
 /// <param name="changeType">The type of change that occurred.</param>
 /// <param name="oldValue">The old value of the content.</param>
 /// <param name="newValue">The new value of the content.</param>
 public ContentChangeEventArgs(IContent content, object index, ContentChangeType changeType, object oldValue, object newValue)
 {
     Content = content;
     Index = index;
     ChangeType = changeType;
     OldValue = oldValue;
     NewValue = newValue;
 }
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            if (localFileSystemInfo is IFileInfo && remoteId is IDocument) {
                var localFile = localFileSystemInfo as IFileInfo;
                var remoteDocument = remoteId as IDocument;

                var mappedObject = this.Storage.GetObject(localFile);
                if (mappedObject == null) {
                    throw new ArgumentException(string.Format("Could not find db entry for {0} => invoke crawl sync", localFileSystemInfo.FullName));
                }

                if (mappedObject.LastChangeToken != (remoteId as ICmisObjectProperties).ChangeToken) {
                    throw new ArgumentException(string.Format("remote {1} {0} has also been changed since last sync => invoke crawl sync", remoteId.Id, remoteId is IDocument ? "document" : "folder"));
                }

                if (localFile != null && localFile.IsContentChangedTo(mappedObject, scanOnlyIfModificationDateDiffers: true)) {
                    Logger.Debug(string.Format("\"{0}\" is different from {1}", localFile.FullName, mappedObject.ToString()));
                    OperationsLogger.Debug(string.Format("Local file \"{0}\" has been changed", localFile.FullName));
                    try {
                        var transmission = this.transmissionManager.CreateTransmission(TransmissionType.UPLOAD_MODIFIED_FILE, localFile.FullName);
                        mappedObject.LastChecksum = this.UploadFileWithPWC(localFile, ref remoteDocument, transmission);
                        mappedObject.ChecksumAlgorithmName = "SHA-1";
                        if (remoteDocument.Id != mappedObject.RemoteObjectId) {
                            this.TransmissionStorage.RemoveObjectByRemoteObjectId(mappedObject.RemoteObjectId);
                            mappedObject.RemoteObjectId = remoteDocument.Id;
                        }
                    } catch (Exception ex) {
                        if (ex.InnerException is CmisPermissionDeniedException) {
                            OperationsLogger.Warn(string.Format("Local changed file \"{0}\" has not been uploaded: PermissionDenied", localFile.FullName));
                            return;
                        } else if (ex.InnerException is CmisStorageException) {
                            OperationsLogger.Warn(string.Format("Local changed file \"{0}\" has not been uploaded: StorageException", localFile.FullName), ex);
                            return;
                        }

                        throw;
                    }

                    mappedObject.LastRemoteWriteTimeUtc = remoteDocument.LastModificationDate;
                    mappedObject.LastLocalWriteTimeUtc = localFile.LastWriteTimeUtc;
                    mappedObject.LastContentSize = localFile.Length;

                    OperationsLogger.Info(string.Format("Local changed file \"{0}\" has been uploaded", localFile.FullName));
                }

                mappedObject.LastChangeToken = remoteDocument.ChangeToken;
                mappedObject.LastLocalWriteTimeUtc = localFile.LastWriteTimeUtc;
                this.Storage.SaveMappedObject(mappedObject);
            } else {
                this.folderOrFileContentUnchangedSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
            }

            return;
        }
 /// <summary>
 /// Solve the specified situation by using localFile and remote object.
 /// </summary>
 /// <param name="localFile">Local file.</param>
 /// <param name="remoteId">Remote identifier or object.</param>
 /// <param name="localContent">Hint if the local content has been changed.</param>
 /// <param name="remoteContent">Information if the remote content has been changed.</param>
 public override void Solve(
     IFileSystemInfo localFile,
     IObjectId remoteId,
     ContentChangeType localContent = ContentChangeType.NONE,
     ContentChangeType remoteContent = ContentChangeType.NONE)
 {
     var mappedObject = this.Storage.GetObjectByLocalPath(localFile);
     this.Storage.RemoveObject(mappedObject);
 }
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent,
            ContentChangeType remoteContent)
        {
            var savedObject = this.Storage.GetObjectByRemoteId(remoteId.Id);
            Guid? newParentUuid = localFileSystemInfo is IFileInfo ? (localFileSystemInfo as IFileInfo).Directory.Uuid : (localFileSystemInfo as IDirectoryInfo).Parent.Uuid;
            string newParentId = this.Storage.GetObjectByGuid((Guid)newParentUuid).RemoteObjectId;
            savedObject.Ignored = (remoteId as ICmisObject).AreAllChildrenIgnored();
            if (localFileSystemInfo.Name == (remoteId as ICmisObject).Name) {
                // Both names are equal => only move to new remote parent
                try {
                    (remoteId as IFileableCmisObject).Move(this.Session.GetObject(savedObject.ParentId), this.Session.GetObject(newParentId));
                } catch (CmisPermissionDeniedException) {
                    OperationsLogger.Info(string.Format("Permission Denied: Cannot move remote object {0} from {1} to {2}", remoteId.Id, savedObject.ParentId, newParentId));
                    return;
                }

                savedObject.Name = localFileSystemInfo.Name;
                savedObject.ParentId = newParentId;
                this.Storage.SaveMappedObject(savedObject);
                this.changeChangeSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
            } else {
                // Names are different to each other
                if (localFileSystemInfo.Name == savedObject.Name) {
                    // Remote rename and local move => Move remote and rename locally => change change solver
                    try {
                        remoteId = (remoteId as IFileableCmisObject).Move(this.Session.GetObject(savedObject.ParentId), this.Session.GetObject(newParentId));
                    } catch (CmisPermissionDeniedException) {
                        OperationsLogger.Info(string.Format("Permission Denied: Cannot move remote object {0} from {1} to {2}", remoteId.Id, savedObject.ParentId, newParentId));
                        return;
                    }

                    var localParentPath = localFileSystemInfo is IFileInfo ? (localFileSystemInfo as IFileInfo).Directory.FullName : (localFileSystemInfo as IDirectoryInfo).Parent.FullName;
                    string newPath = Path.Combine(localParentPath, (remoteId as ICmisObject).Name);
                    this.MoveTo(localFileSystemInfo, localFileSystemInfo.FullName, newPath);
                    savedObject.Name = localFileSystemInfo.Name;
                    savedObject.ParentId = newParentId;
                    this.Storage.SaveMappedObject(savedObject);
                    this.changeChangeSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
                } else {
                    // Both sides have been renamed => Move remote => rename rename solver
                    try {
                        (remoteId as IFileableCmisObject).Move(this.Session.GetObject(savedObject.ParentId), this.Session.GetObject(newParentId));
                    } catch (CmisPermissionDeniedException) {
                        OperationsLogger.Info(string.Format("Permission Denied: Cannot move remote object {0} from {1} to {2}", remoteId.Id, savedObject.ParentId, newParentId));
                        return;
                    }

                    savedObject.ParentId = newParentId;
                    this.Storage.SaveMappedObject(savedObject);
                    this.renameRenameSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
                }
            }
        }
        /// <summary>
        /// Renames the specified localFile to the name of the given remoteId object by using the storage, localFile and remoteId.
        /// </summary>
        /// <param name="localFile">Local file or folder. It is the source file/folder reference, which should be renamed.</param>
        /// <param name="remoteId">Remote identifier. Should be an instance of IFolder or IDocument.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFile,
            IObjectId remoteId,
            ContentChangeType localContent = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            IMappedObject obj = this.Storage.GetObjectByRemoteId(remoteId.Id);
            if (remoteId is IFolder) {
                // Rename local folder
                IFolder remoteFolder = remoteId as IFolder;
                IDirectoryInfo dirInfo = localFile as IDirectoryInfo;
                string oldPath = dirInfo.FullName;
                try {
                    dirInfo.MoveTo(Path.Combine(dirInfo.Parent.FullName, remoteFolder.Name));
                    obj.Name = remoteFolder.Name;
                } catch (IOException) {
                    if (dirInfo.Name.Equals(remoteFolder.Name, StringComparison.OrdinalIgnoreCase)) {
                        obj.Name = dirInfo.Name;
                    } else {
                        throw;
                    }
                }

                if (remoteFolder.LastModificationDate != null) {
                    dirInfo.LastWriteTimeUtc = (DateTime)remoteFolder.LastModificationDate;
                }

                obj.LastChangeToken = remoteFolder.ChangeToken;
                obj.LastRemoteWriteTimeUtc = remoteFolder.LastModificationDate;
                obj.LastLocalWriteTimeUtc = dirInfo.LastWriteTimeUtc;
                obj.Ignored = remoteFolder.AreAllChildrenIgnored();
                this.Storage.SaveMappedObject(obj);
                OperationsLogger.Info(string.Format("Renamed local folder {0} to {1}", oldPath, remoteFolder.Name));
            } else if(remoteId is IDocument) {
                // Rename local file
                IDocument remoteDocument = remoteId as IDocument;
                IFileInfo fileInfo = localFile as IFileInfo;
                string oldPath = fileInfo.FullName;
                fileInfo.MoveTo(Path.Combine(fileInfo.Directory.FullName, remoteDocument.Name));
                if (remoteDocument.LastModificationDate != null) {
                    fileInfo.LastWriteTimeUtc = (DateTime)remoteDocument.LastModificationDate;
                }

                obj.Name = remoteDocument.Name;
                obj.LastChangeToken = remoteContent == ContentChangeType.NONE ? remoteDocument.ChangeToken : obj.LastChangeToken;
                obj.LastRemoteWriteTimeUtc = remoteContent == ContentChangeType.NONE ? remoteDocument.LastModificationDate : obj.LastRemoteWriteTimeUtc;
                obj.LastLocalWriteTimeUtc = fileInfo.LastWriteTimeUtc;
                this.Storage.SaveMappedObject(obj);
                OperationsLogger.Info(string.Format("Renamed local file {0} to {1}", oldPath, remoteDocument.Name));
                if (remoteContent != ContentChangeType.NONE) {
                    throw new ArgumentException("Remote documents content is also changed => force crawl sync.");
                }
            } else {
                throw new ArgumentException("Given remote Id is not an IFolder nor an IDocument instance");
            }
        }
 /// <summary>
 /// Solve the specified situation by using the storage and remote object id to remove existing db entries and forces a crawl sync by throwing an IOException.
 /// </summary>
 /// <param name="localFile">Deleted Local filesystem info instance.</param>
 /// <param name="remoteId">Remote identifier or object.</param>
 /// <param name="localContent">Hint if the local content has been changed. Is not used by this solver.</param>
 /// <param name="remoteContent">Information if the remote content has been changed. Is not used by this solver.</param>
 public override void Solve(
     IFileSystemInfo localFile,
     IObjectId remoteId,
     ContentChangeType localContent = ContentChangeType.NONE,
     ContentChangeType remoteContent = ContentChangeType.NONE)
 {
     var mappedObject = this.Storage.GetObjectByRemoteId(remoteId.Id);
     this.Storage.RemoveObject(mappedObject);
     throw new IOException(
         string.Format(
         "Local deleted {0} is renamed or moved remotely => invoking crawl sync to download them again",
         mappedObject.Type == MappedObjectType.File ? "file" : "directory"));
 }
 /// <summary>
 /// Solve the specified situation by using localFile and remote object.
 /// </summary>
 /// <param name="localFileSystemInfo">Local filesystem info instance.</param>
 /// <param name="remoteId">Remote identifier or object.</param>
 /// <param name="localContent">Hint if the local content has been changed.</param>
 /// <param name="remoteContent">Information if the remote content has been changed.</param>
 public override void Solve(
     IFileSystemInfo localFileSystemInfo,
     IObjectId remoteId,
     ContentChangeType localContent,
     ContentChangeType remoteContent)
 {
     if (localFileSystemInfo is IDirectoryInfo) {
         IDirectoryInfo localFolder = localFileSystemInfo as IDirectoryInfo;
         IDirectoryInfo localParent = localFolder.Parent;
         IFolder remoteFolder = remoteId as IFolder;
         string remoteParentId = remoteFolder.ParentId;
         IMappedObject mappedParent = this.Storage.GetObjectByRemoteId(remoteParentId);
         IMappedObject mappedObject = this.Storage.GetObjectByRemoteId(remoteFolder.Id);
         if (localParent.Uuid == mappedParent.Guid) {
             // Both folders are in the same parent folder
             this.SyncNamesAndDates(localFolder, remoteFolder, mappedObject);
         } else {
             OperationsLogger.Warn(
                 string.Format(
                 "Synchronization Conflict: The local directory {0} has been moved to {1} with id {2},{4}" +
                 "but the remote folder was moved to {3}{4}You can fix this situation by moving them into the same folder",
                 localFileSystemInfo.Name,
                 localFileSystemInfo.FullName,
                 remoteFolder.Path,
                 Environment.NewLine));
             return;
         }
     } else if (localFileSystemInfo is IFileInfo) {
         IFileInfo localFile = localFileSystemInfo as IFileInfo;
         IDirectoryInfo localParent = localFile.Directory;
         IDocument remoteFile = remoteId as IDocument;
         string remoteParentId = remoteFile.Parents[0].Id;
         IMappedObject mappedParent = this.Storage.GetObjectByRemoteId(remoteParentId);
         IMappedObject mappedObject = this.Storage.GetObjectByRemoteId(remoteFile.Id);
         if (localParent.Uuid == mappedParent.Guid) {
             // Both files are in the same parent folder
             this.SyncNamesAndDates(localFile, remoteFile, mappedObject);
             return;
         } else {
             OperationsLogger.Warn(
                 string.Format(
                 "Synchronization Conflict: The local file {0} has been moved to {1} with id {2},{4}" +
                 "but the remote file was moved to {3}{4}You can fix this situation by moving them into the same folder",
                 localFileSystemInfo.Name,
                 localFileSystemInfo.FullName,
                 remoteFile.Paths[0],
                 Environment.NewLine));
             return;
         }
     }
 }
 public override void Solve(
     IFileSystemInfo localFileSystemInfo,
     IObjectId remoteId,
     ContentChangeType localContent,
     ContentChangeType remoteContent)
 {
     // User Interaction needed or the content will be downloaded on next sync.
     // Possibilities:
     // - Download new remote content (default, because no user interaction is needed and it is simple to solve)
     // - Remove remote element
     // - Ignore until situation is cleared
     OperationsLogger.Warn(string.Format("The remote object {0} of the corresponding locally deleted element has been changed => Downloading the remote changes", remoteId.Id));
     this.Storage.RemoveObject(this.Storage.GetObjectByRemoteId(remoteId.Id));
     throw new ArgumentException("Remote object has been changed while the object was deleted locally => force crawl sync");
 }
        /// <summary>
        /// Solve the specified situation by using the session, storage, localFile and remoteId.
        /// If a folder is affected, simply update the local change time of the corresponding local folder.
        /// If it is a file and the changeToken is not equal to the saved, the new content is downloaded.
        /// </summary>
        /// <param name="localFile">Local file.</param>
        /// <param name="remoteId">Remote identifier.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFile,
            IObjectId remoteId,
            ContentChangeType localContent = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            IMappedObject obj = this.Storage.GetObjectByRemoteId(remoteId.Id);
            if (remoteId is IFolder) {
                var remoteFolder = remoteId as IFolder;
                DateTime? lastModified = remoteFolder.LastModificationDate;
                obj.LastChangeToken = remoteFolder.ChangeToken;
                if (lastModified != null) {
                    try {
                        localFile.LastWriteTimeUtc = (DateTime)lastModified;
                    } catch(IOException e) {
                        Logger.Debug("Couldn't set the server side modification date", e);
                    }

                    obj.Ignored = remoteFolder.AreAllChildrenIgnored();
                    obj.LastLocalWriteTimeUtc = localFile.LastWriteTimeUtc;
                }
            } else if (remoteId is IDocument) {
                var remoteDocument = remoteId as IDocument;
                DateTime? lastModified = remoteDocument.LastModificationDate;
                if ((lastModified != null && lastModified != obj.LastRemoteWriteTimeUtc) || obj.LastChangeToken != remoteDocument.ChangeToken) {
                    if (remoteContent != ContentChangeType.NONE) {
                        if (obj.LastLocalWriteTimeUtc != localFile.LastWriteTimeUtc) {
                            throw new ArgumentException("The local file has been changed since last write => aborting update");
                        }

                        obj.LastChecksum = DownloadChanges(localFile as IFileInfo, remoteDocument, obj, this.fsFactory, this.transmissonManager, Logger);
                    }

                    obj.LastRemoteWriteTimeUtc = remoteDocument.LastModificationDate;
                    if (remoteDocument.LastModificationDate != null) {
                        localFile.LastWriteTimeUtc = (DateTime)remoteDocument.LastModificationDate;
                    }

                    obj.LastLocalWriteTimeUtc = localFile.LastWriteTimeUtc;
                    obj.LastContentSize = remoteDocument.ContentStreamLength ?? 0;
                }

                obj.LastChangeToken = remoteDocument.ChangeToken;
                obj.LastRemoteWriteTimeUtc = lastModified;
            }

            this.Storage.SaveMappedObject(obj);
        }
 public override void Solve(
     IFileSystemInfo localFileSystemInfo,
     IObjectId remoteId,
     ContentChangeType localContent,
     ContentChangeType remoteContent)
 {
     // Rename local object and call change/change solver
     var savedObject = this.Storage.GetObjectByRemoteId(remoteId.Id);
     string oldPath = localFileSystemInfo.FullName;
     string parentPath = localFileSystemInfo is IFileInfo ? (localFileSystemInfo as IFileInfo).Directory.FullName : (localFileSystemInfo as IDirectoryInfo).Parent.FullName;
     string newPath = Path.Combine(parentPath, (remoteId as ICmisObject).Name);
     this.MoveTo(localFileSystemInfo, oldPath, newPath);
     savedObject.Name = (remoteId as ICmisObject).Name;
     savedObject.Ignored = (remoteId as ICmisObject).AreAllChildrenIgnored();
     this.Storage.SaveMappedObject(savedObject);
     this.changeChangeSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
 }
 public override void Solve(
     IFileSystemInfo localFileSystemInfo,
     IObjectId remoteId,
     ContentChangeType localContent,
     ContentChangeType remoteContent)
 {
     var mappedObject = this.Storage.GetObjectByGuid((Guid)localFileSystemInfo.Uuid);
     this.Storage.RemoveObject(mappedObject);
     if (localFileSystemInfo is IFileInfo) {
         this.secondSolver.Solve(localFileSystemInfo, null, ContentChangeType.CREATED, ContentChangeType.NONE);
     } else if (localFileSystemInfo is IDirectoryInfo) {
         this.secondSolver.Solve(localFileSystemInfo, null, ContentChangeType.NONE, ContentChangeType.NONE);
         var dir = localFileSystemInfo as IDirectoryInfo;
         if (dir.GetFiles().Length > 0 || dir.GetDirectories().Length > 0) {
             throw new IOException(string.Format("There are unsynced files in local folder {0} => starting crawl sync", dir.FullName));
         }
     }
 }
        /// <summary>
        /// Deletes the given localFileInfo on file system and removes the stored object from storage.
        /// </summary>
        /// <param name="localFileInfo">Local file info.</param>
        /// <param name="remoteId">Remote identifier.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFileInfo,
            IObjectId remoteId,
            ContentChangeType localContent = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            if (localFileInfo is IDirectoryInfo) {
                if (!this.DeleteLocalObjectIfHasBeenSyncedBefore(localFileInfo)) {
                    this.Storage.RemoveObject(this.Storage.GetObjectByLocalPath(localFileInfo));
                    throw new IOException(string.Format("Not all local objects under {0} have been synced yet", localFileInfo.FullName));
                } else {
                    this.Storage.RemoveObject(this.Storage.GetObjectByLocalPath(localFileInfo));
                }
            } else if (localFileInfo is IFileInfo) {
                var file = localFileInfo as IFileInfo;
                file.Refresh();
                var mappedFile = this.Storage.GetObjectByLocalPath(file);
                if (file.Exists) {
                    if (mappedFile != null && file.LastWriteTimeUtc.Equals(mappedFile.LastLocalWriteTimeUtc)) {
                        file.Delete();
                        OperationsLogger.Info(string.Format("Deleted local file {0} because the mapped remote object {0} has been deleted", file.FullName, mappedFile.RemoteObjectId));
                    } else {
                        file.Uuid = null;
                        if (mappedFile == null) {
                            return;
                        }

                        OperationsLogger.Info(string.Format("Deletion of local file {0} skipped because of not yet uploaded changes", file.FullName));
                    }
                } else {
                    if (mappedFile == null) {
                        return;
                    } else {
                        OperationsLogger.Info(string.Format("Deletion of local file {0} skipped because it has already been deleted", file.FullName));
                    }
                }

                this.Storage.RemoveObject(this.Storage.GetObjectByLocalPath(localFileInfo));
                file.Refresh();
                if (file.Exists) {
                    throw new IOException(string.Format("Deletion of local file {0} skipped because of not yet uploaded changes", localFileInfo.FullName));
                }
            }
        }
        /// <summary>
        /// Solves the situation by deleting the corresponding remote object.
        /// </summary>
        /// <param name="localFile">Local file.</param>
        /// <param name="remoteId">Remote identifier or object.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFile,
            IObjectId remoteId,
            ContentChangeType localContent = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            var mappedObject = this.Storage.GetObjectByRemoteId(remoteId.Id);
            if (mappedObject.LastChangeToken != (remoteId as ICmisObject).ChangeToken) {
                throw new ArgumentException("Remote object has been changed since last sync => force crawl sync");
            }

            bool hasBeenDeleted = this.TryDeleteObjectOnServer(remoteId, mappedObject.Type);
            if (hasBeenDeleted) {
                this.Storage.RemoveObject(mappedObject);
                OperationsLogger.Info(string.Format("Deleted the corresponding remote object {0} of locally deleted object {1}", remoteId.Id, mappedObject.Name));
            } else {
                OperationsLogger.Warn(string.Format("Permission denied while trying to Delete the locally deleted object {0} on the server.", mappedObject.Name));
            }
        }
        /// <summary>
        /// Solve the specified situation by using the session, storage, localFile and remoteId.
        /// Moves the local file/folder to the new location.
        /// </summary>
        /// <param name="localFile">Old local file/folder.</param>
        /// <param name="remoteId">Remote identifier.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFile,
            IObjectId remoteId,
            ContentChangeType localContent = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            // Move local object
            var savedObject = this.Storage.GetObjectByRemoteId(remoteId.Id);
            string newPath = remoteId is IFolder ? this.Storage.Matcher.CreateLocalPath(remoteId as IFolder) : this.Storage.Matcher.CreateLocalPath(remoteId as IDocument);
            if (remoteId is IFolder) {
                IDirectoryInfo dirInfo = localFile as IDirectoryInfo;
                string oldPath = dirInfo.FullName;
                if (!dirInfo.FullName.Equals(newPath)) {
                    dirInfo.MoveTo(newPath);
                    dirInfo.LastWriteTimeUtc = (remoteId as IFolder).LastModificationDate != null ? (DateTime)(remoteId as IFolder).LastModificationDate : dirInfo.LastWriteTimeUtc;
                    OperationsLogger.Info(string.Format("Moved local folder {0} to {1}", oldPath, newPath));
                } else {
                    return;
                }
            } else if (remoteId is IDocument) {
                IFileInfo fileInfo = localFile as IFileInfo;
                string oldPath = fileInfo.FullName;
                fileInfo.MoveTo(newPath);
                fileInfo.LastWriteTimeUtc = (remoteId as IDocument).LastModificationDate != null ? (DateTime)(remoteId as IDocument).LastModificationDate : fileInfo.LastWriteTimeUtc;
                OperationsLogger.Info(string.Format("Moved local file {0} to {1}", oldPath, newPath));
            }

            savedObject.Name = (remoteId as ICmisObject).Name;
            savedObject.ParentId = remoteId is IFolder ? (remoteId as IFolder).ParentId : (remoteId as IDocument).Parents[0].Id;
            savedObject.LastChangeToken = (remoteId is IDocument && remoteContent != ContentChangeType.NONE) ? savedObject.LastChangeToken : remoteId is ICmisObject ? (remoteId as ICmisObject).ChangeToken : null;
            savedObject.LastLocalWriteTimeUtc = localFile.LastWriteTimeUtc;
            savedObject.LastRemoteWriteTimeUtc = (remoteId is IDocument && remoteContent != ContentChangeType.NONE) ? savedObject.LastRemoteWriteTimeUtc : (remoteId as ICmisObject).LastModificationDate;
            savedObject.Ignored = (remoteId as ICmisObject).AreAllChildrenIgnored();
            this.Storage.SaveMappedObject(savedObject);
            if (remoteId is IDocument && remoteContent != ContentChangeType.NONE) {
                throw new ArgumentException("Remote content has also been changed => force crawl sync.");
            }
        }
 /// <inheritdoc/>
 protected override void UndoAction()
 {
     switch (ChangeType)
     {
         case ContentChangeType.ValueChange:
             var previousValue = Content.Retrieve(Index);
             Content.Update(PreviousValue, Index);
             PreviousValue = previousValue;
             break;
         case ContentChangeType.CollectionAdd:
             PreviousValue = Content.Retrieve(Index);
             Content.Remove(Index);
             ChangeType = ContentChangeType.CollectionRemove;
             break;
         case ContentChangeType.CollectionRemove:
             Content.Add(Index, PreviousValue);
             PreviousValue = null;
             ChangeType = ContentChangeType.CollectionAdd;
             break;
         default:
             throw new ArgumentOutOfRangeException();
     }
 }
Beispiel #22
0
        protected override void ApplyUndo(object oldValue, object newValue, ContentChangeType type, bool isUndo)
        {
            var memberNode = Node as IAssetMemberNode;
            var objectNode = Node as IAssetObjectNode;

            switch (type)
            {
            case ContentChangeType.ValueChange:
                if (memberNode == null)
                {
                    throw new InvalidOperationException($"Expecting an {nameof(IAssetMemberNode)} when the change type is {nameof(ContentChangeType.ValueChange)}");
                }
                memberNode.Update(oldValue);
                break;

            case ContentChangeType.CollectionUpdate:
                if (objectNode == null)
                {
                    throw new InvalidOperationException($"Expecting an {nameof(IAssetObjectNode)} when the change type is {nameof(ContentChangeType.CollectionUpdate)}");
                }
                objectNode.Update(oldValue, Index);
                break;

            case ContentChangeType.CollectionAdd:
                if (objectNode == null)
                {
                    throw new InvalidOperationException($"Expecting an {nameof(IAssetObjectNode)} when the change type is {nameof(ContentChangeType.CollectionAdd)}");
                }
                // Some Add might have an empty index. In this case we need to retrieve the index from the content to pass it to remove.
                // TODO: this way of fetching the index is not robust at all! what if there's the same item twice in the collection?
                var index = !Index.IsEmpty ? Index : objectNode.Indices.First(x => Equals(Node.Retrieve(x), newValue));
                // When undoing (an add), we don't want to track the item as deleted. But when redoing (a remove) we do!
                if (isUndo)
                {
                    objectNode.RemoveAndDiscard(newValue, index, itemId);
                }
                else
                {
                    objectNode.Remove(newValue, index);
                }

                break;

            case ContentChangeType.CollectionRemove:
                if (objectNode == null)
                {
                    throw new InvalidOperationException($"Expecting an {nameof(IAssetObjectNode)} when the change type is {nameof(ContentChangeType.CollectionRemove)}");
                }
                if (!Index.IsEmpty)
                {
                    objectNode.Restore(oldValue, Index, itemId);
                }
                else
                {
                    objectNode.Restore(oldValue, itemId);
                }
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
 private static void TestContentChange(GraphNodeChangeListener listener, IGraphNode contentOwner, ContentChangeType type, Index index, object oldValue, object newValue, Action change)
 {
     var i = 0;
     var prepareChange = new EventHandler<GraphContentChangeEventArgs>((sender, e) => { Assert.AreEqual(0, i); VerifyListenerEvent(e, contentOwner, type, index, oldValue, newValue, false); ++i; });
     var changing = new EventHandler<GraphContentChangeEventArgs>((sender, e) => { Assert.AreEqual(1, i); VerifyListenerEvent(e, contentOwner, type, index, oldValue, newValue, false); ++i; });
     var changed = new EventHandler<GraphContentChangeEventArgs>((sender, e) => { Assert.AreEqual(2, i); VerifyListenerEvent(e, contentOwner, type, index, oldValue, newValue, true); ++i; });
     var finalizeChange = new EventHandler<GraphContentChangeEventArgs>((sender, e) => { Assert.AreEqual(3, i); VerifyListenerEvent(e, contentOwner, type, index, oldValue, newValue, true); ++i; });
     listener.PrepareChange += prepareChange;
     listener.Changing += changing;
     listener.Changed += changed;
     listener.FinalizeChange += finalizeChange;
     change();
     Assert.AreEqual(4, i);
     listener.PrepareChange -= prepareChange;
     listener.Changing -= changing;
     listener.Changed -= changed;
     listener.FinalizeChange -= finalizeChange;
 }
Beispiel #24
0
        /// <summary>
        /// Solve the specified situation by using localFile and remote object.
        /// </summary>
        /// <param name="localFile">Local file.</param>
        /// <param name="remoteId">Remote identifier or object.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFile,
            IObjectId remoteId,
            ContentChangeType localContent  = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            var obj = this.Storage.GetObjectByRemoteId(remoteId.Id);

            // Rename remote object
            if (remoteId is ICmisObject)
            {
                if ((remoteId as ICmisObject).ChangeToken != obj.LastChangeToken)
                {
                    throw new ArgumentException("Last changetoken is invalid => force crawl sync");
                }

                string oldName = (remoteId as ICmisObject).Name;
                try {
                    (remoteId as ICmisObject).Rename(localFile.Name, true);
                } catch (CmisNameConstraintViolationException e) {
                    if (!Utils.IsValidISO885915(localFile.Name))
                    {
                        OperationsLogger.Warn(string.Format("The server denies the renaming of {2} from {0} to {1}, perhaps because the new name contains UTF-8 characters", oldName, localFile.Name, localFile.FullName));
                        throw new InteractionNeededException(string.Format("Server denied renaming of {0}", oldName), e)
                              {
                                  Title       = string.Format("Server denied renaming of {0}", oldName),
                                  Description = string.Format("The server denies the renaming of {2} from {0} to {1}, perhaps because the new name contains UTF-8 characters", oldName, localFile.Name, localFile.FullName)
                              };
                    }
                    else
                    {
                        try {
                            string wishedRemotePath        = this.Storage.Matcher.CreateRemotePath(localFile.FullName);
                            var    conflictingRemoteObject = this.Session.GetObjectByPath(wishedRemotePath) as IFileableCmisObject;
                            if (conflictingRemoteObject != null && conflictingRemoteObject.AreAllChildrenIgnored())
                            {
                                OperationsLogger.Warn(string.Format("The server denies the renaming of {2} from {0} to {1}, because there is an ignored file/folder with this name already, trying to create conflict file/folder name", oldName, localFile.Name, localFile.FullName), e);
                                string newName = localFile.Name;
                                if (localFile is IDirectoryInfo)
                                {
                                    (localFile as IDirectoryInfo).MoveTo(Path.Combine((localFile as IDirectoryInfo).Parent.FullName, newName + "_Conflict"));
                                }
                                else if (localFile is IFileInfo)
                                {
                                    (localFile as IFileInfo).MoveTo(Path.Combine((localFile as IFileInfo).Directory.FullName, newName + "_Conflict"));
                                }

                                return;
                            }
                        } catch (CmisObjectNotFoundException) {
                        }

                        OperationsLogger.Warn(string.Format("The server denies the renaming of {2} from {0} to {1}", oldName, localFile.Name, localFile.FullName), e);
                    }

                    throw;
                } catch (CmisPermissionDeniedException) {
                    OperationsLogger.Warn(string.Format("Unable to renamed remote object from {0} to {1}: Permission Denied", oldName, localFile.Name));
                    return;
                }

                OperationsLogger.Info(string.Format("Renamed remote object {0} from {1} to {2}", remoteId.Id, oldName, localFile.Name));
            }
            else
            {
                throw new ArgumentException("Given remoteId type is unknown: " + remoteId.GetType().Name);
            }

            bool isContentChanged = localFile is IFileInfo ? (localFile as IFileInfo).IsContentChangedTo(obj) : false;

            obj.Name = (remoteId as ICmisObject).Name;
            obj.LastRemoteWriteTimeUtc = (remoteId as ICmisObject).LastModificationDate;
            obj.LastLocalWriteTimeUtc  = isContentChanged ? obj.LastLocalWriteTimeUtc : localFile.LastWriteTimeUtc;
            obj.LastChangeToken        = (remoteId as ICmisObject).ChangeToken;
            obj.Ignored = (remoteId as ICmisObject).AreAllChildrenIgnored();
            this.Storage.SaveMappedObject(obj);
            if (isContentChanged)
            {
                throw new ArgumentException("Local file content is also changed => force crawl sync.");
            }
        }
        /// <summary>
        /// Solve the specified situation by using localFile and remote object if the local file content is the only changed content. Otherwise the given fallback will be used.
        /// </summary>
        /// <param name="localFileSystemInfo">Local filesystem info instance.</param>
        /// <param name="remoteId">Remote identifier or object.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent,
            ContentChangeType remoteContent)
        {
            if (!(localFileSystemInfo is IFileInfo))
            {
                this.fallbackSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
                return;
            }

            IFileInfo localFile      = localFileSystemInfo as IFileInfo;
            IDocument remoteDocument = remoteId as IDocument;

            if (remoteContent != ContentChangeType.NONE)
            {
                this.fallbackSolver.Solve(localFile, remoteId, localContent, remoteContent);
                return;
            }

            bool updateLocalDate  = false;
            bool updateRemoteDate = false;
            var  obj = this.Storage.GetObjectByRemoteId(remoteDocument.Id);

            if (localFile.IsContentChangedTo(obj, true))
            {
                updateRemoteDate = true;
                try {
                    var transmission = this.transmissionManager.CreateTransmission(TransmissionType.UPLOAD_MODIFIED_FILE, localFile.FullName);
                    obj.LastChecksum          = UploadFileWithPWC(localFile, ref remoteDocument, transmission);
                    obj.ChecksumAlgorithmName = "SHA-1";
                    obj.LastContentSize       = remoteDocument.ContentStreamLength ?? localFile.Length;
                    if (remoteDocument.Id != obj.RemoteObjectId)
                    {
                        this.TransmissionStorage.RemoveObjectByRemoteObjectId(obj.RemoteObjectId);
                        obj.RemoteObjectId = remoteDocument.Id;
                    }
                } catch (Exception ex) {
                    if (ex.InnerException is CmisPermissionDeniedException)
                    {
                        OperationsLogger.Warn(string.Format("Local changed file \"{0}\" has not been uploaded: PermissionDenied", localFile.FullName));
                        return;
                    }
                    else if (ex.InnerException is CmisStorageException)
                    {
                        OperationsLogger.Warn(string.Format("Local changed file \"{0}\" has not been uploaded: StorageException", localFile.FullName), ex);
                        return;
                    }

                    throw;
                }
            }
            else
            {
                //  just date sync
                if (remoteDocument.LastModificationDate != null && localFile.LastWriteTimeUtc < remoteDocument.LastModificationDate)
                {
                    updateLocalDate = true;
                }
                else
                {
                    updateRemoteDate = true;
                }
            }

            if (this.ServerCanModifyDateTimes)
            {
                if (updateLocalDate)
                {
                    localFile.LastWriteTimeUtc = (DateTime)remoteDocument.LastModificationDate;
                }
                else if (updateRemoteDate)
                {
                    remoteDocument.UpdateLastWriteTimeUtc(localFile.LastWriteTimeUtc);
                }
                else
                {
                    throw new ArgumentException();
                }
            }

            obj.LastChangeToken        = remoteDocument.ChangeToken;
            obj.LastLocalWriteTimeUtc  = localFileSystemInfo.LastWriteTimeUtc;
            obj.LastRemoteWriteTimeUtc = remoteDocument.LastModificationDate;
            this.Storage.SaveMappedObject(obj);
        }
Beispiel #26
0
        private static void TestItemChange([NotNull] GraphNodeChangeListener listener, [NotNull] Func <IObjectNode> fetchNode, ContentChangeType type, NodeIndex index, object oldValue, object newValue, [NotNull] Action <IObjectNode> change)
        {
            var i            = 0;
            var contentOwner = fetchNode();
            var changing     = new EventHandler <ItemChangeEventArgs>((sender, e) => { Assert.Equal(0, i); VerifyListenerEvent(e, contentOwner, type, index, oldValue, newValue, false); ++i; });
            var changed      = new EventHandler <ItemChangeEventArgs>((sender, e) => { Assert.Equal(1, i); VerifyListenerEvent(e, contentOwner, type, index, oldValue, newValue, true); ++i; });

            listener.ItemChanging += changing;
            listener.ItemChanged  += changed;
            change(contentOwner);
            Assert.Equal(2, i);
            listener.ItemChanging -= changing;
            listener.ItemChanged  -= changed;
        }
Beispiel #27
0
        /// <summary>
        /// Solve the specified situation by using localFile and remote object.
        /// </summary>
        /// <param name="localFileSystemInfo">Local filesystem info instance.</param>
        /// <param name="remoteId">Remote identifier or object.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent  = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            Stopwatch completewatch = new Stopwatch();

            completewatch.Start();
            Logger.Debug("Starting LocalObjectAdded");
            string parentId = this.GetParentId(localFileSystemInfo, this.Storage);
            Guid   uuid     = this.WriteOrUseUuidIfSupported(localFileSystemInfo);

            ICmisObject addedObject;

            try {
                addedObject = this.AddCmisObject(localFileSystemInfo, parentId, this.Session);
            } catch (CmisPermissionDeniedException e) {
                OperationsLogger.Warn(string.Format("Permission denied while trying to Create the locally added object {0} on the server ({1}).", localFileSystemInfo.FullName, e.Message));
                return;
            }

            OperationsLogger.Info(string.Format("Created remote {2} {0} for {1}", addedObject.Id, localFileSystemInfo.FullName, addedObject is IFolder ? "folder" : "document"));

            MappedObject mapped = new MappedObject(
                localFileSystemInfo.Name,
                addedObject.Id,
                localFileSystemInfo is IDirectoryInfo ? MappedObjectType.Folder : MappedObjectType.File,
                parentId,
                addedObject.ChangeToken)
            {
                Guid = uuid,
                LastRemoteWriteTimeUtc = addedObject.LastModificationDate,
                LastLocalWriteTimeUtc  = localFileSystemInfo is IFileInfo && (localFileSystemInfo as IFileInfo).Length > 0 ? (DateTime?)null : (DateTime?)localFileSystemInfo.LastWriteTimeUtc,
                LastChangeToken        = addedObject.ChangeToken,
                LastContentSize        = localFileSystemInfo is IDirectoryInfo ? -1 : 0,
                ChecksumAlgorithmName  = localFileSystemInfo is IDirectoryInfo ? null : "SHA-1",
                LastChecksum           = localFileSystemInfo is IDirectoryInfo ? null : SHA1.Create().ComputeHash(new byte[0])
            };

            this.Storage.SaveMappedObject(mapped);

            var localFile = localFileSystemInfo as IFileInfo;

            if (localFile != null)
            {
                FileTransmissionEvent transmissionEvent = new FileTransmissionEvent(FileTransmissionType.UPLOAD_NEW_FILE, localFile.FullName);
                this.transmissionManager.AddTransmission(transmissionEvent);
                if (localFile.Length > 0)
                {
                    Stopwatch watch = new Stopwatch();
                    OperationsLogger.Debug(string.Format("Uploading file content of {0}", localFile.FullName));
                    watch.Start();
                    IFileUploader uploader = ContentTaskUtils.CreateUploader();
                    using (SHA1 hashAlg = new SHA1Managed())
                        using (var fileStream = localFile.Open(FileMode.Open, FileAccess.Read)) {
                            try {
                                uploader.UploadFile(addedObject as IDocument, fileStream, transmissionEvent, hashAlg);
                            } catch (Exception ex) {
                                transmissionEvent.ReportProgress(new TransmissionProgressEventArgs {
                                    FailedException = ex
                                });
                                throw;
                            }

                            mapped.ChecksumAlgorithmName = "SHA-1";
                            mapped.LastChecksum          = hashAlg.Hash;
                        }

                    watch.Stop();

                    if (this.ServerCanModifyDateTimes)
                    {
                        (addedObject as IDocument).UpdateLastWriteTimeUtc(localFile.LastWriteTimeUtc);
                    }

                    mapped.LastContentSize        = localFile.Length;
                    mapped.LastChangeToken        = addedObject.ChangeToken;
                    mapped.LastRemoteWriteTimeUtc = addedObject.LastModificationDate;
                    mapped.LastLocalWriteTimeUtc  = localFileSystemInfo.LastWriteTimeUtc;
                    if (mapped.RemoteObjectId != addedObject.Id)
                    {
                        this.Storage.RemoveObject(mapped);
                        mapped.RemoteObjectId = addedObject.Id;
                    }

                    this.Storage.SaveMappedObject(mapped);
                    OperationsLogger.Info(string.Format("Uploaded file content of {0} in [{1} msec]", localFile.FullName, watch.ElapsedMilliseconds));
                }

                transmissionEvent.ReportProgress(new TransmissionProgressEventArgs {
                    Completed = true
                });
            }

            completewatch.Stop();
            Logger.Debug(string.Format("Finished LocalObjectAdded after [{0} msec]", completewatch.ElapsedMilliseconds));
        }
 private static void VerifyListenerEvent(MemberNodeChangeEventArgs e, IContentNode contentOwner, ContentChangeType type, Index index, object oldValue, object newValue, bool changeApplied)
 {
     Assert.NotNull(e);
     Assert.NotNull(contentOwner);
     Assert.AreEqual(type, e.ChangeType);
     Assert.AreEqual(contentOwner, e.Member);
     Assert.AreEqual(index, e.Index);
     Assert.AreEqual(newValue, e.NewValue);
     Assert.AreEqual(oldValue, e.OldValue);
     if (type == ContentChangeType.ValueChange)
     {
         Assert.AreEqual(changeApplied ? newValue : oldValue, contentOwner.Retrieve(index));
     }
 }
Beispiel #29
0
        /// <summary>
        /// Solve the specified situation by using the session, storage, localFile and remoteId.
        /// If a folder is affected, simply update the local change time of the corresponding local folder.
        /// If it is a file and the changeToken is not equal to the saved, the new content is downloaded.
        /// </summary>
        /// <param name="localFile">Local file.</param>
        /// <param name="remoteId">Remote identifier.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFile,
            IObjectId remoteId,
            ContentChangeType localContent  = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            IMappedObject obj = this.Storage.GetObjectByRemoteId(remoteId.Id);

            if (remoteId is IFolder)
            {
                var      remoteFolder = remoteId as IFolder;
                DateTime?lastModified = remoteFolder.LastModificationDate;
                obj.LastChangeToken = remoteFolder.ChangeToken;
                if (lastModified != null)
                {
                    try {
                        localFile.LastWriteTimeUtc = (DateTime)lastModified;
                    } catch (IOException e) {
                        Logger.Debug("Couldn't set the server side modification date", e);
                    }

                    obj.LastLocalWriteTimeUtc = localFile.LastWriteTimeUtc;
                }
            }
            else if (remoteId is IDocument)
            {
                byte[]   lastChecksum   = obj.LastChecksum;
                var      remoteDocument = remoteId as IDocument;
                DateTime?lastModified   = remoteDocument.LastModificationDate;
                if ((lastModified != null && lastModified != obj.LastRemoteWriteTimeUtc) || obj.LastChangeToken != remoteDocument.ChangeToken)
                {
                    if (remoteContent != ContentChangeType.NONE)
                    {
                        if (obj.LastLocalWriteTimeUtc != localFile.LastWriteTimeUtc)
                        {
                            throw new ArgumentException("The local file has been changed since last write => aborting update");
                        }

                        // Download changes
                        var file              = localFile as IFileInfo;
                        var cacheFile         = this.fsFactory.CreateDownloadCacheFileInfo(file);
                        var transmissionEvent = new FileTransmissionEvent(FileTransmissionType.DOWNLOAD_MODIFIED_FILE, localFile.FullName, cacheFile.FullName);
                        this.queue.AddEvent(transmissionEvent);
                        this.transmissonManager.AddTransmission(transmissionEvent);
                        using (SHA1 hashAlg = new SHA1Managed())
                            using (var filestream = cacheFile.Open(FileMode.Create, FileAccess.Write, FileShare.None))
                                using (IFileDownloader download = ContentTaskUtils.CreateDownloader()) {
                                    try {
                                        download.DownloadFile(remoteDocument, filestream, transmissionEvent, hashAlg);
                                    } catch (Exception ex) {
                                        transmissionEvent.ReportProgress(new TransmissionProgressEventArgs {
                                            FailedException = ex
                                        });
                                        throw;
                                    }

                                    obj.ChecksumAlgorithmName = "SHA-1";
                                    obj.LastChecksum          = hashAlg.Hash;
                                }

                        var  backupFile = this.fsFactory.CreateFileInfo(file.FullName + ".bak.sync");
                        Guid?uuid       = file.Uuid;
                        cacheFile.Replace(file, backupFile, true);
                        try {
                            file.Uuid = uuid;
                        } catch (RestoreModificationDateException e) {
                            Logger.Debug("Failed to restore modification date of original file", e);
                        }

                        try {
                            backupFile.Uuid = null;
                        } catch (RestoreModificationDateException e) {
                            Logger.Debug("Failed to restore modification date of backup file", e);
                        }

                        byte[] checksumOfOldFile = null;
                        using (var oldFileStream = backupFile.Open(FileMode.Open, FileAccess.Read, FileShare.None)) {
                            checksumOfOldFile = SHA1Managed.Create().ComputeHash(oldFileStream);
                        }

                        if (!lastChecksum.SequenceEqual(checksumOfOldFile))
                        {
                            var conflictFile = this.fsFactory.CreateConflictFileInfo(file);
                            backupFile.MoveTo(conflictFile.FullName);
                            OperationsLogger.Info(string.Format("Updated local content of \"{0}\" with content of remote document {1} and created conflict file {2}", file.FullName, remoteId.Id, conflictFile.FullName));
                        }
                        else
                        {
                            backupFile.Delete();
                            OperationsLogger.Info(string.Format("Updated local content of \"{0}\" with content of remote document {1}", file.FullName, remoteId.Id));
                        }

                        transmissionEvent.ReportProgress(new TransmissionProgressEventArgs {
                            Completed = true
                        });
                    }

                    obj.LastRemoteWriteTimeUtc = remoteDocument.LastModificationDate;
                    if (remoteDocument.LastModificationDate != null)
                    {
                        localFile.LastWriteTimeUtc = (DateTime)remoteDocument.LastModificationDate;
                    }

                    obj.LastLocalWriteTimeUtc = localFile.LastWriteTimeUtc;
                    obj.LastContentSize       = remoteDocument.ContentStreamLength ?? 0;
                }

                obj.LastChangeToken        = remoteDocument.ChangeToken;
                obj.LastRemoteWriteTimeUtc = lastModified;
            }

            this.Storage.SaveMappedObject(obj);
        }
Beispiel #30
0
        /// <summary>
        /// Solve the specified situation by taking renaming the local or remote object to the name of the last changed object.
        /// </summary>
        /// <param name="localFileSystemInfo">Local file system info.</param>
        /// <param name="remoteId">Remote object.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent  = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            if (localFileSystemInfo is IDirectoryInfo)
            {
                var localFolder  = localFileSystemInfo as IDirectoryInfo;
                var remoteFolder = remoteId as IFolder;
                var mappedObject = this.Storage.GetObjectByRemoteId(remoteFolder.Id);
                if (localFolder.Name.Equals(remoteFolder.Name))
                {
                    mappedObject.Name = localFolder.Name;
                }
                else if (localFolder.LastWriteTimeUtc.CompareTo((DateTime)remoteFolder.LastModificationDate) > 0)
                {
                    string oldName = remoteFolder.Name;
                    try {
                        remoteFolder.Rename(localFolder.Name, true);
                    } catch (CmisConstraintException e) {
                        if (!Utils.IsValidISO885915(localFolder.Name))
                        {
                            OperationsLogger.Warn(string.Format("Server denied to rename {0} to {1}, perhaps because it contains UTF-8 characters", oldName, localFolder.Name));
                            throw new InteractionNeededException(string.Format("Server denied renaming of {0}", oldName), e)
                                  {
                                      Title       = string.Format("Server denied renaming of {0}", oldName),
                                      Description = string.Format("Server denied to rename {0} to {1}, perhaps because it contains UTF-8 characters", oldName, localFolder.Name)
                                  };
                        }

                        throw;
                    }

                    mappedObject.Name = remoteFolder.Name;
                    OperationsLogger.Info(string.Format("Renamed remote folder {0} with id {2} to {1}", oldName, remoteFolder.Id, remoteFolder.Name));
                }
                else
                {
                    string oldName = localFolder.Name;
                    localFolder.MoveTo(Path.Combine(localFolder.Parent.FullName, remoteFolder.Name));
                    mappedObject.Name = remoteFolder.Name;
                    OperationsLogger.Info(string.Format("Renamed local folder {0} to {1}", Path.Combine(localFolder.Parent.FullName, oldName), remoteFolder.Name));
                }

                mappedObject.LastLocalWriteTimeUtc  = localFolder.LastWriteTimeUtc;
                mappedObject.LastRemoteWriteTimeUtc = (DateTime)remoteFolder.LastModificationDate;
                mappedObject.LastChangeToken        = remoteFolder.ChangeToken;
                mappedObject.Ignored = remoteFolder.AreAllChildrenIgnored();
                this.Storage.SaveMappedObject(mappedObject);
            }
            else if (localFileSystemInfo is IFileInfo)
            {
                var localFile    = localFileSystemInfo as IFileInfo;
                var remoteFile   = remoteId as IDocument;
                var mappedObject = this.Storage.GetObjectByRemoteId(remoteFile.Id);
                if (localFile.Name.Equals(remoteFile.Name))
                {
                    mappedObject.Name = localFile.Name;
                    this.Storage.SaveMappedObject(mappedObject);
                    this.changeChangeSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
                }
                else
                {
                    string desc = string.Format(
                        "The local file {0} has been locally renamed from {1} to {2} and remotely to {3}. " +
                        "Fix this conflict by renaming the remote file to {2} or the local file to {3}.",
                        localFile.FullName,
                        mappedObject.Name,
                        localFile.Name,
                        remoteFile.Name);
                    OperationsLogger.Warn("Synchronization Conflict: " + desc);
                    throw new InteractionNeededException("Synchronization Conflict")
                          {
                              Title       = "Synchronization Conflict",
                              Description = desc
                          };
                }
            }
        }
        private static void TestContentChange(GraphNodeChangeListener listener, IGraphNode contentOwner, ContentChangeType type, Index index, object oldValue, object newValue, GraphNodePath path, Action change)
        {
            var i              = 0;
            var prepareChange  = new EventHandler <GraphContentChangeEventArgs>((sender, e) => { Assert.AreEqual(0, i); VerifyListenerEvent(e, contentOwner, type, index, oldValue, newValue, path, false); ++i; });
            var changing       = new EventHandler <GraphContentChangeEventArgs>((sender, e) => { Assert.AreEqual(1, i); VerifyListenerEvent(e, contentOwner, type, index, oldValue, newValue, path, false); ++i; });
            var changed        = new EventHandler <GraphContentChangeEventArgs>((sender, e) => { Assert.AreEqual(2, i); VerifyListenerEvent(e, contentOwner, type, index, oldValue, newValue, path, true); ++i; });
            var finalizeChange = new EventHandler <GraphContentChangeEventArgs>((sender, e) => { Assert.AreEqual(3, i); VerifyListenerEvent(e, contentOwner, type, index, oldValue, newValue, path, true); ++i; });

            listener.PrepareChange  += prepareChange;
            listener.Changing       += changing;
            listener.Changed        += changed;
            listener.FinalizeChange += finalizeChange;
            change();
            Assert.AreEqual(4, i);
            listener.PrepareChange  -= prepareChange;
            listener.Changing       -= changing;
            listener.Changed        -= changed;
            listener.FinalizeChange -= finalizeChange;
        }
 private static void VerifyListenerEvent(GraphContentChangeEventArgs e, IGraphNode contentOwner, ContentChangeType type, Index index, object oldValue, object newValue, GraphNodePath path, bool changeApplied)
 {
     Assert.NotNull(e);
     Assert.NotNull(contentOwner);
     Assert.NotNull(path);
     Assert.AreEqual(type, e.ChangeType);
     Assert.AreEqual(contentOwner.Content, e.Content);
     Assert.AreEqual(index, e.Index);
     Assert.AreEqual(newValue, e.NewValue);
     Assert.AreEqual(oldValue, e.OldValue);
     Assert.AreEqual(path, e.Path);
     if (type == ContentChangeType.ValueChange)
     {
         Assert.AreEqual(changeApplied ? newValue : oldValue, contentOwner.Content.Retrieve(index));
     }
 }
 /// <summary>
 /// Solve the specified situation by using localFile and remote object.
 /// </summary>
 /// <param name="localFileSystemInfo">Local filesystem info instance.</param>
 /// <param name="remoteId">Remote identifier or object.</param>
 /// <param name="localContent">Hint if the local content has been changed.</param>
 /// <param name="remoteContent">Information if the remote content has been changed.</param>
 public override void Solve(
     IFileSystemInfo localFileSystemInfo,
     IObjectId remoteId,
     ContentChangeType localContent,
     ContentChangeType remoteContent)
 {
     if (localFileSystemInfo is IDirectoryInfo)
     {
         IDirectoryInfo localFolder    = localFileSystemInfo as IDirectoryInfo;
         IDirectoryInfo localParent    = localFolder.Parent;
         IFolder        remoteFolder   = remoteId as IFolder;
         string         remoteParentId = remoteFolder.ParentId;
         IMappedObject  mappedParent   = this.Storage.GetObjectByRemoteId(remoteParentId);
         IMappedObject  mappedObject   = this.Storage.GetObjectByRemoteId(remoteFolder.Id);
         if (localParent.Uuid == mappedParent.Guid)
         {
             // Both folders are in the same parent folder
             this.SyncNamesAndDates(localFolder, remoteFolder, mappedObject);
         }
         else
         {
             OperationsLogger.Warn(
                 string.Format(
                     "Synchronization Conflict: The local directory {0} has been moved to {1} with id {2},{4}" +
                     "but the remote folder was moved to {3}{4}You can fix this situation by moving them into the same folder",
                     localFileSystemInfo.Name,
                     localFileSystemInfo.FullName,
                     remoteFolder.Path,
                     Environment.NewLine));
             return;
         }
     }
     else if (localFileSystemInfo is IFileInfo)
     {
         IFileInfo      localFile      = localFileSystemInfo as IFileInfo;
         IDirectoryInfo localParent    = localFile.Directory;
         IDocument      remoteFile     = remoteId as IDocument;
         string         remoteParentId = remoteFile.Parents[0].Id;
         IMappedObject  mappedParent   = this.Storage.GetObjectByRemoteId(remoteParentId);
         IMappedObject  mappedObject   = this.Storage.GetObjectByRemoteId(remoteFile.Id);
         if (localParent.Uuid == mappedParent.Guid)
         {
             // Both files are in the same parent folder
             mappedObject.ParentId = remoteParentId;
             this.Storage.SaveMappedObject(mappedObject);
             throw new ArgumentException("Solved move conflict => invoke crawl sync to detect other changes");
         }
         else
         {
             OperationsLogger.Warn(
                 string.Format(
                     "Synchronization Conflict: The local file {0} has been moved to {1} with id {2},{4}" +
                     "but the remote file was moved to {3}{4}You can fix this situation by moving them into the same folder",
                     localFileSystemInfo.Name,
                     localFileSystemInfo.FullName,
                     remoteFile.Paths[0],
                     Environment.NewLine));
             return;
         }
     }
 }
 public override void Solve(
     IFileSystemInfo localFileSystemInfo,
     IObjectId remoteId,
     ContentChangeType localContent,
     ContentChangeType remoteContent)
 {
     throw new NotImplementedException();
 }
Beispiel #35
0
 /// <summary>
 /// Solve the specified situation by using localFile and remote object.
 /// </summary>
 /// <param name="localFileSystemInfo">Local filesystem info instance.</param>
 /// <param name="remoteId">Remote identifier or object.</param>
 /// <param name="localContent">Signalizes how the local content has been modified.</param>
 /// <param name="remoteContent">Signalizes how the remote content has been modified.</param>
 public abstract void Solve(
     IFileSystemInfo localFileSystemInfo,
     IObjectId remoteId,
     ContentChangeType localContent,
     ContentChangeType remoteContent);
Beispiel #36
0
        /// <summary>
        /// Solve the specified situation by using the storage, localFile and remoteId.
        /// Uploads the file content if content has been changed. Otherwise simply saves the
        /// last modification date.
        /// </summary>
        /// <param name="localFileSystemInfo">Local filesystem info instance.</param>
        /// <param name="remoteId">Remote identifier or object.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent  = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            if (!localFileSystemInfo.Exists)
            {
                throw new ArgumentException("Given local path does not exists: " + localFileSystemInfo.FullName);
            }

            // Match local changes to remote changes and updated them remotely
            IMappedObject mappedObject = null;

            try {
                string ea = localFileSystemInfo.GetExtendedAttribute(MappedObject.ExtendedAttributeKey);
                Guid   guid;
                if (Guid.TryParse(ea, out guid))
                {
                    mappedObject = this.Storage.GetObjectByGuid(guid);
                }
            } catch (Exception) {
            }

            if (mappedObject == null)
            {
                mappedObject = this.Storage.GetObjectByLocalPath(localFileSystemInfo);
            }

            if (mappedObject == null)
            {
                throw new ArgumentException(string.Format("Could not find db entry for {0} => invoke crawl sync", localFileSystemInfo.FullName));
            }

            IFileInfo localFile = localFileSystemInfo as IFileInfo;

            if (localFile != null && localFile.IsContentChangedTo(mappedObject, scanOnlyIfModificationDateDiffers: true))
            {
                Logger.Debug(string.Format("\"{0}\" is different from {1}", localFile.FullName, mappedObject.ToString()));
                OperationsLogger.Debug(string.Format("Local file \"{0}\" has been changed", localFile.FullName));
                IFileUploader         uploader          = FileTransmission.ContentTaskUtils.CreateUploader();
                var                   doc               = remoteId as IDocument;
                FileTransmissionEvent transmissionEvent = new FileTransmissionEvent(FileTransmissionType.UPLOAD_MODIFIED_FILE, localFile.FullName);
                this.transmissionManager.AddTransmission(transmissionEvent);
                transmissionEvent.ReportProgress(new TransmissionProgressEventArgs {
                    Started = true
                });
                using (var hashAlg = new SHA1Managed())
                    using (var file = localFile.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)) {
                        try {
                            uploader.UploadFile(doc, file, transmissionEvent, hashAlg);
                        } catch (Exception ex) {
                            transmissionEvent.ReportProgress(new TransmissionProgressEventArgs {
                                FailedException = ex
                            });
                            if (ex.InnerException is CmisPermissionDeniedException)
                            {
                                OperationsLogger.Warn(string.Format("Local changed file \"{0}\" has been not been uploaded: PermissionDenied", localFile.FullName));
                                return;
                            }

                            throw;
                        }

                        mappedObject.LastChecksum = hashAlg.Hash;
                    }

                mappedObject.LastChangeToken        = doc.ChangeToken;
                mappedObject.LastRemoteWriteTimeUtc = doc.LastModificationDate;
                mappedObject.LastLocalWriteTimeUtc  = localFile.LastWriteTimeUtc;
                mappedObject.LastContentSize        = localFile.Length;

                OperationsLogger.Info(string.Format("Local changed file \"{0}\" has been uploaded", localFile.FullName));

                transmissionEvent.ReportProgress(new TransmissionProgressEventArgs {
                    Completed = true
                });
            }

            if (this.ServerCanModifyDateTimes)
            {
                try {
                    if (remoteId is IDocument)
                    {
                        (remoteId as IDocument).UpdateLastWriteTimeUtc(localFileSystemInfo.LastWriteTimeUtc);
                        mappedObject.LastRemoteWriteTimeUtc = localFileSystemInfo.LastWriteTimeUtc;
                    }
                    else if (remoteId is IFolder)
                    {
                        (remoteId as IFolder).UpdateLastWriteTimeUtc(localFileSystemInfo.LastWriteTimeUtc);
                        mappedObject.LastRemoteWriteTimeUtc = localFileSystemInfo.LastWriteTimeUtc;
                    }
                } catch (CmisPermissionDeniedException) {
                    Logger.Debug(string.Format("Locally changed modification date \"{0}\"is not uploaded to the server: PermissionDenied", localFileSystemInfo.LastWriteTimeUtc));
                }
            }

            mappedObject.LastLocalWriteTimeUtc = localFileSystemInfo.LastWriteTimeUtc;
            this.Storage.SaveMappedObject(mappedObject);
        }
Beispiel #37
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GraphContentChangeEventArgs"/> class.
 /// </summary>
 /// <param name="content">The content that has changed.</param>
 /// <param name="index">The index in the content where the change occurred.</param>
 /// <param name="changeType">The type of change that occurred.</param>
 /// <param name="oldValue">The old value of the content.</param>
 /// <param name="newValue">The new value of the content.</param>
 public GraphContentChangeEventArgs(IContent content, Index index, ContentChangeType changeType, object oldValue, object newValue)
     : base(content, index, changeType, oldValue, newValue)
 {
 }
Beispiel #38
0
        // TODO: move this in AssetPropertyGraph as a private method, it's the only usage (could also be inlined or split in 3 methods)
        internal Index RetrieveDerivedIndex(Index baseIndex, ContentChangeType changeType)
        {
            var baseMemberContent = BaseContent as MemberContent;
            if (baseMemberContent == null)
                return Index.Empty;

            switch (changeType)
            {
                case ContentChangeType.ValueChange:
                {
                    if (baseIndex.IsEmpty)
                        return baseIndex;

                    var baseNode = (AssetNode)BaseContent.OwnerNode;
                    ItemId baseId;
                    if (!baseNode.TryIndexToId(baseIndex, out baseId))
                        return Index.Empty;

                    Index index;
                    // Find the index of the item in this instance corresponding to the modified item in the base.
                    return TryIdToIndex(baseId, out index) ? index : Index.Empty;
                }
                case ContentChangeType.CollectionAdd:
                {
                    if (baseIndex.IsEmpty)
                        return Index.Empty;

                    var baseNode = (AssetNode)BaseContent.OwnerNode;
                    ItemId baseId;
                    if (!baseNode.TryIndexToId(baseIndex, out baseId))
                        throw new InvalidOperationException("Cannot find an identifier matching the index in the base collection");

                    if (BaseContent.Descriptor is CollectionDescriptor)
                    {
                        var currentBaseIndex = baseIndex.Int - 1;
                        // Find the first item before the new one that also exists (in term of id) in the local node
                        while (currentBaseIndex >= 0)
                        {
                            if (!baseNode.TryIndexToId(new Index(currentBaseIndex), out baseId))
                                throw new InvalidOperationException("Cannot find an identifier matching the index in the base collection");

                            Index localIndex;
                            // If we have an matching item, we want to insert right after it
                            if (TryIdToIndex(baseId, out localIndex))
                                return new Index(localIndex.Int + 1);

                            currentBaseIndex--;
                        }
                        // Otherwise, insert at 0
                        return new Index(0);
                    }
                    return baseIndex;
                }
                case ContentChangeType.CollectionRemove:
                {
                    // If we're removing, we need to find the item id that still exists in our instance but not in the base anymore.
                    var baseIds = CollectionItemIdHelper.GetCollectionItemIds(baseMemberContent.Retrieve());
                    var instanceIds = CollectionItemIdHelper.GetCollectionItemIds(Content.Retrieve());
                    var missingIds = baseIds.FindMissingIds(instanceIds);
                    var foundUnique = false;
                    var index = Index.Empty;
                    foreach (var id in missingIds)
                    {
                        if (TryIdToIndex(id, out index))
                        {
                            if (foundUnique)
                                throw new InvalidOperationException("Couldn't find a unique item id in the instance collection corresponding to the item removed in the base collection");
                            foundUnique = true;
                        }
                    }
                    return index;
                }
                default:
                    throw new ArgumentException(@"Cannot retrieve index in derived asset for a remove operation.", nameof(changeType));
            }
        }
Beispiel #39
0
 private static void VerifyListenerEvent(INodeChangeEventArgs e, IGraphNode nodeOwner, ContentChangeType type, NodeIndex index, object oldValue, object newValue, bool changeApplied)
 {
     Assert.NotNull(e);
     Assert.NotNull(nodeOwner);
     Assert.Equal(type, e.ChangeType);
     Assert.Equal(nodeOwner, e.Node);
     Assert.Equal(index, (e as ItemChangeEventArgs)?.Index ?? NodeIndex.Empty);
     Assert.Equal(newValue, e.NewValue);
     Assert.Equal(oldValue, e.OldValue);
     if (type == ContentChangeType.ValueChange)
     {
         Assert.Equal(changeApplied ? newValue : oldValue, nodeOwner.Retrieve(index));
     }
 }
Beispiel #40
0
        /// <summary>
        /// Adds the Object to Disk and Database
        /// </summary>
        /// <param name='localFile'>
        /// Local file.
        /// </param>
        /// <param name='remoteId'>
        /// Remote Object (already fetched).
        /// </param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        /// <exception cref='ArgumentException'>
        /// Is thrown when remoteId is not prefetched.
        /// </exception>
        public override void Solve(
            IFileSystemInfo localFile,
            IObjectId remoteId,
            ContentChangeType localContent  = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            if (localFile is IDirectoryInfo)
            {
                if (!(remoteId is IFolder))
                {
                    throw new ArgumentException("remoteId has to be a prefetched Folder");
                }

                var            remoteFolder = remoteId as IFolder;
                IDirectoryInfo localFolder  = localFile as IDirectoryInfo;
                localFolder.Create();

                Guid uuid = Guid.Empty;
                if (localFolder.IsExtendedAttributeAvailable())
                {
                    uuid = Guid.NewGuid();
                    try {
                        localFolder.Uuid = uuid;
                    } catch (RestoreModificationDateException) {
                    }
                }

                if (remoteFolder.LastModificationDate != null)
                {
                    localFolder.LastWriteTimeUtc = (DateTime)remoteFolder.LastModificationDate;
                }

                var mappedObject = new MappedObject(remoteFolder);
                mappedObject.Guid = uuid;
                mappedObject.LastRemoteWriteTimeUtc = remoteFolder.LastModificationDate;
                mappedObject.LastLocalWriteTimeUtc  = localFolder.LastWriteTimeUtc;
                this.Storage.SaveMappedObject(mappedObject);
                OperationsLogger.Info(string.Format("New local folder {0} created and mapped to remote folder {1}", localFolder.FullName, remoteId.Id));
            }
            else if (localFile is IFileInfo)
            {
                Guid guid = Guid.NewGuid();
                var  file = localFile as IFileInfo;
                if (!(remoteId is IDocument))
                {
                    throw new ArgumentException("remoteId has to be a prefetched Document");
                }

                if (file.Exists)
                {
                    Guid?uuid = file.Uuid;
                    if (uuid != null)
                    {
                        if (this.Storage.GetObjectByGuid((Guid)uuid) != null)
                        {
                            throw new ArgumentException("This file has already been synced => force crawl sync");
                        }
                    }

                    Logger.Debug(string.Format("This file {0} conflicts with remote file => conflict file will be produced after download", file.FullName));
                }

                var cacheFile = this.fsFactory.CreateDownloadCacheFileInfo(guid);

                IDocument remoteDoc         = remoteId as IDocument;
                var       transmissionEvent = new FileTransmissionEvent(FileTransmissionType.DOWNLOAD_NEW_FILE, localFile.FullName, cacheFile.FullName);
                this.manager.AddTransmission(transmissionEvent);
                byte[] hash = null;
                using (var hashAlg = new SHA1Managed())
                    using (var fileStream = cacheFile.Open(FileMode.Create, FileAccess.Write, FileShare.Read))
                        using (var downloader = FileTransmission.ContentTaskUtils.CreateDownloader())
                        {
                            try {
                                downloader.DownloadFile(remoteDoc, fileStream, transmissionEvent, hashAlg);
                            } catch (Exception ex) {
                                transmissionEvent.ReportProgress(new TransmissionProgressEventArgs {
                                    FailedException = ex
                                });
                                throw;
                            }

                            hash = hashAlg.Hash;
                        }

                cacheFile.Uuid = guid;
                try {
                    cacheFile.MoveTo(file.FullName);
                } catch (IOException e) {
                    file.Refresh();
                    if (file.Exists)
                    {
                        IFileInfo conflictFile = this.fsFactory.CreateConflictFileInfo(file);
                        IFileInfo targetFile   = cacheFile.Replace(file, conflictFile, true);
                        targetFile.SetExtendedAttribute(MappedObject.ExtendedAttributeKey, guid.ToString(), true);
                        conflictFile.SetExtendedAttribute(MappedObject.ExtendedAttributeKey, null, true);
                    }
                    else
                    {
                        transmissionEvent.ReportProgress(new TransmissionProgressEventArgs {
                            FailedException = e
                        });
                        throw;
                    }
                }

                file.Refresh();
                if (remoteDoc.LastModificationDate != null)
                {
                    try {
                        file.LastWriteTimeUtc = (DateTime)remoteDoc.LastModificationDate;
                    } catch (IOException e) {
                        Logger.Debug("Cannot set last modification date", e);
                    }
                }

                MappedObject mappedObject = new MappedObject(
                    file.Name,
                    remoteDoc.Id,
                    MappedObjectType.File,
                    remoteDoc.Parents[0].Id,
                    remoteDoc.ChangeToken,
                    remoteDoc.ContentStreamLength ?? 0)
                {
                    Guid = guid,
                    LastLocalWriteTimeUtc  = file.LastWriteTimeUtc,
                    LastRemoteWriteTimeUtc = remoteDoc.LastModificationDate,
                    LastChecksum           = hash,
                    ChecksumAlgorithmName  = "SHA-1"
                };
                this.Storage.SaveMappedObject(mappedObject);
                OperationsLogger.Info(string.Format("New local file {0} created and mapped to remote file {1}", file.FullName, remoteId.Id));
                transmissionEvent.ReportProgress(new TransmissionProgressEventArgs {
                    Completed = true
                });
            }
        }
Beispiel #41
0
        // TODO: move this in AssetPropertyGraph as a private method, it's the only usage (could also be inlined or split in 3 methods)
        internal Index RetrieveDerivedIndex(Index baseIndex, ContentChangeType changeType)
        {
            var baseMemberContent = BaseContent as MemberContent;

            if (baseMemberContent == null)
            {
                return(Index.Empty);
            }

            switch (changeType)
            {
            case ContentChangeType.ValueChange:
            {
                if (baseIndex.IsEmpty)
                {
                    return(baseIndex);
                }

                var    baseNode = (AssetNode)BaseContent.OwnerNode;
                ItemId baseId;
                if (!baseNode.TryIndexToId(baseIndex, out baseId))
                {
                    return(Index.Empty);
                }

                Index index;
                // Find the index of the item in this instance corresponding to the modified item in the base.
                return(TryIdToIndex(baseId, out index) ? index : Index.Empty);
            }

            case ContentChangeType.CollectionAdd:
            {
                if (baseIndex.IsEmpty)
                {
                    return(Index.Empty);
                }

                var    baseNode = (AssetNode)BaseContent.OwnerNode;
                ItemId baseId;
                if (!baseNode.TryIndexToId(baseIndex, out baseId))
                {
                    throw new InvalidOperationException("Cannot find an identifier matching the index in the base collection");
                }

                if (BaseContent.Descriptor is CollectionDescriptor)
                {
                    var currentBaseIndex = baseIndex.Int - 1;
                    // Find the first item before the new one that also exists (in term of id) in the local node
                    while (currentBaseIndex >= 0)
                    {
                        if (!baseNode.TryIndexToId(new Index(currentBaseIndex), out baseId))
                        {
                            throw new InvalidOperationException("Cannot find an identifier matching the index in the base collection");
                        }

                        Index localIndex;
                        // If we have an matching item, we want to insert right after it
                        if (TryIdToIndex(baseId, out localIndex))
                        {
                            return(new Index(localIndex.Int + 1));
                        }

                        currentBaseIndex--;
                    }
                    // Otherwise, insert at 0
                    return(new Index(0));
                }
                return(baseIndex);
            }

            case ContentChangeType.CollectionRemove:
            {
                // If we're removing, we need to find the item id that still exists in our instance but not in the base anymore.
                var baseIds     = CollectionItemIdHelper.GetCollectionItemIds(baseMemberContent.Retrieve());
                var instanceIds = CollectionItemIdHelper.GetCollectionItemIds(Content.Retrieve());
                var missingIds  = baseIds.FindMissingIds(instanceIds);
                var foundUnique = false;
                var index       = Index.Empty;
                foreach (var id in missingIds)
                {
                    if (TryIdToIndex(id, out index))
                    {
                        if (foundUnique)
                        {
                            throw new InvalidOperationException("Couldn't find a unique item id in the instance collection corresponding to the item removed in the base collection");
                        }
                        foundUnique = true;
                    }
                }
                return(index);
            }

            default:
                throw new ArgumentException(@"Cannot retrieve index in derived asset for a remove operation.", nameof(changeType));
            }
        }
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent,
            ContentChangeType remoteContent)
        {
            var savedObject = this.Storage.GetObjectByRemoteId(remoteId.Id);
            string oldPath = localFileSystemInfo.FullName;
            string oldName = (remoteId as ICmisObject).Name;
            if ((remoteId as ICmisObject).Name != savedObject.Name) {
                // Both are renamed and remote is also moved => move & rename/rename
                string newPath = remoteId is IFolder ? this.Storage.Matcher.CreateLocalPath(remoteId as IFolder) : this.Storage.Matcher.CreateLocalPath(remoteId as IDocument);
                if ((remoteId as ICmisObject).Name == localFileSystemInfo.Name) {
                    // Move local object to new name, bacause it is the same => only change/change solver is needed
                    this.MoveTo(localFileSystemInfo, oldPath, newPath);
                    savedObject.Name = localFileSystemInfo.Name;
                    savedObject.ParentId = remoteId is IFolder ? (remoteId as IFolder).ParentId : (remoteId as IDocument).Parents[0].Id;
                    this.Storage.SaveMappedObject(savedObject);
                    this.changeChangeSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
                } else {
                    // Only move local object to new folder but keep the old name => both names are different => rename/rename solver needed
                    newPath = newPath.TrimEnd(Path.DirectorySeparatorChar);
                    newPath = newPath.Substring(0, newPath.Length - (remoteId as ICmisObject).Name.Length) + oldName;
                    this.MoveTo(localFileSystemInfo, oldPath, newPath);
                    savedObject.ParentId = remoteId is IFolder ? (remoteId as IFolder).ParentId : (remoteId as IDocument).Parents[0].Id;
                    this.Storage.SaveMappedObject(savedObject);
                    this.renameRenameSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
                }
            } else {
                // Local rename and remote move => move locally and rename remote => change/change
                try {
                    // rename remote file
                    (remoteId as ICmisObject).Rename(localFileSystemInfo.Name, true);
                    OperationsLogger.Info(string.Format("Renamed remote object {0} from {1} to {2}", remoteId.Id, oldName, localFileSystemInfo.Name));
                    savedObject.Name = (remoteId as ICmisObject).Name;
                } catch (CmisConstraintException e) {
                    if (!Utils.IsValidISO885915(localFileSystemInfo.Name)) {
                        OperationsLogger.Warn(string.Format("Server denied to rename {0} to {1}, perhaps because it contains UTF-8 characters", oldName, localFileSystemInfo.Name));
                        throw new InteractionNeededException(string.Format("Server denied renaming of {0}", oldName), e) {
                            Title = string.Format("Server denied renaming of {0}", oldName),
                            Description = string.Format("Server denied to rename {0} to {1}, perhaps because it contains UTF-8 characters", oldName, localFileSystemInfo.Name)
                        };
                    }

                    throw;
                } catch (CmisPermissionDeniedException) {
                    OperationsLogger.Info(string.Format("Permission Denied: Cannot rename remote object ({1}): {0}", (remoteId as ICmisObject).Name, remoteId.Id));
                    return;
                }

                string newPath = remoteId is IFolder ? this.Storage.Matcher.CreateLocalPath(remoteId as IFolder) : this.Storage.Matcher.CreateLocalPath(remoteId as IDocument);
                // move local object to same directory as the remote object is
                this.MoveTo(localFileSystemInfo, oldPath, newPath);

                savedObject.ParentId = remoteId is IFolder ? (remoteId as IFolder).ParentId : (remoteId as IDocument).Parents[0].Id;
                this.Storage.SaveMappedObject(savedObject);

                // Synchronize the rest with the change change solver
                this.changeChangeSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
            }
        }
        /// <summary>
        /// Solve the specified situation by using the storage, localFile and remoteId.
        /// Uploads the file content if content has been changed. Otherwise simply saves the
        /// last modification date.
        /// </summary>
        /// <param name="localFileSystemInfo">Local filesystem info instance.</param>
        /// <param name="remoteId">Remote identifier or object.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            if (!localFileSystemInfo.Exists) {
                throw new ArgumentException("Given local path does not exists: " + localFileSystemInfo.FullName);
            }

            // Match local changes to remote changes and updated them remotely
            IMappedObject mappedObject = this.Storage.GetObject(localFileSystemInfo);
            if (mappedObject == null) {
                throw new ArgumentException(string.Format("Could not find db entry for {0} => invoke crawl sync", localFileSystemInfo.FullName));
            }

            if (mappedObject.LastChangeToken != (remoteId as ICmisObjectProperties).ChangeToken) {
                throw new ArgumentException(string.Format("remote {1} {0} has also been changed since last sync => invoke crawl sync", remoteId.Id, remoteId is IDocument ? "document" : "folder"));
            }

            IFileInfo localFile = localFileSystemInfo as IFileInfo;
            if (localFile != null && localFile.IsContentChangedTo(mappedObject, scanOnlyIfModificationDateDiffers: true)) {
                Logger.Debug(string.Format("\"{0}\" is different from {1}", localFile.FullName, mappedObject.ToString()));
                OperationsLogger.Debug(string.Format("Local file \"{0}\" has been changed", localFile.FullName));
                var doc = remoteId as IDocument;
                try {
                    var transmission = this.transmissionManager.CreateTransmission(TransmissionType.UPLOAD_MODIFIED_FILE, localFile.FullName);
                    mappedObject.LastChecksum = UploadFile(localFile, doc, transmission);
                } catch(Exception ex) {
                    if (ex.InnerException is CmisPermissionDeniedException) {
                        OperationsLogger.Warn(string.Format("Local changed file \"{0}\" has not been uploaded: PermissionDenied", localFile.FullName));
                        return;
                    } else if (ex.InnerException is CmisStorageException) {
                        OperationsLogger.Warn(string.Format("Local changed file \"{0}\" has not been uploaded: StorageException", localFile.FullName), ex);
                        return;
                    }

                    throw;
                }

                mappedObject.LastRemoteWriteTimeUtc = doc.LastModificationDate;
                mappedObject.LastLocalWriteTimeUtc = localFile.LastWriteTimeUtc;
                mappedObject.LastContentSize = localFile.Length;

                OperationsLogger.Info(string.Format("Local changed file \"{0}\" has been uploaded", localFile.FullName));
            }

            if (this.ServerCanModifyDateTimes) {
                try {
                    if (remoteId is IDocument) {
                        var doc = remoteId as IDocument;
                        doc.UpdateLastWriteTimeUtc(localFileSystemInfo.LastWriteTimeUtc);
                        mappedObject.LastRemoteWriteTimeUtc = doc.LastModificationDate ?? localFileSystemInfo.LastWriteTimeUtc;
                    } else if (remoteId is IFolder) {
                        var folder = remoteId as IFolder;
                        folder.UpdateLastWriteTimeUtc(localFileSystemInfo.LastWriteTimeUtc);
                        mappedObject.LastRemoteWriteTimeUtc = folder.LastModificationDate ?? localFileSystemInfo.LastWriteTimeUtc;
                    }
                } catch(CmisPermissionDeniedException) {
                    Logger.Debug(string.Format("Locally changed modification date \"{0}\"is not uploaded to the server: PermissionDenied", localFileSystemInfo.LastWriteTimeUtc));
                }
            }

            mappedObject.LastChangeToken = (remoteId as ICmisObjectProperties).ChangeToken;
            mappedObject.LastLocalWriteTimeUtc = localFileSystemInfo.LastWriteTimeUtc;
            this.Storage.SaveMappedObject(mappedObject);
        }
Beispiel #44
0
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent,
            ContentChangeType remoteContent)
        {
            var    savedObject   = this.Storage.GetObjectByRemoteId(remoteId.Id);
            Guid?  newParentUuid = localFileSystemInfo is IFileInfo ? (localFileSystemInfo as IFileInfo).Directory.Uuid : (localFileSystemInfo as IDirectoryInfo).Parent.Uuid;
            string newParentId   = this.Storage.GetObjectByGuid((Guid)newParentUuid).RemoteObjectId;

            if (localFileSystemInfo.Name == (remoteId as ICmisObject).Name)
            {
                // Both names are equal => only move to new remote parent
                try {
                    (remoteId as IFileableCmisObject).Move(this.Session.GetObject(savedObject.ParentId), this.Session.GetObject(newParentId));
                } catch (CmisPermissionDeniedException) {
                    OperationsLogger.Info(string.Format("Permission Denied: Cannot move remote object {0} from {1} to {2}", remoteId.Id, savedObject.ParentId, newParentId));
                    return;
                }

                savedObject.Name     = localFileSystemInfo.Name;
                savedObject.ParentId = newParentId;
                this.Storage.SaveMappedObject(savedObject);
                this.changeChangeSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
            }
            else
            {
                // Names are different to each other
                if (localFileSystemInfo.Name == savedObject.Name)
                {
                    // Remote rename and local move => Move remote and rename locally => change change solver
                    try {
                        remoteId = (remoteId as IFileableCmisObject).Move(this.Session.GetObject(savedObject.ParentId), this.Session.GetObject(newParentId));
                    } catch (CmisPermissionDeniedException) {
                        OperationsLogger.Info(string.Format("Permission Denied: Cannot move remote object {0} from {1} to {2}", remoteId.Id, savedObject.ParentId, newParentId));
                        return;
                    }

                    var    localParentPath = localFileSystemInfo is IFileInfo ? (localFileSystemInfo as IFileInfo).Directory.FullName : (localFileSystemInfo as IDirectoryInfo).Parent.FullName;
                    string newPath         = Path.Combine(localParentPath, (remoteId as ICmisObject).Name);
                    this.MoveTo(localFileSystemInfo, localFileSystemInfo.FullName, newPath);
                    savedObject.Name     = localFileSystemInfo.Name;
                    savedObject.ParentId = newParentId;
                    this.Storage.SaveMappedObject(savedObject);
                    this.changeChangeSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
                }
                else
                {
                    // Both sides have been renamed => Move remote => rename rename solver
                    try {
                        (remoteId as IFileableCmisObject).Move(this.Session.GetObject(savedObject.ParentId), this.Session.GetObject(newParentId));
                    } catch (CmisPermissionDeniedException) {
                        OperationsLogger.Info(string.Format("Permission Denied: Cannot move remote object {0} from {1} to {2}", remoteId.Id, savedObject.ParentId, newParentId));
                        return;
                    }

                    savedObject.ParentId = newParentId;
                    this.Storage.SaveMappedObject(savedObject);
                    this.renameRenameSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
                }
            }
        }
 private static void VerifyListenerEvent(GraphContentChangeEventArgs e, IGraphNode contentOwner, ContentChangeType type, Index index, object oldValue, object newValue, bool changeApplied)
 {
     Assert.NotNull(e);
     Assert.NotNull(contentOwner);
     Assert.AreEqual(type, e.ChangeType);
     Assert.AreEqual(contentOwner.Content, e.Content);
     Assert.AreEqual(index, e.Index);
     Assert.AreEqual(newValue, e.NewValue);
     Assert.AreEqual(oldValue, e.OldValue);
     if (type == ContentChangeType.ValueChange)
     {
         Assert.AreEqual(changeApplied ? newValue : oldValue, contentOwner.Content.Retrieve(index));
     }
 }
        /// <summary>
        /// Solve the specified situation by using localFile and remote object.
        /// </summary>
        /// <param name="localFileSystemInfo">Local filesystem info instance.</param>
        /// <param name="remoteId">Remote identifier or object.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent,
            ContentChangeType remoteContent)
        {
            var obj = this.Storage.GetObjectByRemoteId(remoteId.Id);

            if (localFileSystemInfo is IDirectoryInfo)
            {
                obj.LastLocalWriteTimeUtc  = localFileSystemInfo.LastWriteTimeUtc;
                obj.LastRemoteWriteTimeUtc = (remoteId as IFolder).LastModificationDate;
                obj.LastChangeToken        = (remoteId as IFolder).ChangeToken;
                this.Storage.SaveMappedObject(obj);
            }
            else if (localFileSystemInfo is IFileInfo)
            {
                var  fileInfo         = localFileSystemInfo as IFileInfo;
                var  doc              = remoteId as IDocument;
                bool updateLocalDate  = false;
                bool updateRemoteDate = false;
                if (remoteContent == ContentChangeType.NONE)
                {
                    if (fileInfo.IsContentChangedTo(obj, true))
                    {
                        // Upload local content
                        updateRemoteDate = true;
                        try {
                            obj.LastChecksum    = LocalObjectChanged.UploadFile(fileInfo, doc, this.transmissionManager);
                            obj.LastContentSize = doc.ContentStreamLength ?? fileInfo.Length;
                        } catch (Exception ex) {
                            if (ex.InnerException is CmisPermissionDeniedException)
                            {
                                OperationsLogger.Warn(string.Format("Local changed file \"{0}\" has not been uploaded: PermissionDenied", fileInfo.FullName), ex.InnerException);
                                return;
                            }

                            throw;
                        }
                    }
                    else
                    {
                        // Just date sync
                        if (doc.LastModificationDate != null && fileInfo.LastWriteTimeUtc < (DateTime)doc.LastModificationDate)
                        {
                            updateLocalDate = true;
                        }
                        else
                        {
                            updateRemoteDate = true;
                        }
                    }
                }
                else
                {
                    byte[] actualLocalHash;
                    if (fileInfo.IsContentChangedTo(obj, out actualLocalHash, true))
                    {
                        // Check if both are changed to the same value
                        if (actualLocalHash == null)
                        {
                            using (var f = fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)) {
                                actualLocalHash = SHA1Managed.Create().ComputeHash(f);
                            }
                        }

                        byte[] remoteHash = doc.ContentStreamHash();
                        if (remoteHash != null && actualLocalHash.SequenceEqual(remoteHash))
                        {
                            // Both files are equal
                            obj.LastChecksum    = remoteHash;
                            obj.LastContentSize = fileInfo.Length;

                            // Sync dates
                            if (doc.LastModificationDate != null && fileInfo.LastWriteTimeUtc < (DateTime)doc.LastModificationDate)
                            {
                                updateLocalDate = true;
                            }
                            else
                            {
                                updateRemoteDate = true;
                            }
                        }
                        else
                        {
                            // Both are different => Check modification dates
                            // Download remote version and create conflict file
                            updateLocalDate     = true;
                            obj.LastChecksum    = DownloadChanges(fileInfo, doc, obj, this.fsFactory, this.transmissionManager, Logger);
                            obj.LastContentSize = doc.ContentStreamLength ?? 0;
                        }
                    }
                    else
                    {
                        // Download remote content
                        updateLocalDate     = true;
                        obj.LastChecksum    = DownloadChanges(fileInfo, doc, obj, this.fsFactory, this.transmissionManager, Logger);
                        obj.LastContentSize = doc.ContentStreamLength ?? 0;
                    }
                }

                if (this.ServerCanModifyDateTimes)
                {
                    if (updateLocalDate)
                    {
                        fileInfo.LastWriteTimeUtc = (DateTime)doc.LastModificationDate;
                    }
                    else if (updateRemoteDate)
                    {
                        doc.UpdateLastWriteTimeUtc(fileInfo.LastWriteTimeUtc);
                    }
                    else
                    {
                        throw new ArgumentException();
                    }
                }

                obj.LastChangeToken        = doc.ChangeToken;
                obj.LastLocalWriteTimeUtc  = localFileSystemInfo.LastWriteTimeUtc;
                obj.LastRemoteWriteTimeUtc = doc.LastModificationDate;
                this.Storage.SaveMappedObject(obj);
            }
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="GraphContentChangeEventArgs"/> class.
 /// </summary>
 /// <param name="content">The content that has changed.</param>
 /// <param name="index">The index in the content where the change occurred.</param>
 /// <param name="changeType">The type of change that occurred.</param>
 /// <param name="oldValue">The old value of the content.</param>
 /// <param name="newValue">The new value of the content.</param>
 /// <param name="path">The path to the node of content that has been modified.</param>
 public GraphContentChangeEventArgs(IContent content, Index index, ContentChangeType changeType, object oldValue, object newValue, GraphNodePath path)
     : base(content, index, changeType, oldValue, newValue)
 {
     Path = path;
 }
Beispiel #48
0
        private async Task UpdateGameSideReference([NotNull] AssetCompositeEditorViewModel editor, [NotNull] IGraphNode gameSideNode, ContentChangeType changeType, object oldValue, object newValue, Index index)
        {
            if (editor == null)
            {
                throw new ArgumentNullException(nameof(editor));
            }

            if (!AssetRegistry.IsContentType(gameSideNode.Descriptor.GetInnerCollectionType()))
            {
                return;
            }

            // Grab the old referenced object if it's not null
            AttachedReference reference = null;

            if (!ReferenceEquals(oldValue, null))
            {
                reference = AttachedReferenceManager.GetAttachedReference(oldValue);
            }

            // Switch to game thread to actually update objects
            await editor.Controller.InvokeTask(() =>
            {
                // For references, push null instead of the real value, the editor asset loader will set the actual value later
                switch (changeType)
                {
                case ContentChangeType.ValueChange:
                    ((IMemberNode)gameSideNode).Update(null);
                    break;

                case ContentChangeType.CollectionUpdate:
                    ((IObjectNode)gameSideNode).Update(null, index);
                    break;

                case ContentChangeType.CollectionAdd:
                    ((IObjectNode)gameSideNode).Add(null, index);
                    break;

                case ContentChangeType.CollectionRemove:
                    var oldValueGameSide = gameSideNode.Retrieve(index);
                    ((IObjectNode)gameSideNode).Remove(oldValueGameSide, index);
                    break;

                default:
                    throw new ArgumentOutOfRangeException(nameof(changeType), changeType, null);
                }

                if (oldValue == newValue)
                {
                    return(Task.CompletedTask);
                }

                // Unregister the previous value
                if (reference != null)
                {
                    return(editor.Controller.Loader.Manager.ClearContentReference(Owner.Id, reference.Id, gameSideNode, index));
                }
                return(Task.CompletedTask);
            });
        }
        /// <summary>
        /// Solve the specified situation by taking renaming the local or remote object to the name of the last changed object.
        /// </summary>
        /// <param name="localFileSystemInfo">Local file system info.</param>
        /// <param name="remoteId">Remote object.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            if (localFileSystemInfo is IDirectoryInfo) {
                var localFolder = localFileSystemInfo as IDirectoryInfo;
                var remoteFolder = remoteId as IFolder;
                var mappedObject = this.Storage.GetObjectByRemoteId(remoteFolder.Id);
                if (localFolder.Name.Equals(remoteFolder.Name)) {
                    mappedObject.Name = localFolder.Name;
                } else if (localFolder.LastWriteTimeUtc.CompareTo((DateTime)remoteFolder.LastModificationDate) > 0) {
                    string oldName = remoteFolder.Name;
                    try {
                        remoteFolder.Rename(localFolder.Name, true);
                    } catch (CmisConstraintException e) {
                        if (!Utils.IsValidISO885915(localFolder.Name)) {
                            OperationsLogger.Warn(string.Format("Server denied to rename {0} to {1}, perhaps because it contains UTF-8 characters", oldName, localFolder.Name));
                            throw new InteractionNeededException(string.Format("Server denied renaming of {0}", oldName), e) {
                                Title = string.Format("Server denied renaming of {0}", oldName),
                                Description = string.Format("Server denied to rename {0} to {1}, perhaps because it contains UTF-8 characters", oldName, localFolder.Name)
                            };
                        }

                        throw;
                    }

                    mappedObject.Name = remoteFolder.Name;
                    OperationsLogger.Info(string.Format("Renamed remote folder {0} with id {2} to {1}", oldName, remoteFolder.Id, remoteFolder.Name));
                } else {
                    string oldName = localFolder.Name;
                    localFolder.MoveTo(Path.Combine(localFolder.Parent.FullName, remoteFolder.Name));
                    mappedObject.Name = remoteFolder.Name;
                    OperationsLogger.Info(string.Format("Renamed local folder {0} to {1}", Path.Combine(localFolder.Parent.FullName, oldName), remoteFolder.Name));
                }

                mappedObject.LastLocalWriteTimeUtc = localFolder.LastWriteTimeUtc;
                mappedObject.LastRemoteWriteTimeUtc = (DateTime)remoteFolder.LastModificationDate;
                mappedObject.LastChangeToken = remoteFolder.ChangeToken;
                mappedObject.Ignored = remoteFolder.AreAllChildrenIgnored();
                this.Storage.SaveMappedObject(mappedObject);
            } else if (localFileSystemInfo is IFileInfo) {
                var localFile = localFileSystemInfo as IFileInfo;
                var remoteFile = remoteId as IDocument;
                var mappedObject = this.Storage.GetObjectByRemoteId(remoteFile.Id);
                if (localFile.Name.Equals(remoteFile.Name)) {
                    mappedObject.Name = localFile.Name;
                    this.Storage.SaveMappedObject(mappedObject);
                    this.changeChangeSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
                } else {
                    string desc = string.Format(
                        "The local file {0} has been locally renamed from {1} to {2} and remotely to {3}. " +
                        "Fix this conflict by renaming the remote file to {2} or the local file to {3}.",
                        localFile.FullName,
                        mappedObject.Name,
                        localFile.Name,
                        remoteFile.Name);
                    OperationsLogger.Warn("Synchronization Conflict: " + desc);
                    throw new InteractionNeededException("Synchronization Conflict") {
                        Title = "Synchronization Conflict",
                        Description = desc
                    };
                }
            }
        }
Beispiel #50
0
        /// <summary>
        /// Solve the specified situation by using localFile and remote object.
        /// </summary>
        /// <param name="localFileSystemInfo">Local filesystem info instance.</param>
        /// <param name="remoteId">Remote identifier or object.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent  = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            Stopwatch completewatch = new Stopwatch();

            completewatch.Start();
            Logger.Debug("Starting LocalObjectAdded");
            localFileSystemInfo.Refresh();
            if (!localFileSystemInfo.Exists)
            {
                throw new FileNotFoundException(string.Format("Local file/folder {0} has been renamed/moved/deleted", localFileSystemInfo.FullName));
            }

            string parentId = Storage.GetRemoteId(this.GetParent(localFileSystemInfo));

            if (parentId == null)
            {
                if (this.IsParentReadOnly(localFileSystemInfo))
                {
                    return;
                }
                else
                {
                    throw new ArgumentException("ParentId is null => invoke crawl sync to create parent first");
                }
            }

            ICmisObject addedObject;

            try {
                addedObject = this.AddCmisObject(localFileSystemInfo, parentId, this.Session);
            } catch (CmisConstraintException e) {
                this.EnsureThatLocalFileNameContainsLegalCharacters(localFileSystemInfo, e);
                throw;
            } catch (CmisPermissionDeniedException e) {
                OperationsLogger.Warn(string.Format("Permission denied while trying to Create the locally added object {0} on the server ({1}).", localFileSystemInfo.FullName, e.Message));
                return;
            }

            Guid uuid = this.WriteOrUseUuidIfSupported(localFileSystemInfo);

            OperationsLogger.Info(string.Format("Created remote {2} {0} for {1}", addedObject.Id, localFileSystemInfo.FullName, addedObject is IFolder ? "folder" : "document"));

            MappedObject mapped = new MappedObject(
                localFileSystemInfo.Name,
                addedObject.Id,
                localFileSystemInfo is IDirectoryInfo ? MappedObjectType.Folder : MappedObjectType.File,
                parentId,
                addedObject.ChangeToken)
            {
                Guid = uuid,
                LastRemoteWriteTimeUtc = addedObject.LastModificationDate,
                LastLocalWriteTimeUtc  = localFileSystemInfo is IFileInfo && (localFileSystemInfo as IFileInfo).Length > 0 ? (DateTime?)null : (DateTime?)localFileSystemInfo.LastWriteTimeUtc,
                LastChangeToken        = addedObject.ChangeToken,
                LastContentSize        = localFileSystemInfo is IDirectoryInfo ? -1 : 0,
                ChecksumAlgorithmName  = localFileSystemInfo is IDirectoryInfo ? null : "SHA-1",
                LastChecksum           = localFileSystemInfo is IDirectoryInfo ? null : SHA1.Create().ComputeHash(new byte[0])
            };

            this.Storage.SaveMappedObject(mapped);

            var localFile = localFileSystemInfo as IFileInfo;

            if (localFile != null)
            {
                var transmission = this.transmissionManager.CreateTransmission(TransmissionType.UPLOAD_NEW_FILE, localFile.FullName);
                if (localFile.Length > 0)
                {
                    Stopwatch watch = new Stopwatch();
                    OperationsLogger.Debug(string.Format("Uploading file content of {0}", localFile.FullName));
                    watch.Start();
                    try {
                        mapped.LastChecksum          = this.UploadFile(localFile, addedObject as IDocument, transmission);
                        mapped.ChecksumAlgorithmName = "SHA-1";
                    } catch (Exception ex) {
                        if (ex is UploadFailedException && (ex as UploadFailedException).InnerException is CmisStorageException)
                        {
                            OperationsLogger.Warn(string.Format("Could not upload file content of {0}:", localFile.FullName), (ex as UploadFailedException).InnerException);
                            return;
                        }

                        throw;
                    }

                    watch.Stop();

                    if (this.ServerCanModifyDateTimes)
                    {
                        (addedObject as IDocument).UpdateLastWriteTimeUtc(localFile.LastWriteTimeUtc);
                    }

                    mapped.LastContentSize        = localFile.Length;
                    mapped.LastChangeToken        = addedObject.ChangeToken;
                    mapped.LastRemoteWriteTimeUtc = addedObject.LastModificationDate;
                    mapped.LastLocalWriteTimeUtc  = localFileSystemInfo.LastWriteTimeUtc;

                    this.Storage.SaveMappedObject(mapped);
                    OperationsLogger.Info(string.Format("Uploaded file content of {0} in [{1} msec]", localFile.FullName, watch.ElapsedMilliseconds));
                }
                else
                {
                    transmission.Length   = 0;
                    transmission.Position = 0;
                    transmission.Status   = TransmissionStatus.FINISHED;
                }
            }

            completewatch.Stop();
            Logger.Debug(string.Format("Finished LocalObjectAdded after [{0} msec]", completewatch.ElapsedMilliseconds));
        }
        /// <summary>
        /// Solve the specified situation by using localFile and remote object.
        /// </summary>
        /// <param name="localFileSystemInfo">Local filesystem info instance.</param>
        /// <param name="remoteId">Remote identifier or object.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent  = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            if (localFileSystemInfo is IFileInfo)
            {
                IFileInfo localFile = localFileSystemInfo as IFileInfo;
                localFile.Refresh();
                if (!localFile.Exists)
                {
                    throw new FileNotFoundException(string.Format("Local file {0} has been renamed/moved/deleted", localFile.FullName));
                }

                if (localFile.Length == 0)
                {
                    this.folderOrEmptyFileAddedSolver.Solve(localFileSystemInfo, null, localContent, remoteContent);
                    return;
                }

                string parentId = this.Storage.GetRemoteId(localFile.Directory);
                if (parentId == null)
                {
                    if (this.IsParentReadOnly(localFile))
                    {
                        return;
                    }
                    else
                    {
                        throw new ArgumentException("ParentId is null => invoke crawl sync to create parent first");
                    }
                }

                IDocument remoteDocument;
                try {
                    remoteDocument = this.CreateOrLoadExistingRemoteDocument(localFile, new ObjectId(parentId));
                } catch (CmisPermissionDeniedException e) {
                    OperationsLogger.Warn(string.Format("Permission denied while trying to Create the locally added object {0} on the server ({1}).", localFile.FullName, e.Message));
                    return;
                }

                Guid uuid = this.WriteOrUseUuidIfSupported(localFile);

                var transmission = this.transmissionManager.CreateTransmission(TransmissionType.UPLOAD_NEW_FILE, localFile.FullName);

                MappedObject mapped = new MappedObject(
                    localFile.Name,
                    remoteDocument.Id,
                    MappedObjectType.File,
                    parentId,
                    remoteDocument.ChangeToken)
                {
                    Guid = uuid,
                    LastRemoteWriteTimeUtc = remoteDocument.LastModificationDate,
                    LastLocalWriteTimeUtc  = (DateTime?)localFileSystemInfo.LastWriteTimeUtc,
                    LastChangeToken        = remoteDocument.ChangeToken,
                    LastContentSize        = 0,
                    ChecksumAlgorithmName  = "SHA-1",
                    LastChecksum           = SHA1.Create().ComputeHash(new byte[0])
                };

                Stopwatch watch = new Stopwatch();
                OperationsLogger.Debug(string.Format("Uploading file content of {0}", localFile.FullName));
                watch.Start();
                try {
                    mapped.LastChecksum          = this.UploadFileWithPWC(localFile, ref remoteDocument, transmission);
                    mapped.ChecksumAlgorithmName = "SHA-1";
                    mapped.RemoteObjectId        = remoteDocument.Id;
                } catch (Exception ex) {
                    if (ex is UploadFailedException && (ex as UploadFailedException).InnerException is CmisStorageException)
                    {
                        OperationsLogger.Warn(string.Format("Could not upload file content of {0}:", localFile.FullName), (ex as UploadFailedException).InnerException);
                        return;
                    }

                    throw;
                }
                watch.Stop();

                mapped.LastContentSize        = localFile.Length;
                mapped.LastChangeToken        = remoteDocument.ChangeToken;
                mapped.LastRemoteWriteTimeUtc = remoteDocument.LastModificationDate;
                mapped.LastLocalWriteTimeUtc  = localFileSystemInfo.LastWriteTimeUtc;

                this.Storage.SaveMappedObject(mapped);
                OperationsLogger.Info(string.Format("Uploaded file content of {0} in [{1} msec]", localFile.FullName, watch.ElapsedMilliseconds));
            }
            else
            {
                this.folderOrEmptyFileAddedSolver.Solve(localFileSystemInfo, remoteId, localContent, remoteContent);
            }
        }
Beispiel #52
0
        /// <summary>
        /// Renames the specified localFile to the name of the given remoteId object by using the storage, localFile and remoteId.
        /// </summary>
        /// <param name="localFile">Local file or folder. It is the source file/folder reference, which should be renamed.</param>
        /// <param name="remoteId">Remote identifier. Should be an instance of IFolder or IDocument.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFile,
            IObjectId remoteId,
            ContentChangeType localContent  = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            IMappedObject obj = this.Storage.GetObjectByRemoteId(remoteId.Id);

            if (remoteId is IFolder)
            {
                // Rename local folder
                IFolder        remoteFolder = remoteId as IFolder;
                IDirectoryInfo dirInfo      = localFile as IDirectoryInfo;
                string         oldPath      = dirInfo.FullName;
                try {
                    dirInfo.MoveTo(Path.Combine(dirInfo.Parent.FullName, remoteFolder.Name));
                    obj.Name = remoteFolder.Name;
                } catch (IOException) {
                    if (dirInfo.Name.Equals(remoteFolder.Name, StringComparison.OrdinalIgnoreCase))
                    {
                        obj.Name = dirInfo.Name;
                    }
                    else
                    {
                        throw;
                    }
                }

                if (remoteFolder.LastModificationDate != null)
                {
                    dirInfo.LastWriteTimeUtc = (DateTime)remoteFolder.LastModificationDate;
                }


                obj.LastChangeToken        = remoteFolder.ChangeToken;
                obj.LastRemoteWriteTimeUtc = remoteFolder.LastModificationDate;
                obj.LastLocalWriteTimeUtc  = dirInfo.LastWriteTimeUtc;
                this.Storage.SaveMappedObject(obj);
                OperationsLogger.Info(string.Format("Renamed local folder {0} to {1}", oldPath, remoteFolder.Name));
            }
            else if (remoteId is IDocument)
            {
                // Rename local file
                IDocument remoteDocument = remoteId as IDocument;
                IFileInfo fileInfo       = localFile as IFileInfo;
                string    oldPath        = fileInfo.FullName;
                fileInfo.MoveTo(Path.Combine(fileInfo.Directory.FullName, remoteDocument.Name));
                if (remoteDocument.LastModificationDate != null)
                {
                    fileInfo.LastWriteTimeUtc = (DateTime)remoteDocument.LastModificationDate;
                }

                obj.Name                   = remoteDocument.Name;
                obj.LastChangeToken        = remoteContent == ContentChangeType.NONE ? remoteDocument.ChangeToken : obj.LastChangeToken;
                obj.LastRemoteWriteTimeUtc = remoteContent == ContentChangeType.NONE ? remoteDocument.LastModificationDate : obj.LastRemoteWriteTimeUtc;
                obj.LastLocalWriteTimeUtc  = fileInfo.LastWriteTimeUtc;
                this.Storage.SaveMappedObject(obj);
                OperationsLogger.Info(string.Format("Renamed local file {0} to {1}", oldPath, remoteDocument.Name));
                if (remoteContent != ContentChangeType.NONE)
                {
                    throw new ArgumentException("Remote documents content is also changed => force crawl sync.");
                }
            }
            else
            {
                throw new ArgumentException("Given remote Id is not an IFolder nor an IDocument instance");
            }
        }
Beispiel #53
0
        /// <summary>
        /// Adds the Object to Disk and Database
        /// </summary>
        /// <param name='localFile'>
        /// Local file.
        /// </param>
        /// <param name='remoteId'>
        /// Remote Object (already fetched).
        /// </param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        /// <exception cref='ArgumentException'>
        /// Is thrown when remoteId is not prefetched.
        /// </exception>
        public override void Solve(
            IFileSystemInfo localFile,
            IObjectId remoteId,
            ContentChangeType localContent  = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            if (localFile is IDirectoryInfo)
            {
                if (!(remoteId is IFolder))
                {
                    throw new ArgumentException("remoteId has to be a prefetched Folder");
                }

                var            remoteFolder = remoteId as IFolder;
                IDirectoryInfo localFolder  = localFile as IDirectoryInfo;
                localFolder.Create();

                Guid uuid = Guid.Empty;
                if (localFolder.IsExtendedAttributeAvailable())
                {
                    uuid = Guid.NewGuid();
                    try {
                        localFolder.Uuid = uuid;
                    } catch (RestoreModificationDateException) {
                    }
                }

                if (remoteFolder.LastModificationDate != null)
                {
                    try {
                        localFolder.LastWriteTimeUtc = (DateTime)remoteFolder.LastModificationDate;
                    } catch (IOException e) {
                        Logger.Info("Directory modification date could not be synced", e);
                    }
                }

                var mappedObject = new MappedObject(remoteFolder);
                mappedObject.Guid = uuid;
                mappedObject.LastRemoteWriteTimeUtc = remoteFolder.LastModificationDate;
                mappedObject.LastLocalWriteTimeUtc  = localFolder.LastWriteTimeUtc;
                mappedObject.Ignored = remoteFolder.AreAllChildrenIgnored();
                this.Storage.SaveMappedObject(mappedObject);
                OperationsLogger.Info(string.Format("New local folder {0} created and mapped to remote folder {1}", localFolder.FullName, remoteId.Id));
            }
            else if (localFile is IFileInfo)
            {
                if (!(remoteId is IDocument))
                {
                    throw new ArgumentException("remoteId has to be a prefetched Document");
                }

                Guid     guid          = Guid.NewGuid();
                byte[]   localFileHash = null;
                DateTime?lastLocalFileModificationDate = null;
                var      file = localFile as IFileInfo;
                if (file.Exists)
                {
                    Guid?uuid = file.Uuid;
                    if (uuid != null)
                    {
                        if (this.Storage.GetObjectByGuid((Guid)uuid) != null)
                        {
                            throw new ArgumentException("This file has already been synced => force crawl sync");
                        }
                    }

                    lastLocalFileModificationDate = file.LastWriteTimeUtc;
                    if (this.MergeExistingFileWithRemoteFile(file, remoteId as IDocument, guid, out localFileHash))
                    {
                        return;
                    }

                    Logger.Debug(string.Format("This file {0} conflicts with remote file => conflict file will could be produced after download", file.FullName));
                }

                var cacheFile = this.fsFactory.CreateDownloadCacheFileInfo(guid);

                IDocument remoteDoc    = remoteId as IDocument;
                var       transmission = this.manager.CreateTransmission(TransmissionType.DOWNLOAD_NEW_FILE, localFile.FullName, cacheFile.FullName);
                byte[]    hash         = DownloadCacheFile(cacheFile, remoteDoc, transmission, this.fsFactory);

                try {
                    cacheFile.Uuid = guid;
                } catch (RestoreModificationDateException e) {
                    Logger.Debug("Could not retore the last modification date of " + cacheFile.FullName, e);
                }

                try {
                    cacheFile.MoveTo(file.FullName);
                } catch (IOException e) {
                    file.Refresh();
                    if (file.Exists)
                    {
                        if (localFileHash == null ||
                            lastLocalFileModificationDate == null ||
                            !lastLocalFileModificationDate.Equals(file.LastWriteTimeUtc))
                        {
                            lastLocalFileModificationDate = file.LastWriteTimeUtc;
                            using (var f = file.Open(FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete)) {
                                localFileHash = SHA1Managed.Create().ComputeHash(f);
                            }
                        }

                        if (localFileHash.SequenceEqual(hash))
                        {
                            file.Uuid = guid;
                            try {
                                cacheFile.Delete();
                            } catch (IOException) {
                            }
                        }
                        else
                        {
                            IFileInfo conflictFile = this.fsFactory.CreateConflictFileInfo(file);
                            try {
                                IFileInfo targetFile = cacheFile.Replace(file, conflictFile, true);
                                try {
                                    targetFile.Uuid = guid;
                                } catch (RestoreModificationDateException restoreException) {
                                    Logger.Debug("Could not retore the last modification date of " + targetFile.FullName, restoreException);
                                }
                            } catch (Exception ex) {
                                transmission.FailedException = ex;
                                throw;
                            }

                            try {
                                conflictFile.Uuid = null;
                            } catch (RestoreModificationDateException restoreException) {
                                Logger.Debug("Could not retore the last modification date of " + conflictFile.FullName, restoreException);
                            }
                        }
                    }
                    else
                    {
                        transmission.FailedException = e;
                        throw;
                    }
                }

                file.Refresh();
                if (remoteDoc.LastModificationDate != null)
                {
                    try {
                        file.LastWriteTimeUtc = (DateTime)remoteDoc.LastModificationDate;
                    } catch (IOException e) {
                        Logger.Debug("Cannot set last modification date", e);
                    }
                }

                MappedObject mappedObject = new MappedObject(
                    file.Name,
                    remoteDoc.Id,
                    MappedObjectType.File,
                    remoteDoc.Parents[0].Id,
                    remoteDoc.ChangeToken,
                    remoteDoc.ContentStreamLength ?? 0)
                {
                    Guid = guid,
                    LastLocalWriteTimeUtc  = file.LastWriteTimeUtc,
                    LastRemoteWriteTimeUtc = remoteDoc.LastModificationDate,
                    LastChecksum           = hash,
                    ChecksumAlgorithmName  = "SHA-1"
                };
                this.Storage.SaveMappedObject(mappedObject);
                OperationsLogger.Info(string.Format("New local file {0} created and mapped to remote file {1}", file.FullName, remoteId.Id));
                transmission.Status = TransmissionStatus.FINISHED;
            }
        }
Beispiel #54
0
        protected static void UpdateGameSideContent(IGraphNode gameSideNode, object value, ContentChangeType changeType, Index index)
        {
            switch (changeType)
            {
            case ContentChangeType.ValueChange:
                ((IMemberNode)gameSideNode).Update(value);
                break;

            case ContentChangeType.CollectionUpdate:
                ((IObjectNode)gameSideNode).Update(value, index);
                break;

            case ContentChangeType.CollectionAdd:
                ((IObjectNode)gameSideNode).Add(value, index);
                break;

            case ContentChangeType.CollectionRemove:
                var item = gameSideNode.Retrieve(index);
                ((IObjectNode)gameSideNode).Remove(item, index);
                break;

            default:
                throw new ArgumentOutOfRangeException();
            }
        }
Beispiel #55
0
 /// <summary>
 /// Initializes a new instance of the <see cref="GraphContentChangeEventArgs"/> class.
 /// </summary>
 /// <param name="content">The content that has changed.</param>
 /// <param name="index">The index in the content where the change occurred, if applicable. <c>null</c> otherwise.</param>
 /// <param name="changeType">The type of change that occurred.</param>
 /// <param name="oldValue">The old value of the content.</param>
 /// <param name="newValue">The new value of the content.</param>
 /// <param name="path">The path to the node of content that has been modified.</param>
 public GraphContentChangeEventArgs(IContent content, object index, ContentChangeType changeType, object oldValue, object newValue, GraphNodePath path)
     : base(content, index, changeType, oldValue, newValue)
 {
     Path = path;
 }
        /// <summary>
        /// Solve the specified situation by using the storage, localFile and remoteId.
        /// Uploads the file content if content has been changed. Otherwise simply saves the
        /// last modification date.
        /// </summary>
        /// <param name="localFileSystemInfo">Local filesystem info instance.</param>
        /// <param name="remoteId">Remote identifier or object.</param>
        /// <param name="localContent">Hint if the local content has been changed.</param>
        /// <param name="remoteContent">Information if the remote content has been changed.</param>
        public override void Solve(
            IFileSystemInfo localFileSystemInfo,
            IObjectId remoteId,
            ContentChangeType localContent  = ContentChangeType.NONE,
            ContentChangeType remoteContent = ContentChangeType.NONE)
        {
            if (!localFileSystemInfo.Exists)
            {
                throw new ArgumentException("Given local path does not exists: " + localFileSystemInfo.FullName);
            }

            // Match local changes to remote changes and updated them remotely
            IMappedObject mappedObject = null;

            try {
                Guid?guid = localFileSystemInfo.Uuid;
                if (guid != null)
                {
                    mappedObject = this.Storage.GetObjectByGuid((Guid)guid);
                }
            } catch (Exception) {
            }

            if (mappedObject == null)
            {
                mappedObject = this.Storage.GetObjectByLocalPath(localFileSystemInfo);
            }

            if (mappedObject == null)
            {
                throw new ArgumentException(string.Format("Could not find db entry for {0} => invoke crawl sync", localFileSystemInfo.FullName));
            }

            if (mappedObject.LastChangeToken != (remoteId as ICmisObjectProperties).ChangeToken)
            {
                throw new ArgumentException(string.Format("remote {1} {0} has also been changed since last sync => invoke crawl sync", remoteId.Id, remoteId is IDocument ? "document" : "folder"));
            }

            IFileInfo localFile = localFileSystemInfo as IFileInfo;

            if (localFile != null && localFile.IsContentChangedTo(mappedObject, scanOnlyIfModificationDateDiffers: true))
            {
                Logger.Debug(string.Format("\"{0}\" is different from {1}", localFile.FullName, mappedObject.ToString()));
                OperationsLogger.Debug(string.Format("Local file \"{0}\" has been changed", localFile.FullName));
                var doc = remoteId as IDocument;
                try {
                    mappedObject.LastChecksum = AbstractEnhancedSolver.UploadFile(localFile, doc, this.transmissionManager);
                } catch (Exception ex) {
                    if (ex.InnerException is CmisPermissionDeniedException)
                    {
                        OperationsLogger.Warn(string.Format("Local changed file \"{0}\" has not been uploaded: PermissionDenied", localFile.FullName));
                        return;
                    }
                    else if (ex.InnerException is CmisStorageException)
                    {
                        OperationsLogger.Warn(string.Format("Local changed file \"{0}\" has not been uploaded: StorageException", localFile.FullName), ex);
                        return;
                    }

                    throw;
                }

                mappedObject.LastRemoteWriteTimeUtc = doc.LastModificationDate;
                mappedObject.LastLocalWriteTimeUtc  = localFile.LastWriteTimeUtc;
                mappedObject.LastContentSize        = localFile.Length;

                OperationsLogger.Info(string.Format("Local changed file \"{0}\" has been uploaded", localFile.FullName));
            }

            if (this.ServerCanModifyDateTimes)
            {
                try {
                    if (remoteId is IDocument)
                    {
                        var doc = remoteId as IDocument;
                        doc.UpdateLastWriteTimeUtc(localFileSystemInfo.LastWriteTimeUtc);
                        mappedObject.LastRemoteWriteTimeUtc = doc.LastModificationDate ?? localFileSystemInfo.LastWriteTimeUtc;
                    }
                    else if (remoteId is IFolder)
                    {
                        var folder = remoteId as IFolder;
                        folder.UpdateLastWriteTimeUtc(localFileSystemInfo.LastWriteTimeUtc);
                        mappedObject.LastRemoteWriteTimeUtc = folder.LastModificationDate ?? localFileSystemInfo.LastWriteTimeUtc;
                    }
                } catch (CmisPermissionDeniedException) {
                    Logger.Debug(string.Format("Locally changed modification date \"{0}\"is not uploaded to the server: PermissionDenied", localFileSystemInfo.LastWriteTimeUtc));
                }
            }

            mappedObject.LastChangeToken       = (remoteId as ICmisObjectProperties).ChangeToken;
            mappedObject.LastLocalWriteTimeUtc = localFileSystemInfo.LastWriteTimeUtc;
            this.Storage.SaveMappedObject(mappedObject);
        }
Beispiel #57
0
        public void ResetOverride(Index index, object overriddenValue, ContentChangeType changeType)
        {
            if (BaseContent == null)
                return;

            if (changeType == ContentChangeType.ValueChange)
            {
                // Make sure that what we're trying to reset is actually overridden.
                if ((index != Index.Empty && !IsItemOverridden(index)) || (index == Index.Empty && !IsContentOverridden()))
                    return;
            }

            object baseValue;
            object clonedValue;
            ResettingOverride = true;
            switch (changeType)
            {
                case ContentChangeType.ValueChange:
                    baseValue = RetrieveBaseContent(index);
                    clonedValue = Cloner(baseValue);
                    Content.Update(clonedValue, index);
                    break;
                case ContentChangeType.CollectionRemove:
                    baseValue = RetrieveBaseContent(index);
                    clonedValue = Cloner(baseValue);
                    Content.Add(clonedValue, index);
                    break;
                case ContentChangeType.CollectionAdd:
                    var value = Content.Retrieve(index);
                    Content.Remove(value, index);
                    break;
            }
            ResettingOverride = false;
        }
 // TODO: this method is should be called in every scenario of ReconcileWithBase, it is not the case yet.
 protected virtual bool CanUpdate(IAssetNode node, ContentChangeType changeType, Index index, object value)
 {
     return(true);
 }