/mongodb/src/main/java/org/restheart/mongodb/handlers/document/PutDocumentHandler.java

https://github.com/SoftInstigate/restheart · Java · 157 lines · 90 code · 21 blank · 46 comment · 14 complexity · c365bc801ad9de40c23ba06b1f108a9c MD5 · raw file

  1. /*-
  2. * ========================LICENSE_START=================================
  3. * restheart-mongodb
  4. * %%
  5. * Copyright (C) 2014 - 2020 SoftInstigate
  6. * %%
  7. * This program is free software: you can redistribute it and/or modify
  8. * it under the terms of the GNU Affero General Public License as published by
  9. * the Free Software Foundation, either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Affero General Public License
  18. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. * =========================LICENSE_END==================================
  20. */
  21. package org.restheart.mongodb.handlers.document;
  22. import io.undertow.server.HttpServerExchange;
  23. import io.undertow.util.Headers;
  24. import org.bson.BsonDocument;
  25. import org.bson.BsonValue;
  26. import org.restheart.exchange.MongoRequest;
  27. import org.restheart.exchange.MongoResponse;
  28. import org.restheart.exchange.OperationResult;
  29. import org.restheart.handlers.PipelinedHandler;
  30. import org.restheart.mongodb.db.DocumentDAO;
  31. import org.restheart.mongodb.utils.ResponseHelper;
  32. import org.restheart.utils.HttpStatus;
  33. /**
  34. *
  35. * @author Andrea Di Cesare {@literal <andrea@softinstigate.com>}
  36. */
  37. public class PutDocumentHandler extends PipelinedHandler {
  38. private final DocumentDAO documentDAO;
  39. /**
  40. * Default ctor
  41. */
  42. public PutDocumentHandler() {
  43. this(null, new DocumentDAO());
  44. }
  45. /**
  46. * Default ctor
  47. *
  48. * @param next
  49. */
  50. public PutDocumentHandler(PipelinedHandler next) {
  51. this(next, new DocumentDAO());
  52. }
  53. /**
  54. * Creates a new instance of PutDocumentHandler
  55. *
  56. * @param next
  57. * @param documentDAO
  58. */
  59. public PutDocumentHandler(PipelinedHandler next, DocumentDAO documentDAO) {
  60. super(next);
  61. this.documentDAO = documentDAO;
  62. }
  63. /**
  64. *
  65. * @param exchange
  66. * @throws Exception
  67. */
  68. @Override
  69. public void handleRequest(HttpServerExchange exchange) throws Exception {
  70. var request = MongoRequest.of(exchange);
  71. var response = MongoResponse.of(exchange);
  72. if (request.isInError()) {
  73. next(exchange);
  74. return;
  75. }
  76. BsonValue _content = request.getContent();
  77. if (_content == null) {
  78. _content = new BsonDocument();
  79. }
  80. // cannot PUT an array
  81. if (!_content.isDocument()) {
  82. response.setInError(
  83. HttpStatus.SC_NOT_ACCEPTABLE,
  84. "data must be a josn object");
  85. next(exchange);
  86. return;
  87. }
  88. BsonDocument content = _content.asDocument();
  89. BsonValue id = request.getDocumentId();
  90. if (content.get("_id") == null) {
  91. content.put("_id", id);
  92. } else if (!content.get("_id").equals(id)) {
  93. response.setInError(
  94. HttpStatus.SC_NOT_ACCEPTABLE,
  95. "_id in content body is different than id in URL");
  96. next(exchange);
  97. return;
  98. }
  99. String etag = request.getETag();
  100. OperationResult result = this.documentDAO.upsertDocument(
  101. request.getClientSession(),
  102. request.getDBName(),
  103. request.getCollectionName(),
  104. request.getDocumentId(),
  105. request.getFiltersDocument(),
  106. request.getShardKey(),
  107. content,
  108. etag,
  109. false,
  110. request.isETagCheckRequired());
  111. response.setDbOperationResult(result);
  112. // inject the etag
  113. if (result.getEtag() != null) {
  114. ResponseHelper.injectEtagHeader(exchange, result.getEtag());
  115. }
  116. if (result.getHttpCode() == HttpStatus.SC_CONFLICT) {
  117. response.setInError(
  118. HttpStatus.SC_CONFLICT,
  119. "The document's ETag must be provided using the '"
  120. + Headers.IF_MATCH
  121. + "' header");
  122. next(exchange);
  123. return;
  124. }
  125. // handle the case of duplicate key error
  126. if (result.getHttpCode() == HttpStatus.SC_EXPECTATION_FAILED) {
  127. response.setInError(
  128. HttpStatus.SC_EXPECTATION_FAILED,
  129. ResponseHelper.getMessageFromErrorCode(11000));
  130. next(exchange);
  131. return;
  132. }
  133. response.setStatusCode(result.getHttpCode());
  134. next(exchange);
  135. }
  136. }