public override void Process()
        {
            Remoting.Get rem;

            TriggerOnActionChanged(EngineActionType.GettingVersion, true);

            try
            {
                rem = new Remoting.Get(_db, _id.ToString(), _sendTimeout, _receiveTimeout,
                                       _sendBufferSize, _receiveBufferSize);
            }
            catch (Exception e)
            {
                Logger.Storage.Error("An exception occurred while instantiating the Transactions.Tasks.Remoting.Get object.", e);
                throw;
            }

            rem.OnComplete += delegate(Remoting.Base sender, ICommandReply reply)
            {
                JObject             jobj;
                Transitions.Version txVersion = new Transitions.Version();
                Version   = txVersion.Transition(((Remoting.Get)sender).Document, out jobj);
                Remainder = jobj;
                TriggerOnComplete(reply);
            };
            rem.OnError += delegate(Remoting.Base sender, string message, Exception exception)
            {
                TriggerOnError(message, exception);
            };
            rem.OnProgress += delegate(Remoting.Base sender, OpenDMS.Networking.Protocols.Tcp.DirectionType direction, int packetSize, decimal sendPercentComplete, decimal receivePercentComplete)
            {
                TriggerOnProgress(direction, packetSize, sendPercentComplete, receivePercentComplete);
            };
            rem.OnTimeout += delegate(Remoting.Base sender)
            {
                TriggerOnTimeout();
            };

            rem.Process();
        }
        public override void Process()
        {
            Remoting.Get rem;

            TriggerOnActionChanged(EngineActionType.GettingVersion, true);

            try
            {
                rem = new Remoting.Get(_db, _id.ToString(), _sendTimeout, _receiveTimeout,
                    _sendBufferSize, _receiveBufferSize);
            }
            catch (Exception e)
            {
                Logger.Storage.Error("An exception occurred while instantiating the Transactions.Tasks.Remoting.Get object.", e);
                throw;
            }

            rem.OnComplete += delegate(Remoting.Base sender, ICommandReply reply)
            {
                JObject jobj;
                Transitions.Version txVersion = new Transitions.Version();
                Version = txVersion.Transition(((Remoting.Get)sender).Document, out jobj);
                Remainder = jobj;
                TriggerOnComplete(reply);
            };
            rem.OnError += delegate(Remoting.Base sender, string message, Exception exception)
            {
                TriggerOnError(message, exception);
            };
            rem.OnProgress += delegate(Remoting.Base sender, OpenDMS.Networking.Protocols.Tcp.DirectionType direction, int packetSize, decimal sendPercentComplete, decimal receivePercentComplete)
            {
                TriggerOnProgress(direction, packetSize, sendPercentComplete, receivePercentComplete);
            };
            rem.OnTimeout += delegate(Remoting.Base sender)
            {
                TriggerOnTimeout();
            };

            rem.Process();
        }
        public override void TaskComplete(Tasks.Base sender, ICommandReply reply)
        {
            Type t = sender.GetType();

            if (t == typeof(Tasks.DownloadResource))
            {
                Tasks.DownloadResource task = (Tasks.DownloadResource)sender;
                _resource = task.Resource;
                _resourceRemainder = task.Remainder;
                RunTaskProcess(new Tasks.CheckResourcePermissions(_db, _resource, _requestingPartyType,
                    _session, Security.Authorization.ResourcePermissionType.Modify, _sendTimeout, _receiveTimeout,
                    _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.CheckResourcePermissions))
            {
                Tasks.CheckResourcePermissions task = (Tasks.CheckResourcePermissions)sender;
                if (!task.IsAuthorized)
                {
                    TriggerOnAuthorizationDenied(task);
                    return;
                }
                RunTaskProcess(new Tasks.MarkResourceForCheckout(_resource, _session.User.Username, _sendTimeout, _receiveTimeout,
                    _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.MarkResourceForCheckout))
            {
                Tasks.MarkResourceForCheckout task = (Tasks.MarkResourceForCheckout)sender;
                _resource = task.Resource;

                List<Exception> errors;
                List<Model.Document> docs = new List<Model.Document>();
                Transitions.Version txVersion = new Transitions.Version();
                Transitions.Resource txResource = new Transitions.Resource();

                docs.Add(txResource.Transition(_resource, out errors));
                if (errors != null)
                {
                    TriggerOnError(null, errors[0].Message, errors[0]);
                    return;
                }
                docs[0].CombineWith(_resourceRemainder);
                docs.Add(txVersion.Transition(_version, out errors));
                if (errors != null)
                {
                    TriggerOnError(null, errors[0].Message, errors[0]);
                    return;
                }

                RunTaskProcess(new Tasks.MakeBulkDocument(docs, _sendTimeout, _receiveTimeout,
                    _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.MakeBulkDocument))
            {
                Tasks.MakeBulkDocument task = (Tasks.MakeBulkDocument)sender;
                RunTaskProcess(new Tasks.UploadBulkDocuments(_db, task.BulkDocument, _sendTimeout, _receiveTimeout,
                    _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.UploadBulkDocuments))
            {
                Tasks.UploadBulkDocuments task = (Tasks.UploadBulkDocuments)sender;

                Commands.PostBulkDocumentsReply.Entry entry = task.FindEntryById(_version.VersionId.ToString());

                if (entry == null)
                {
                    TriggerOnError(task, "Failed to locate " + _version.VersionId.ToString() + " in the " +
                        "bulk document post results.", null);
                    return;
                }

                // This is needed so that couchdb can apply the content to the correct revision.
                _version.UpdateRevision(entry.Rev);

                // If no content -> return
                if (_version.Content == null)
                {
                    Resource = _resource;
                    Version = _version;
                    TriggerOnComplete(reply, new Tuple<Data.Resource, Data.Version>(_resource, _version));
                    return;
                }

                // Upload Data.Content from Data.Version
                RunTaskProcess(new Tasks.UploadContent(_db, _version, _sendTimeout, _receiveTimeout,
                    _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.UploadContent))
            {
                Resource = _resource;
                Version = _version;
                TriggerOnComplete(reply, new Tuple<Data.Resource, Data.Version>(_resource, _version));
            }
            else
            {
                TriggerOnError(sender, reply.ToString(), null);
            }
        }
Example #4
0
        public override void Process()
        {
            Commands.PutAttachment cmd;            
            List<Exception> errors;
            OpenDMS.IO.FileStream stream;

            Transitions.Version txVersion = new Transitions.Version();
            Model.Document doc = txVersion.Transition(_version, out errors);

            if (errors != null)
            {
                TriggerOnError(errors[0].Message, errors[0]);
                return;
            }
                
            if (doc.Attachments == null || doc.Attachments.Count == 0)
            {
                TriggerOnError("No content to upload.", null);
                return;
            }
            else if(doc.Attachments.Count > 1)
            {
                TriggerOnError("To many content elements found, only one is expected.", null);
                return;
            }

            Dictionary<string, Model.Attachment>.Enumerator en = doc.Attachments.GetEnumerator();
            
            // Due to the above checks, we know there is 1 and only 1 entry
            en.MoveNext();
            stream = GetStream();

            if (stream == null)
            {
                TriggerOnError("Could not access a content stream.", null);
                return;
            }


            try
            {
                cmd = new Commands.PutAttachment(_db, doc, en.Current.Key, en.Current.Value, stream);
            }
            catch (Exception e)
            {
                Logger.Storage.Error("An exception occurred while creating the PutDocument command.", e);
                throw;
            }

            cmd.OnComplete += delegate(Commands.Base sender, Http.Client client, Http.HttpConnection connection, Commands.ReplyBase reply)
            {
                stream.Close();
                stream.Dispose();
                TriggerOnComplete(reply);
            };
            cmd.OnError += delegate(Commands.Base sender, Http.Client client, string message, Exception exception)
            {
                TriggerOnError(message, exception);
                stream.Close();
                stream.Dispose();
            };
            cmd.OnProgress += delegate(Commands.Base sender, Http.Client client, Http.HttpConnection connection, Tcp.DirectionType direction, int packetSize, decimal sendPercentComplete, decimal receivePercentComplete)
            {
                TriggerOnProgress(direction, packetSize, sendPercentComplete, receivePercentComplete);
            };
            cmd.OnTimeout += delegate(Commands.Base sender, Http.Client client, Http.HttpConnection connection)
            {
                TriggerOnTimeout();
            };

            cmd.Execute(_sendTimeout, _receiveTimeout, _sendBufferSize, _receiveBufferSize);
        }
        public override void TaskComplete(Tasks.Base sender, ICommandReply reply)
        {
            Type t = sender.GetType();

            if (t == typeof(Tasks.DownloadResource))
            {
                Tasks.DownloadResource task = (Tasks.DownloadResource)sender;
                _resource          = task.Resource;
                _resourceRemainder = task.Remainder;
                RunTaskProcess(new Tasks.CheckResourcePermissions(_db, _resource, _requestingPartyType,
                                                                  _session, Security.Authorization.ResourcePermissionType.Modify, _sendTimeout, _receiveTimeout,
                                                                  _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.CheckResourcePermissions))
            {
                Tasks.CheckResourcePermissions task = (Tasks.CheckResourcePermissions)sender;
                if (!task.IsAuthorized)
                {
                    TriggerOnAuthorizationDenied(task);
                    return;
                }
                RunTaskProcess(new Tasks.MarkResourceForCheckout(_resource, _session.User.Username, _sendTimeout, _receiveTimeout,
                                                                 _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.MarkResourceForCheckout))
            {
                Tasks.MarkResourceForCheckout task = (Tasks.MarkResourceForCheckout)sender;
                _resource = task.Resource;

                List <Exception>      errors;
                List <Model.Document> docs       = new List <Model.Document>();
                Transitions.Version   txVersion  = new Transitions.Version();
                Transitions.Resource  txResource = new Transitions.Resource();

                docs.Add(txResource.Transition(_resource, out errors));
                if (errors != null)
                {
                    TriggerOnError(null, errors[0].Message, errors[0]);
                    return;
                }
                docs[0].CombineWith(_resourceRemainder);
                docs.Add(txVersion.Transition(_version, out errors));
                if (errors != null)
                {
                    TriggerOnError(null, errors[0].Message, errors[0]);
                    return;
                }

                RunTaskProcess(new Tasks.MakeBulkDocument(docs, _sendTimeout, _receiveTimeout,
                                                          _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.MakeBulkDocument))
            {
                Tasks.MakeBulkDocument task = (Tasks.MakeBulkDocument)sender;
                RunTaskProcess(new Tasks.UploadBulkDocuments(_db, task.BulkDocument, _sendTimeout, _receiveTimeout,
                                                             _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.UploadBulkDocuments))
            {
                Tasks.UploadBulkDocuments task = (Tasks.UploadBulkDocuments)sender;

                Commands.PostBulkDocumentsReply.Entry entry = task.FindEntryById(_version.VersionId.ToString());

                if (entry == null)
                {
                    TriggerOnError(task, "Failed to locate " + _version.VersionId.ToString() + " in the " +
                                   "bulk document post results.", null);
                    return;
                }

                // This is needed so that couchdb can apply the content to the correct revision.
                _version.UpdateRevision(entry.Rev);

                // If no content -> return
                if (_version.Content == null)
                {
                    Resource = _resource;
                    Version  = _version;
                    TriggerOnComplete(reply, new Tuple <Data.Resource, Data.Version>(_resource, _version));
                    return;
                }

                // Upload Data.Content from Data.Version
                RunTaskProcess(new Tasks.UploadContent(_db, _version, _sendTimeout, _receiveTimeout,
                                                       _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.UploadContent))
            {
                Resource = _resource;
                Version  = _version;
                TriggerOnComplete(reply, new Tuple <Data.Resource, Data.Version>(_resource, _version));
            }
            else
            {
                TriggerOnError(sender, reply.ToString(), null);
            }
        }
        public override void TaskComplete(Tasks.Base sender, ICommandReply reply)
        {
            Type t = sender.GetType();

            if (t == typeof(Tasks.DownloadResource))
            {
                Tasks.DownloadResource task = (Tasks.DownloadResource)sender;
                _resource  = task.Resource;
                _remainder = task.Remainder;
                RunTaskProcess(new Tasks.CheckResourcePermissions(_db, _resource, _requestingPartyType,
                                                                  _session, Security.Authorization.ResourcePermissionType.Delete,
                                                                  _sendTimeout, _receiveTimeout, _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.CheckResourcePermissions))
            {
                Tasks.CheckResourcePermissions task = (Tasks.CheckResourcePermissions)sender;
                if (!task.IsAuthorized)
                {
                    TriggerOnAuthorizationDenied(task);
                    return;
                }

                // First, we load up revisions
                for (int i = 0; i < _resource.VersionIds.Count; i++)
                {
                    _versions.Add(_resource.VersionIds[i], new Data.Version(_resource.VersionIds[i]));
                }

                // Now our _revisions holds indexes for all version ids
                // Dispatch all our heads to get the revisions
                // *note* do not combine these loops - we want the full dictionary before starting
                for (int i = 0; i < _resource.VersionIds.Count; i++)
                {
                    RunTaskProcess(new Tasks.HeadVersion(_db, _resource.VersionIds[i], _sendTimeout,
                                                         _receiveTimeout, _sendBufferSize, _receiveBufferSize));
                }
            }
            else if (t == typeof(Tasks.HeadVersion))
            {
                Tasks.HeadVersion task = (Tasks.HeadVersion)sender;

                if (!_versions.ContainsKey(task.VersionId))
                {
                    TriggerOnError(task, "The id '" + task.VersionId.ToString() + "' could not be found.", new KeyNotFoundException());
                    return;
                }

                lock (_versions)
                {
                    _receivedCount++;
                    _versions[task.VersionId].UpdateRevision(task.Revision);
                    if (_versions.Count == _receivedCount)
                    {
                        List <Exception>      errors;
                        List <Model.Document> docs       = new List <Model.Document>();
                        Transitions.Resource  txResource = new Transitions.Resource();
                        Model.Document        doc        = txResource.Transition(_resource, out errors);

                        if (errors != null)
                        {
                            TriggerOnError(null, errors[0].Message, errors[0]);
                            return;
                        }

                        // Pointless, we are deleting it
                        //doc.CombineWith(_remainder);
                        doc.Add("_deleted", true);
                        docs.Add(doc);

                        Dictionary <Data.VersionId, Data.Version> .Enumerator en = _versions.GetEnumerator();

                        while (en.MoveNext())
                        {
                            Transitions.Version txVersion = new Transitions.Version();
                            Model.Document      doc2      = txVersion.Transition(en.Current.Value, out errors);
                            if (errors != null)
                            {
                                TriggerOnError(null, errors[0].Message, errors[0]);
                                return;
                            }
                            doc2.Add("_deleted", true);
                            docs.Add(doc2);
                        }

                        RunTaskProcess(new Tasks.MakeBulkDocument(docs, _sendTimeout, _receiveTimeout,
                                                                  _sendBufferSize, _receiveBufferSize));
                    }
                    else
                    {
                        TriggerOnProgress(task, Networking.Protocols.Tcp.DirectionType.Download, -1, -1,
                                          ((decimal)((decimal)_receivedCount / (decimal)_versions.Count)));
                    }
                }
            }
            else if (t == typeof(Tasks.MakeBulkDocument))
            {
                Tasks.MakeBulkDocument task = (Tasks.MakeBulkDocument)sender;
                RunTaskProcess(new Tasks.UploadBulkDocuments(_db, task.BulkDocument, _sendTimeout,
                                                             _receiveTimeout, _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.UploadBulkDocuments))
            {
                Tasks.UploadBulkDocuments task = (Tasks.UploadBulkDocuments)sender;
                TriggerOnComplete(reply, task.Results);
            }
            else
            {
                TriggerOnError(sender, reply.ToString(), null);
            }
        }
        public override void TaskComplete(Tasks.Base sender, ICommandReply reply)
        {
            Type t = sender.GetType();

            if (t == typeof(Tasks.DownloadGlobalPermissions))
            {
                Tasks.DownloadGlobalPermissions task = (Tasks.DownloadGlobalPermissions)sender;
                _gur = task.GlobalUsageRights;
                RunTaskProcess(new Tasks.CheckGlobalPermissions(_db, _gur, _requestingPartyType,
                    _session, Security.Authorization.GlobalPermissionType.CreateResource, _sendTimeout, _receiveTimeout,
                    _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.CheckGlobalPermissions))
            {
                Tasks.CheckGlobalPermissions task = (Tasks.CheckGlobalPermissions)sender;
                if (!task.IsAuthorized)
                {
                    TriggerOnAuthorizationDenied(task);
                    return;
                }
                RunTaskProcess(new Tasks.DownloadResourceUsageRightsTemplate(_db, _sendTimeout, _receiveTimeout,
                    _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.DownloadResourceUsageRightsTemplate))
            {
                string username = _session.User.Username;
                DateTime creation = DateTime.Now;
                List<Exception> errors;
                List<Model.Document> docs = new List<Model.Document>();

                Tasks.DownloadResourceUsageRightsTemplate task = (Tasks.DownloadResourceUsageRightsTemplate)sender;
                
                // Create the Resource and Version objects
                List<Data.VersionId> versions = new List<Data.VersionId>();

                Data.ResourceId resourceId = Data.ResourceId.Create();

                _version = new Data.Version(new Data.VersionId(resourceId), _args.VersionArgs.Metadata, _args.VersionArgs.Content)
                {
                    Md5 = _args.VersionArgs.Md5,
                    Extension = _args.VersionArgs.Extension,
                    Created = creation,
                    Creator = username,
                    Modified = creation,
                    Modifier = username
                };

                versions.Add(_version.VersionId);

                _resource = new Data.Resource(resourceId, null, versions, _version.VersionId,
                    _args.Metadata, task.Value.UsageRights)
                {
                    Tags = _args.Tags,
                    Created = creation,
                    Creator = username,
                    Modified = creation,
                    Modifier = username,
                    CheckedOutAt = creation,
                    CheckedOutTo = username,
                    LastCommit = creation,
                    LastCommitter = username,
                    Title = _args.Title
                };
                
                // Transition to json objects
                
                Transitions.Resource txResource = new Transitions.Resource();
                docs.Add(txResource.Transition(_resource, out errors));
                if (errors != null)
                {
                    TriggerOnError(null, errors[0].Message, errors[0]);
                    return;
                }
                Transitions.Version txVersion = new Transitions.Version();
                docs.Add(txVersion.Transition(_version, out errors));
                if (errors != null)
                {
                    TriggerOnError(null, errors[0].Message, errors[0]);
                    return;
                }

                RunTaskProcess(new Tasks.MakeBulkDocument(docs, _sendTimeout, _receiveTimeout,
                    _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.MakeBulkDocument))
            {
                Tasks.MakeBulkDocument task = (Tasks.MakeBulkDocument)sender;
                RunTaskProcess(new Tasks.UploadBulkDocuments(_db, task.BulkDocument, _sendTimeout, _receiveTimeout,
                    _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.UploadBulkDocuments))
            {
                Tasks.UploadBulkDocuments task = (Tasks.UploadBulkDocuments)sender;

                Commands.PostBulkDocumentsReply.Entry entry = task.FindEntryById(_version.VersionId.ToString());

                if (entry == null)
                {
                    TriggerOnError(task, "Failed to locate " + _version.VersionId.ToString() + " in the " +
                        "bulk document post results.", null);
                    return;
                }

                // This is needed so that couchdb can apply the content to the correct revision.
                _version.UpdateRevision(entry.Rev);

                // Upload Data.Content from Data.Version
                RunTaskProcess(new Tasks.UploadContent(_db, _version, _sendTimeout, _receiveTimeout,
                    _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.UploadContent))
            {
                TriggerOnComplete(reply, new Tuple<Data.Resource, Data.Version>(_resource, _version));
            }
            else
            {
                TriggerOnError(sender, reply.ToString(), null);
            }
        }
        public override void TaskComplete(Tasks.Base sender, ICommandReply reply)
        {
            Type t = sender.GetType();

            if (t == typeof(Tasks.DownloadResource))
            {
                Tasks.DownloadResource task = (Tasks.DownloadResource)sender;
                _resource = task.Resource;
                _remainder = task.Remainder;
                RunTaskProcess(new Tasks.CheckResourcePermissions(_db, _resource, _requestingPartyType,
                    _session, Security.Authorization.ResourcePermissionType.Delete,
                    _sendTimeout, _receiveTimeout, _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.CheckResourcePermissions))
            {
                Tasks.CheckResourcePermissions task = (Tasks.CheckResourcePermissions)sender;
                if (!task.IsAuthorized)
                {
                    TriggerOnAuthorizationDenied(task);
                    return;
                }

                // First, we load up revisions
                for (int i = 0; i < _resource.VersionIds.Count; i++)
                {
                    _versions.Add(_resource.VersionIds[i], new Data.Version(_resource.VersionIds[i]));
                }

                // Now our _revisions holds indexes for all version ids
                // Dispatch all our heads to get the revisions
                // *note* do not combine these loops - we want the full dictionary before starting
                for (int i = 0; i < _resource.VersionIds.Count; i++)
                {
                    RunTaskProcess(new Tasks.HeadVersion(_db, _resource.VersionIds[i], _sendTimeout,
                        _receiveTimeout, _sendBufferSize, _receiveBufferSize));
                }
            }
            else if (t == typeof(Tasks.HeadVersion))
            {
                Tasks.HeadVersion task = (Tasks.HeadVersion)sender;

                if (!_versions.ContainsKey(task.VersionId))
                {
                    TriggerOnError(task, "The id '" + task.VersionId.ToString() + "' could not be found.", new KeyNotFoundException());
                    return;
                }

                lock (_versions)
                {
                    _receivedCount++;
                    _versions[task.VersionId].UpdateRevision(task.Revision);
                    if (_versions.Count == _receivedCount)
                    {
                        List<Exception> errors;
                        List<Model.Document> docs = new List<Model.Document>();
                        Transitions.Resource txResource = new Transitions.Resource();
                        Model.Document doc = txResource.Transition(_resource, out errors);

                        if (errors != null)
                        {
                            TriggerOnError(null, errors[0].Message, errors[0]);
                            return;
                        }

                        // Pointless, we are deleting it
                        //doc.CombineWith(_remainder);
                        doc.Add("_deleted", true);
                        docs.Add(doc);

                        Dictionary<Data.VersionId, Data.Version>.Enumerator en = _versions.GetEnumerator();

                        while (en.MoveNext())
                        {
                            Transitions.Version txVersion = new Transitions.Version();
                            Model.Document doc2 = txVersion.Transition(en.Current.Value, out errors);
                            if (errors != null)
                            {
                                TriggerOnError(null, errors[0].Message, errors[0]);
                                return;
                            }
                            doc2.Add("_deleted", true);
                            docs.Add(doc2);
                        }

                        RunTaskProcess(new Tasks.MakeBulkDocument(docs, _sendTimeout, _receiveTimeout,
                            _sendBufferSize, _receiveBufferSize));
                    }
                    else
                    {
                        TriggerOnProgress(task, Networking.Protocols.Tcp.DirectionType.Download, -1, -1,
                            ((decimal)((decimal)_receivedCount / (decimal)_versions.Count)));
                    }
                }
            }
            else if (t == typeof(Tasks.MakeBulkDocument))
            {
                Tasks.MakeBulkDocument task = (Tasks.MakeBulkDocument)sender;
                RunTaskProcess(new Tasks.UploadBulkDocuments(_db, task.BulkDocument, _sendTimeout,
                    _receiveTimeout, _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.UploadBulkDocuments))
            {
                Tasks.UploadBulkDocuments task = (Tasks.UploadBulkDocuments)sender;
                TriggerOnComplete(reply, task.Results);
            }
            else
            {
                TriggerOnError(sender, reply.ToString(), null);
            }
        }
        public override void Process()
        {
            Commands.PutAttachment cmd;
            List <Exception>       errors;

            OpenDMS.IO.FileStream stream;

            Transitions.Version txVersion = new Transitions.Version();
            Model.Document      doc       = txVersion.Transition(_version, out errors);

            if (errors != null)
            {
                TriggerOnError(errors[0].Message, errors[0]);
                return;
            }

            if (doc.Attachments == null || doc.Attachments.Count == 0)
            {
                TriggerOnError("No content to upload.", null);
                return;
            }
            else if (doc.Attachments.Count > 1)
            {
                TriggerOnError("To many content elements found, only one is expected.", null);
                return;
            }

            Dictionary <string, Model.Attachment> .Enumerator en = doc.Attachments.GetEnumerator();

            // Due to the above checks, we know there is 1 and only 1 entry
            en.MoveNext();
            stream = GetStream();

            if (stream == null)
            {
                TriggerOnError("Could not access a content stream.", null);
                return;
            }


            try
            {
                cmd = new Commands.PutAttachment(_db, doc, en.Current.Key, en.Current.Value, stream);
            }
            catch (Exception e)
            {
                Logger.Storage.Error("An exception occurred while creating the PutDocument command.", e);
                throw;
            }

            cmd.OnComplete += delegate(Commands.Base sender, Http.Client client, Http.HttpConnection connection, Commands.ReplyBase reply)
            {
                stream.Close();
                stream.Dispose();
                TriggerOnComplete(reply);
            };
            cmd.OnError += delegate(Commands.Base sender, Http.Client client, string message, Exception exception)
            {
                TriggerOnError(message, exception);
                stream.Close();
                stream.Dispose();
            };
            cmd.OnProgress += delegate(Commands.Base sender, Http.Client client, Http.HttpConnection connection, Tcp.DirectionType direction, int packetSize, decimal sendPercentComplete, decimal receivePercentComplete)
            {
                TriggerOnProgress(direction, packetSize, sendPercentComplete, receivePercentComplete);
            };
            cmd.OnTimeout += delegate(Commands.Base sender, Http.Client client, Http.HttpConnection connection)
            {
                TriggerOnTimeout();
            };

            cmd.Execute(_sendTimeout, _receiveTimeout, _sendBufferSize, _receiveBufferSize);
        }
        public override void TaskComplete(Tasks.Base sender, ICommandReply reply)
        {
            /* We encounter a bit of an issue here.  Upon doing some research it is easily resolved
             * by couchdb.  Lets examine.
             * 
             * Issue: We update the resource to the server, connection is lost, we try to delete the
             * versions newer than the target version of the rollback.  This fails.  We now have 
             * zombie versions that will block future recreation of those versions as the IDs will
             * be the same.
             * 
             * Solution: "Updating existing documents requires setting the _rev member to the 
             * revision being updated. To delete a document set the _deleted member to true." 
             * http://wiki.apache.org/couchdb/HTTP_Bulk_Document_API.
             * 
             * Example: 
             * {
             *  "docs": [
             *      {"_id": "0", "_rev": "1-62657917", "_deleted": true},
             *      {"_id": "1", "_rev": "1-2089673485", "integer": 2, "string": "2"},
             *      {"_id": "2", "_rev": "1-2063452834", "integer": 3, "string": "3"}
             *  ]
             * }
             * 
             * Implementation: So, we already have bulk document post support.  We simply need to
             * load the bulkdocument with the resource and the _id and _rev for each version we want
             * to remove.  We will also want to set the _deleted to true.
             */

            // 1) Download Resource
            // 2) Check for VersionControl permission
            // 3) Modify Resource (VersionIds, CurrentVersionId)
            // 4) Make bulk document
            // 5) Upload bulk document
            
            Type t = sender.GetType();

            if (t == typeof(Tasks.DownloadResource))
            {
                Tasks.DownloadResource task = (Tasks.DownloadResource)sender;
                _resource = task.Resource;
                _remainder = task.Remainder;
                RunTaskProcess(new Tasks.CheckResourcePermissions(_db, _resource, _requestingPartyType,
                    _session, Security.Authorization.ResourcePermissionType.VersionControl, 
                    _sendTimeout, _receiveTimeout, _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.CheckResourcePermissions))
            {
                Data.VersionId oldCurrentVersionId;
                Tasks.CheckResourcePermissions task = (Tasks.CheckResourcePermissions)sender;

                if (!task.IsAuthorized)
                {
                    TriggerOnAuthorizationDenied(task);
                    return;
                }

                // If version number < rollback -> error
                // Versions: 0,1,2 / rollback: 2 -> 0th version
                if (_resource.CurrentVersionId.VersionNumber < _rollbackDepth)
                {
                    TriggerOnError(null, "Rollback depth out of range.", null);
                    return;
                }
                else if (_rollbackDepth <= 0)
                {
                    TriggerOnError(null, "Rollback depth must be a positive value.", null);
                    return;
                }

                oldCurrentVersionId = _resource.CurrentVersionId;

                _versionsToDelete = new Dictionary<Data.VersionId, Data.Version>();

                long targetVersionNumber = _resource.CurrentVersionId.VersionNumber - _rollbackDepth;
                for(int i=0; i<_resource.VersionIds.Count; i++)
                {
                    if (_resource.VersionIds[i].VersionNumber > targetVersionNumber)
                    {                        
                        Data.VersionId vid = new Data.VersionId(_resource.ResourceId, i);
                        _versionsToDelete.Add(vid, new Data.Version(vid));
                    }
                }
                
                // Removes the versions more recent than the rollback point
                _resource.VersionIds.RemoveRange(_resource.VersionIds.Count - _rollbackDepth,
                    _rollbackDepth);

                _resource.UpdateCurrentVersionBasedOnVersionsList();


                Dictionary<Data.VersionId, Data.Version>.Enumerator en = _versionsToDelete.GetEnumerator();
                
                // Dispatch all our heads to get the revisions
                // *note* do not combine these loops - we want the full list before starting
                while (en.MoveNext())
                {
                    RunTaskProcess(new Tasks.HeadVersion(_db, en.Current.Key, _sendTimeout,
                        _receiveTimeout, _sendBufferSize, _receiveBufferSize));
                }
            }
            else if (t == typeof(Tasks.HeadVersion))
            {
                Tasks.HeadVersion task = (Tasks.HeadVersion)sender;

                if (!_versionsToDelete.ContainsKey(task.VersionId))
                {
                    TriggerOnError(task, "The id '" + task.VersionId.ToString() + "' could not be found.", new KeyNotFoundException());
                    return;
                }

                lock (_versionsToDelete)
                {
                    _receivedCount++;
                    _versionsToDelete[task.VersionId].UpdateRevision(task.Revision);
                    if (_versionsToDelete.Count == _receivedCount)
                    {
                        // Inside here we have a collection "docs" that contains the new resource
                        // which has the new "current" version and has all the more recent
                        // versions removed.  We also have inside "docs" deletion markers for all
                        // the more recent versions.

                        List<Exception> errors;
                        List<Model.Document> docs = new List<Model.Document>();
                        Transitions.Resource txResource = new Transitions.Resource();
                        Model.Document doc = txResource.Transition(_resource, out errors);

                        if (errors != null)
                        {
                            TriggerOnError(null, errors[0].Message, errors[0]);
                            return;
                        }

                        doc.CombineWith(_remainder);
                        docs.Add(doc);
                        
                        Dictionary<Data.VersionId, Data.Version>.Enumerator en = _versionsToDelete.GetEnumerator();
                
                        // Dispatch all our heads to get the revisions
                        // *note* do not combine these loops - we want the full list before starting
                        while (en.MoveNext())
                        {
                            Transitions.Version txVersion = new Transitions.Version();
                            Model.Document doc2 = txVersion.Transition(en.Current.Value, out errors);
                            if (errors != null)
                            {
                                TriggerOnError(null, errors[0].Message, errors[0]);
                                return;
                            }
                            doc2.Add("_deleted", true);
                            docs.Add(doc2);
                        }
                        
                        RunTaskProcess(new Tasks.MakeBulkDocument(docs, _sendTimeout, _receiveTimeout,
                            _sendBufferSize, _receiveBufferSize));
                    }
                }
            }
            else if (t == typeof(Tasks.MakeBulkDocument))
            {
                Tasks.MakeBulkDocument task = (Tasks.MakeBulkDocument)sender;
                RunTaskProcess(new Tasks.UploadBulkDocuments(_db, task.BulkDocument, _sendTimeout,
                    _receiveTimeout, _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.UploadBulkDocuments))
            {
                Tasks.UploadBulkDocuments task = (Tasks.UploadBulkDocuments)sender;
                TriggerOnComplete(reply, task.Results);
            }
            else
            {
                TriggerOnError(sender, reply.ToString(), null);
            }
        }
        public override void TaskComplete(Tasks.Base sender, ICommandReply reply)
        {
            /* We encounter a bit of an issue here.  Upon doing some research it is easily resolved
             * by couchdb.  Lets examine.
             *
             * Issue: We update the resource to the server, connection is lost, we try to delete the
             * versions newer than the target version of the rollback.  This fails.  We now have
             * zombie versions that will block future recreation of those versions as the IDs will
             * be the same.
             *
             * Solution: "Updating existing documents requires setting the _rev member to the
             * revision being updated. To delete a document set the _deleted member to true."
             * http://wiki.apache.org/couchdb/HTTP_Bulk_Document_API.
             *
             * Example:
             * {
             *  "docs": [
             *      {"_id": "0", "_rev": "1-62657917", "_deleted": true},
             *      {"_id": "1", "_rev": "1-2089673485", "integer": 2, "string": "2"},
             *      {"_id": "2", "_rev": "1-2063452834", "integer": 3, "string": "3"}
             *  ]
             * }
             *
             * Implementation: So, we already have bulk document post support.  We simply need to
             * load the bulkdocument with the resource and the _id and _rev for each version we want
             * to remove.  We will also want to set the _deleted to true.
             */

            // 1) Download Resource
            // 2) Check for VersionControl permission
            // 3) Modify Resource (VersionIds, CurrentVersionId)
            // 4) Make bulk document
            // 5) Upload bulk document

            Type t = sender.GetType();

            if (t == typeof(Tasks.DownloadResource))
            {
                Tasks.DownloadResource task = (Tasks.DownloadResource)sender;
                _resource  = task.Resource;
                _remainder = task.Remainder;
                RunTaskProcess(new Tasks.CheckResourcePermissions(_db, _resource, _requestingPartyType,
                                                                  _session, Security.Authorization.ResourcePermissionType.VersionControl,
                                                                  _sendTimeout, _receiveTimeout, _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.CheckResourcePermissions))
            {
                Data.VersionId oldCurrentVersionId;
                Tasks.CheckResourcePermissions task = (Tasks.CheckResourcePermissions)sender;

                if (!task.IsAuthorized)
                {
                    TriggerOnAuthorizationDenied(task);
                    return;
                }

                // If version number < rollback -> error
                // Versions: 0,1,2 / rollback: 2 -> 0th version
                if (_resource.CurrentVersionId.VersionNumber < _rollbackDepth)
                {
                    TriggerOnError(null, "Rollback depth out of range.", null);
                    return;
                }
                else if (_rollbackDepth <= 0)
                {
                    TriggerOnError(null, "Rollback depth must be a positive value.", null);
                    return;
                }

                oldCurrentVersionId = _resource.CurrentVersionId;

                _versionsToDelete = new Dictionary <Data.VersionId, Data.Version>();

                long targetVersionNumber = _resource.CurrentVersionId.VersionNumber - _rollbackDepth;
                for (int i = 0; i < _resource.VersionIds.Count; i++)
                {
                    if (_resource.VersionIds[i].VersionNumber > targetVersionNumber)
                    {
                        Data.VersionId vid = new Data.VersionId(_resource.ResourceId, i);
                        _versionsToDelete.Add(vid, new Data.Version(vid));
                    }
                }

                // Removes the versions more recent than the rollback point
                _resource.VersionIds.RemoveRange(_resource.VersionIds.Count - _rollbackDepth,
                                                 _rollbackDepth);

                _resource.UpdateCurrentVersionBasedOnVersionsList();


                Dictionary <Data.VersionId, Data.Version> .Enumerator en = _versionsToDelete.GetEnumerator();

                // Dispatch all our heads to get the revisions
                // *note* do not combine these loops - we want the full list before starting
                while (en.MoveNext())
                {
                    RunTaskProcess(new Tasks.HeadVersion(_db, en.Current.Key, _sendTimeout,
                                                         _receiveTimeout, _sendBufferSize, _receiveBufferSize));
                }
            }
            else if (t == typeof(Tasks.HeadVersion))
            {
                Tasks.HeadVersion task = (Tasks.HeadVersion)sender;

                if (!_versionsToDelete.ContainsKey(task.VersionId))
                {
                    TriggerOnError(task, "The id '" + task.VersionId.ToString() + "' could not be found.", new KeyNotFoundException());
                    return;
                }

                lock (_versionsToDelete)
                {
                    _receivedCount++;
                    _versionsToDelete[task.VersionId].UpdateRevision(task.Revision);
                    if (_versionsToDelete.Count == _receivedCount)
                    {
                        // Inside here we have a collection "docs" that contains the new resource
                        // which has the new "current" version and has all the more recent
                        // versions removed.  We also have inside "docs" deletion markers for all
                        // the more recent versions.

                        List <Exception>      errors;
                        List <Model.Document> docs       = new List <Model.Document>();
                        Transitions.Resource  txResource = new Transitions.Resource();
                        Model.Document        doc        = txResource.Transition(_resource, out errors);

                        if (errors != null)
                        {
                            TriggerOnError(null, errors[0].Message, errors[0]);
                            return;
                        }

                        doc.CombineWith(_remainder);
                        docs.Add(doc);

                        Dictionary <Data.VersionId, Data.Version> .Enumerator en = _versionsToDelete.GetEnumerator();

                        // Dispatch all our heads to get the revisions
                        // *note* do not combine these loops - we want the full list before starting
                        while (en.MoveNext())
                        {
                            Transitions.Version txVersion = new Transitions.Version();
                            Model.Document      doc2      = txVersion.Transition(en.Current.Value, out errors);
                            if (errors != null)
                            {
                                TriggerOnError(null, errors[0].Message, errors[0]);
                                return;
                            }
                            doc2.Add("_deleted", true);
                            docs.Add(doc2);
                        }

                        RunTaskProcess(new Tasks.MakeBulkDocument(docs, _sendTimeout, _receiveTimeout,
                                                                  _sendBufferSize, _receiveBufferSize));
                    }
                }
            }
            else if (t == typeof(Tasks.MakeBulkDocument))
            {
                Tasks.MakeBulkDocument task = (Tasks.MakeBulkDocument)sender;
                RunTaskProcess(new Tasks.UploadBulkDocuments(_db, task.BulkDocument, _sendTimeout,
                                                             _receiveTimeout, _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.UploadBulkDocuments))
            {
                Tasks.UploadBulkDocuments task = (Tasks.UploadBulkDocuments)sender;
                TriggerOnComplete(reply, task.Results);
            }
            else
            {
                TriggerOnError(sender, reply.ToString(), null);
            }
        }
        public override void TaskComplete(Tasks.Base sender, ICommandReply reply)
        {
            Type t = sender.GetType();

            if (t == typeof(Tasks.DownloadGlobalPermissions))
            {
                Tasks.DownloadGlobalPermissions task = (Tasks.DownloadGlobalPermissions)sender;
                _gur = task.GlobalUsageRights;
                RunTaskProcess(new Tasks.CheckGlobalPermissions(_db, _gur, _requestingPartyType,
                                                                _session, Security.Authorization.GlobalPermissionType.CreateResource, _sendTimeout, _receiveTimeout,
                                                                _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.CheckGlobalPermissions))
            {
                Tasks.CheckGlobalPermissions task = (Tasks.CheckGlobalPermissions)sender;
                if (!task.IsAuthorized)
                {
                    TriggerOnAuthorizationDenied(task);
                    return;
                }
                RunTaskProcess(new Tasks.DownloadResourceUsageRightsTemplate(_db, _sendTimeout, _receiveTimeout,
                                                                             _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.DownloadResourceUsageRightsTemplate))
            {
                string                username = _session.User.Username;
                DateTime              creation = DateTime.Now;
                List <Exception>      errors;
                List <Model.Document> docs = new List <Model.Document>();

                Tasks.DownloadResourceUsageRightsTemplate task = (Tasks.DownloadResourceUsageRightsTemplate)sender;

                // Create the Resource and Version objects
                List <Data.VersionId> versions = new List <Data.VersionId>();

                Data.ResourceId resourceId = Data.ResourceId.Create();

                _version = new Data.Version(new Data.VersionId(resourceId), _args.VersionArgs.Metadata, _args.VersionArgs.Content)
                {
                    Md5       = _args.VersionArgs.Md5,
                    Extension = _args.VersionArgs.Extension,
                    Created   = creation,
                    Creator   = username,
                    Modified  = creation,
                    Modifier  = username
                };

                versions.Add(_version.VersionId);

                _resource = new Data.Resource(resourceId, null, versions, _version.VersionId,
                                              _args.Metadata, task.Value.UsageRights)
                {
                    Tags          = _args.Tags,
                    Created       = creation,
                    Creator       = username,
                    Modified      = creation,
                    Modifier      = username,
                    CheckedOutAt  = creation,
                    CheckedOutTo  = username,
                    LastCommit    = creation,
                    LastCommitter = username,
                    Title         = _args.Title
                };

                // Transition to json objects

                Transitions.Resource txResource = new Transitions.Resource();
                docs.Add(txResource.Transition(_resource, out errors));
                if (errors != null)
                {
                    TriggerOnError(null, errors[0].Message, errors[0]);
                    return;
                }
                Transitions.Version txVersion = new Transitions.Version();
                docs.Add(txVersion.Transition(_version, out errors));
                if (errors != null)
                {
                    TriggerOnError(null, errors[0].Message, errors[0]);
                    return;
                }

                RunTaskProcess(new Tasks.MakeBulkDocument(docs, _sendTimeout, _receiveTimeout,
                                                          _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.MakeBulkDocument))
            {
                Tasks.MakeBulkDocument task = (Tasks.MakeBulkDocument)sender;
                RunTaskProcess(new Tasks.UploadBulkDocuments(_db, task.BulkDocument, _sendTimeout, _receiveTimeout,
                                                             _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.UploadBulkDocuments))
            {
                Tasks.UploadBulkDocuments task = (Tasks.UploadBulkDocuments)sender;

                Commands.PostBulkDocumentsReply.Entry entry = task.FindEntryById(_version.VersionId.ToString());

                if (entry == null)
                {
                    TriggerOnError(task, "Failed to locate " + _version.VersionId.ToString() + " in the " +
                                   "bulk document post results.", null);
                    return;
                }

                // This is needed so that couchdb can apply the content to the correct revision.
                _version.UpdateRevision(entry.Rev);

                // Upload Data.Content from Data.Version
                RunTaskProcess(new Tasks.UploadContent(_db, _version, _sendTimeout, _receiveTimeout,
                                                       _sendBufferSize, _receiveBufferSize));
            }
            else if (t == typeof(Tasks.UploadContent))
            {
                TriggerOnComplete(reply, new Tuple <Data.Resource, Data.Version>(_resource, _version));
            }
            else
            {
                TriggerOnError(sender, reply.ToString(), null);
            }
        }