Ejemplo n.º 1
0
        public async Task <HttpResponseMessage> Put(string id)
        {
            if (IsSystemDatabase(id))
            {
                return(GetMessageWithString("System database document cannot be changed!", HttpStatusCode.Forbidden));
            }

            MessageWithStatusCode nameFormatErrorMessage;

            if (IsValidName(id, Database.Configuration.DataDirectory, out nameFormatErrorMessage) == false)
            {
                return(GetMessageWithString(nameFormatErrorMessage.Message, nameFormatErrorMessage.ErrorCode));
            }

            Etag   etag  = GetEtag();
            string error = CheckExistingDatabaseName(id, etag);

            if (error != null)
            {
                return(GetMessageWithString(error, HttpStatusCode.BadRequest));
            }
            var dbDoc = await ReadJsonObjectAsync <DatabaseDocument>().ConfigureAwait(false);

            //Preventing the modification of the database document when it is not actually changed
            //And it happens, see http://issues.hibernatingrhinos.com/issue/RavenDB-7820
            var docKey           = Constants.Database.Prefix + id;
            var databaseDocument = SystemDatabase.Documents.Get(docKey, null);
            var existingDbDoc    = databaseDocument?.DataAsJson.JsonDeserialization <DatabaseDocument>();

            if (existingDbDoc != null)
            {
                DatabasesLandlord.Unprotect(existingDbDoc);
                if (DatabaseDocument.CompareDatabaseDocumentWithoutId(existingDbDoc, dbDoc))
                {
                    return(GetEmptyMessage(HttpStatusCode.NotModified));
                }
            }

            string bundles;

            if (dbDoc.Settings.TryGetValue(Constants.ActiveBundles, out bundles) && bundles.Contains("Encryption"))
            {
                if (dbDoc.SecuredSettings == null || !dbDoc.SecuredSettings.ContainsKey(Constants.EncryptionKeySetting) ||
                    !dbDoc.SecuredSettings.ContainsKey(Constants.AlgorithmTypeSetting))
                {
                    return(GetMessageWithString(string.Format("Failed to create '{0}' database, because of invalid encryption configuration.", id), HttpStatusCode.BadRequest));
                }
            }

            //TODO: check if paths in document are legal

            if (dbDoc.IsClusterDatabase() && ClusterManager.IsActive())
            {
                string dataDir;
                if (dbDoc.Settings.TryGetValue("Raven/DataDir", out dataDir) == false || string.IsNullOrEmpty(dataDir))
                {
                    return(GetMessageWithString(string.Format("Failed to create '{0}' database, because 'Raven/DataDir' setting is missing.", id), HttpStatusCode.BadRequest));
                }

                dataDir = dataDir.ToFullPath(SystemConfiguration.DataDirectory);

                // if etag is not null, it means we want to update existing database
                if (Directory.Exists(dataDir) && etag == null)
                {
                    return(GetMessageWithString(string.Format("Failed to create '{0}' database, because data directory '{1}' exists and it is forbidden to create non-empty cluster-wide databases.", id, dataDir), HttpStatusCode.BadRequest));
                }

                var  changesAppliedMre = new ManualResetEventSlim(false);
                Etag newEtag           = null;
                var  documentKey       = Constants.Database.Prefix + id;

                Action <DocumentDatabase, DocumentChangeNotification, RavenJObject> onDocumentAction = (database, notification, jObject) =>
                {
                    if (notification.Type == DocumentChangeTypes.Put && notification.Id == documentKey)
                    {
                        newEtag = notification.Etag;
                        changesAppliedMre.Set();
                    }
                };
                Database.Notifications.OnDocumentChange += onDocumentAction;
                try
                {
                    await ClusterManager.Client.SendDatabaseUpdateAsync(id, dbDoc).ConfigureAwait(false);

                    changesAppliedMre.Wait(TimeSpan.FromSeconds(15));
                }
                finally
                {
                    Database.Notifications.OnDocumentChange -= onDocumentAction;
                }

                var clusterPutResult = new PutResult
                {
                    ETag = newEtag,
                    Key  = documentKey
                };

                return((etag == null) ? GetEmptyMessage() : GetMessageWithObject(clusterPutResult));
            }

            DatabasesLandlord.Protect(dbDoc);
            var json = RavenJObject.FromObject(dbDoc);

            json.Remove("Id");

            var metadata  = (etag != null) ? ReadInnerHeaders.FilterHeadersToObject() : new RavenJObject();
            var putResult = Database.Documents.Put(docKey, etag, json, metadata, null);

            return((etag == null) ? GetEmptyMessage() : GetMessageWithObject(putResult));
        }