public HeadVersion(IDatabase db, Data.VersionId versionId,
                    int sendTimeout, int receiveTimeout, int sendBufferSize, int receiveBufferSize)
     : base(sendTimeout, receiveTimeout, sendBufferSize, receiveBufferSize)
 {
     _db        = db;
     _versionId = versionId;
 }
Esempio n. 2
0
 public HeadVersion(IDatabase db, Data.VersionId versionId,
     int sendTimeout, int receiveTimeout, int sendBufferSize, int receiveBufferSize)
     : base(sendTimeout, receiveTimeout, sendBufferSize, receiveBufferSize)
 {
     _db = db;
     _versionId = versionId;
 }
Esempio n. 3
0
 public override void CheckoutVersion(EngineRequest request, Data.VersionId version)
 {
     CheckInitialization();
     Logger.Storage.Debug("Checking out the version '" + version.ToString() + "'");
     EngineMethods.CheckoutVersion act = new EngineMethods.CheckoutVersion(request, version);
     act.Execute();
 }
 public DownloadVersion(IDatabase db, Data.VersionId id,
                        int sendTimeout, int receiveTimeout, int sendBufferSize, int receiveBufferSize)
     : base(sendTimeout, receiveTimeout, sendBufferSize, receiveBufferSize)
 {
     _db = db;
     _id = id;
 }
 public DownloadVersion(IDatabase db, Data.VersionId id,
     int sendTimeout, int receiveTimeout, int sendBufferSize, int receiveBufferSize)
     : base(sendTimeout, receiveTimeout, sendBufferSize, receiveBufferSize)
 {
     _db = db;
     _id = id;
 }
Esempio n. 6
0
 public CheckoutVersion(IDatabase db, Data.VersionId id,
                        Security.RequestingPartyType requestingPartyType, Security.Session session, int sendTimeout,
                        int receiveTimeout, int sendBufferSize, int receiveBufferSize)
     : base(db, sendTimeout, receiveTimeout, sendBufferSize, receiveBufferSize)
 {
     _id = id;
     _requestingPartyType = requestingPartyType;
     _session             = session;
 }
 public CheckoutVersion(IDatabase db, Data.VersionId id,
     Security.RequestingPartyType requestingPartyType, Security.Session session, int sendTimeout,
     int receiveTimeout, int sendBufferSize, int receiveBufferSize)
     : base(db, sendTimeout, receiveTimeout, sendBufferSize, receiveBufferSize)
 {
     _id = id;
     _requestingPartyType = requestingPartyType;
     _session = session;
 }
Esempio n. 8
0
        public Data.Version Transition(Model.Document document, out JObject remainder)
        {
            Data.Version version;
            Data.VersionId id;
            string rev;
            string verifyString;

            if (!VerifyDocumentIntegrity(document, out verifyString))
            {
                Logger.Storage.Error("The document is not properly formatted.  It is missing the property '" + verifyString + "'.");
                throw new FormattingException("The argument document does not have the necessary property '" + verifyString + "'.");
            }

            try
            {
                id = new Data.VersionId(document.Id);
                if (document["_rev"] != null)
                {
                    rev = document.Rev;
                    version = new Data.Version(id, rev);
                    document.Remove("_rev");
                }
                else
                {
                    version = new Data.Version(id);
                }

                document.Remove("_id");
                document.Remove("$type");

                version.Md5 = document["$md5"].Value<string>();
                version.Extension = document["$extension"].Value<string>();
                version.Created = document["$created"].Value<DateTime>();
                version.Creator = document["$creator"].Value<string>();
                version.Modified = document["$modified"].Value<DateTime>();
                version.Modifier = document["$modifier"].Value<string>();

                document.Remove("$md5");
                document.Remove("$extension");
                document.Remove("$created");
                document.Remove("$creator");
                document.Remove("$modified");
                document.Remove("$modifier");
            }
            catch (Exception e)
            {
                Logger.Storage.Error("An exception occurred while attempting to parse the document.", e);
                throw;
            }

            remainder = document;
            return version;
        }
Esempio n. 9
0
        public Data.Version Transition(Model.Document document, out JObject remainder)
        {
            Data.Version   version;
            Data.VersionId id;
            string         rev;
            string         verifyString;

            if (!VerifyDocumentIntegrity(document, out verifyString))
            {
                Logger.Storage.Error("The document is not properly formatted.  It is missing the property '" + verifyString + "'.");
                throw new FormattingException("The argument document does not have the necessary property '" + verifyString + "'.");
            }

            try
            {
                id = new Data.VersionId(document.Id);
                if (document["_rev"] != null)
                {
                    rev     = document.Rev;
                    version = new Data.Version(id, rev);
                    document.Remove("_rev");
                }
                else
                {
                    version = new Data.Version(id);
                }

                document.Remove("_id");
                document.Remove("$type");

                version.Md5       = document["$md5"].Value <string>();
                version.Extension = document["$extension"].Value <string>();
                version.Created   = document["$created"].Value <DateTime>();
                version.Creator   = document["$creator"].Value <string>();
                version.Modified  = document["$modified"].Value <DateTime>();
                version.Modifier  = document["$modifier"].Value <string>();

                document.Remove("$md5");
                document.Remove("$extension");
                document.Remove("$created");
                document.Remove("$creator");
                document.Remove("$modified");
                document.Remove("$modifier");
            }
            catch (Exception e)
            {
                Logger.Storage.Error("An exception occurred while attempting to parse the document.", e);
                throw;
            }

            remainder = document;
            return(version);
        }
Esempio n. 10
0
 public CheckoutVersion(EngineRequest request, Data.VersionId versionId)
     : base(request)
 {
     _versionId = versionId;
 }
Esempio n. 11
0
        public Data.Resource Transition(Model.Document document, out JObject remainder)
        {
            Data.Resource   resource;
            Data.ResourceId id;
            string          rev = null;

            Data.VersionId             currentVersionId;
            List <Data.VersionId>      versionIds  = null;
            List <Security.UsageRight> usageRights = null;

            Security.UsageRight  usageRight = null;
            JObject              jobj       = null;
            JProperty            prop       = null;
            IEnumerator <JToken> en;
            string verifyString;
            JArray jarray = new JArray();

            if (!VerifyDocumentIntegrity(document, out verifyString))
            {
                Logger.Storage.Error("The document is not properly formatted.  It is missing the property '" + verifyString + "'.");
                throw new FormattingException("The argument document does not have the necessary property '" + verifyString + "'.");
            }

            // I ran into a problem here where I was removing the properties from the document and what was left was the remainder.
            // However, this causes an issue when using the transition to make a resource for permissions checking as the
            // object returned to implementing software is the document.  Thus, the implementing software only received those properties
            // not removed... which obviously excludes the most important properties.  To remedy this issue, I created a constructor for
            // Model.Document(Document).  This constructor will format the argument document to a string and then create a JObject from
            // that string.  C# will deep copy the string (not byref) so as to guarantee an independent object.
            remainder = new Model.Document(document);

            try
            {
                id = new Data.ResourceId(document.Id);
                if (document["_rev"] != null)
                {
                    rev = document.Rev;
                    remainder.Remove("_rev");
                }

                remainder.Remove("_id");
                remainder.Remove("$type");

                currentVersionId = new Data.VersionId(document["$currentversionid"].Value <string>());
                remainder.Remove("$currentversionid");

                versionIds = new List <Data.VersionId>();
                jarray     = (JArray)document["$versionids"];

                for (int i = 0; i < jarray.Count; i++)
                {
                    versionIds.Add(new Data.VersionId(jarray[i].Value <string>()));
                }

                remainder.Remove("$versionids");


                usageRights = new List <Security.UsageRight>();
                jarray      = (JArray)document["$usagerights"];

                for (int i = 0; i < jarray.Count; i++)
                {
                    jobj = (JObject)jarray[i];
                    en   = jobj.Children().GetEnumerator();
                    while (en.MoveNext())
                    {
                        prop = (JProperty)en.Current;

                        // Json.Net is giving me some weird errors here when I try to call prop.value<int>();
                        // I cannot figure out why so this code is a temporary work-around, it needs figured out.
                        string a = prop.ToString();
                        a = a.Substring(a.LastIndexOf("\"") + 1); // we know the value is an int, so we can look for the last "
                        a = a.Replace(":", "").Trim();

                        usageRight = new Security.UsageRight(prop.Name, (Security.Authorization.ResourcePermissionType) int.Parse(a));
                        usageRights.Add(usageRight);
                    }
                }

                remainder.Remove("$usagerights");

                resource = new Data.Resource(id, rev, versionIds, currentVersionId, new Data.Metadata(), usageRights);

                // Tags
                resource.Tags = new List <string>();
                jarray        = (JArray)document["$tags"];
                for (int i = 0; i < jarray.Count; i++)
                {
                    resource.Tags.Add(jarray[i].Value <string>());
                }
                remainder.Remove("$tags");

                resource.Created       = document["$created"].Value <DateTime>();
                resource.Creator       = document["$creator"].Value <string>();
                resource.Modified      = document["$modified"].Value <DateTime>();
                resource.Modifier      = document["$modifier"].Value <string>();
                resource.CheckedOutAt  = document["$checkedoutat"].Value <DateTime>();
                resource.CheckedOutTo  = document["$checkedoutto"].Value <string>();
                resource.LastCommit    = document["$lastcommit"].Value <DateTime>();
                resource.LastCommitter = document["$lastcommitter"].Value <string>();
                resource.Title         = document["$title"].Value <string>();

                remainder.Remove("$created");
                remainder.Remove("$creator");
                remainder.Remove("$modified");
                remainder.Remove("$modifier");
                remainder.Remove("$checkedoutat");
                remainder.Remove("$checkedoutto");
                remainder.Remove("$lastcommit");
                remainder.Remove("$lastcommitter");
                remainder.Remove("$title");
            }
            catch (Exception e)
            {
                Logger.Storage.Error("An exception occurred while attempting to parse the document.", e);
                throw;
            }

            return(resource);
        }
Esempio n. 12
0
        public Data.Resource Transition(Model.Document document, out JObject remainder)
        {
            Data.Resource resource;
            Data.ResourceId id;
            string rev = null;
            Data.VersionId currentVersionId;
            List<Data.VersionId> versionIds = null;
            List<Security.UsageRight> usageRights = null;
            Security.UsageRight usageRight = null;
            JObject jobj = null;
            JProperty prop = null;
            IEnumerator<JToken> en;
            string verifyString;
            JArray jarray = new JArray();

            if (!VerifyDocumentIntegrity(document, out verifyString))
            {
                Logger.Storage.Error("The document is not properly formatted.  It is missing the property '" + verifyString + "'.");
                throw new FormattingException("The argument document does not have the necessary property '" + verifyString + "'.");
            }

            // I ran into a problem here where I was removing the properties from the document and what was left was the remainder.
            // However, this causes an issue when using the transition to make a resource for permissions checking as the
            // object returned to implementing software is the document.  Thus, the implementing software only received those properties
            // not removed... which obviously excludes the most important properties.  To remedy this issue, I created a constructor for
            // Model.Document(Document).  This constructor will format the argument document to a string and then create a JObject from 
            // that string.  C# will deep copy the string (not byref) so as to guarantee an independent object.
            remainder = new Model.Document(document);

            try
            {
                id = new Data.ResourceId(document.Id);
                if (document["_rev"] != null)
                {
                    rev = document.Rev;
                    remainder.Remove("_rev");
                }
                
                remainder.Remove("_id");
                remainder.Remove("$type");

                currentVersionId = new Data.VersionId(document["$currentversionid"].Value<string>());
                remainder.Remove("$currentversionid");

                versionIds = new List<Data.VersionId>();
                jarray = (JArray)document["$versionids"];

                for (int i = 0; i < jarray.Count; i++)
                    versionIds.Add(new Data.VersionId(jarray[i].Value<string>()));

                remainder.Remove("$versionids");


                usageRights = new List<Security.UsageRight>();
                jarray = (JArray)document["$usagerights"];

                for (int i = 0; i < jarray.Count; i++)
                {
                    jobj = (JObject)jarray[i];
                    en = jobj.Children().GetEnumerator();
                    while (en.MoveNext())
                    {
                        prop = (JProperty)en.Current;

                        // Json.Net is giving me some weird errors here when I try to call prop.value<int>();
                        // I cannot figure out why so this code is a temporary work-around, it needs figured out.
                        string a = prop.ToString();
                        a = a.Substring(a.LastIndexOf("\"") + 1); // we know the value is an int, so we can look for the last "
                        a = a.Replace(":", "").Trim();

                        usageRight = new Security.UsageRight(prop.Name, (Security.Authorization.ResourcePermissionType)int.Parse(a));
                        usageRights.Add(usageRight);
                    }
                }

                remainder.Remove("$usagerights");

                resource = new Data.Resource(id, rev, versionIds, currentVersionId, new Data.Metadata(), usageRights);

                // Tags
                resource.Tags = new List<string>();
                jarray = (JArray)document["$tags"];
                for (int i = 0; i < jarray.Count; i++)
                    resource.Tags.Add(jarray[i].Value<string>());
                remainder.Remove("$tags");

                resource.Created = document["$created"].Value<DateTime>();
                resource.Creator = document["$creator"].Value<string>();
                resource.Modified = document["$modified"].Value<DateTime>();
                resource.Modifier = document["$modifier"].Value<string>();
                resource.CheckedOutAt = document["$checkedoutat"].Value<DateTime>();
                resource.CheckedOutTo = document["$checkedoutto"].Value<string>();
                resource.LastCommit = document["$lastcommit"].Value<DateTime>();
                resource.LastCommitter = document["$lastcommitter"].Value<string>();
                resource.Title = document["$title"].Value<string>();

                remainder.Remove("$created");
                remainder.Remove("$creator");
                remainder.Remove("$modified");
                remainder.Remove("$modifier");
                remainder.Remove("$checkedoutat");
                remainder.Remove("$checkedoutto");
                remainder.Remove("$lastcommit");
                remainder.Remove("$lastcommitter");
                remainder.Remove("$title");
            }
            catch (Exception e)
            {
                Logger.Storage.Error("An exception occurred while attempting to parse the document.", e);
                throw;
            }

            return resource;
        }
        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 CheckoutVersion(EngineRequest request, Data.VersionId versionId)
     : base(request)
 {
     _versionId = versionId;
 }
Esempio n. 15
0
 public static Uri Build(IDatabase db, Data.VersionId versionId)
 {
     return(new Uri(db.Uri.ToString() + versionId.ToString()));
 }
 public virtual void CheckoutVersion(EngineRequest request, Data.VersionId version)
 {
     throw new NotImplementedException();
 }
        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);
            }
        }