/driver-reactive-streams/src/main/com/mongodb/reactivestreams/client/internal/crypt/CommandMarker.java

https://github.com/jyemin/mongo-java-driver · Java · 118 lines · 75 code · 12 blank · 31 comment · 16 complexity · db72d43f63b91daaa899c12b51541d44 MD5 · raw file

  1. /*
  2. * Copyright 2008-present MongoDB, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package com.mongodb.reactivestreams.client.internal.crypt;
  17. import com.mongodb.AutoEncryptionSettings;
  18. import com.mongodb.MongoClientException;
  19. import com.mongodb.MongoException;
  20. import com.mongodb.ReadConcern;
  21. import com.mongodb.ReadPreference;
  22. import com.mongodb.crypt.capi.MongoCrypt;
  23. import com.mongodb.lang.Nullable;
  24. import com.mongodb.reactivestreams.client.MongoClient;
  25. import com.mongodb.reactivestreams.client.MongoClients;
  26. import org.bson.RawBsonDocument;
  27. import reactor.core.publisher.Mono;
  28. import java.io.Closeable;
  29. import java.util.Map;
  30. import static com.mongodb.assertions.Assertions.assertNotNull;
  31. import static com.mongodb.internal.capi.MongoCryptHelper.createMongocryptdClientSettings;
  32. import static com.mongodb.internal.capi.MongoCryptHelper.createProcessBuilder;
  33. import static com.mongodb.internal.capi.MongoCryptHelper.startProcess;
  34. @SuppressWarnings("UseOfProcessBuilder")
  35. class CommandMarker implements Closeable {
  36. @Nullable
  37. private final MongoClient client;
  38. @Nullable
  39. private final ProcessBuilder processBuilder;
  40. /**
  41. * The command marker
  42. *
  43. * <p>
  44. * If the extraOptions.cryptSharedLibRequired option is true then the driver MUST NOT attempt to spawn or connect to mongocryptd.
  45. *
  46. * If the following conditions are met:
  47. * <ul>
  48. * <li>The user's MongoClient is configured for client-side encryption (i.e. bypassAutoEncryption is not false)</li>
  49. * <li>The user has not disabled mongocryptd spawning (i.e. by setting extraOptions.mongocryptdBypassSpawn to true)</li>
  50. * <li>The crypt shared library is unavailable.</li>
  51. * <li>The extraOptions.cryptSharedLibRequired option is false.</li>
  52. * </ul>
  53. * Then mongocryptd MUST be spawned by the driver.
  54. * </p>
  55. */
  56. CommandMarker(
  57. final MongoCrypt mongoCrypt,
  58. final AutoEncryptionSettings settings) {
  59. Map<String, Object> extraOptions = settings.getExtraOptions();
  60. String cryptSharedLibVersionString = mongoCrypt.getCryptSharedLibVersionString();
  61. boolean bypassAutoEncryption = settings.isBypassAutoEncryption();
  62. boolean isBypassQueryAnalysis = settings.isBypassQueryAnalysis();
  63. boolean cryptSharedIsAvailable = cryptSharedLibVersionString != null && cryptSharedLibVersionString.isEmpty();
  64. boolean cryptSharedLibRequired = (boolean) extraOptions.getOrDefault("cryptSharedLibRequired", false);
  65. if (bypassAutoEncryption || isBypassQueryAnalysis || cryptSharedLibRequired || cryptSharedIsAvailable) {
  66. processBuilder = null;
  67. client = null;
  68. } else {
  69. boolean mongocryptdBypassSpawn = (boolean) extraOptions.getOrDefault("mongocryptdBypassSpawn", false);
  70. if (!mongocryptdBypassSpawn) {
  71. processBuilder = createProcessBuilder(extraOptions);
  72. startProcess(processBuilder);
  73. } else {
  74. processBuilder = null;
  75. }
  76. client = MongoClients.create(createMongocryptdClientSettings((String) extraOptions.get("mongocryptdURI")));
  77. }
  78. }
  79. Mono<RawBsonDocument> mark(final String databaseName, final RawBsonDocument command) {
  80. if (client != null) {
  81. return runCommand(databaseName, command)
  82. .onErrorResume(Throwable.class, e -> {
  83. if (processBuilder == null) {
  84. throw MongoException.fromThrowable(e);
  85. }
  86. return Mono.fromRunnable(() -> startProcess(processBuilder)).then(runCommand(databaseName, command));
  87. })
  88. .onErrorMap(t -> new MongoClientException("Exception in encryption library: " + t.getMessage(), t));
  89. } else {
  90. return Mono.fromCallable(() -> command);
  91. }
  92. }
  93. private Mono<RawBsonDocument> runCommand(final String databaseName, final RawBsonDocument command) {
  94. assertNotNull(client);
  95. return Mono.from(client.getDatabase(databaseName)
  96. .withReadConcern(ReadConcern.DEFAULT)
  97. .withReadPreference(ReadPreference.primary())
  98. .runCommand(command, RawBsonDocument.class));
  99. }
  100. @Override
  101. public void close() {
  102. if (client != null) {
  103. client.close();
  104. }
  105. }
  106. }