/* * Copyright (c) 2008-2014 MongoDB, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.mongodb.operation; import com.mongodb.MongoNamespace; import com.mongodb.async.SingleResultCallback; import com.mongodb.binding.AsyncReadBinding; import com.mongodb.binding.ReadBinding; import com.mongodb.client.model.Collation; import com.mongodb.connection.AsyncConnection; import com.mongodb.connection.Connection; import org.bson.BsonArray; import org.bson.BsonBoolean; import org.bson.BsonDocument; import org.bson.BsonInt64; import org.bson.BsonString; import java.util.List; import java.util.concurrent.TimeUnit; import static com.mongodb.assertions.Assertions.notNull; import static com.mongodb.internal.async.ErrorHandlingResultCallback.errorHandlingCallback; import static com.mongodb.operation.CommandOperationHelper.IdentityTransformer; import static com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocol; import static com.mongodb.operation.CommandOperationHelper.executeWrappedCommandProtocolAsync; import static com.mongodb.operation.OperationHelper.AsyncCallableWithConnection; import static com.mongodb.operation.OperationHelper.CallableWithConnection; import static com.mongodb.operation.OperationHelper.LOGGER; import static com.mongodb.operation.OperationHelper.validateCollation; import static com.mongodb.operation.OperationHelper.releasingCallback; import static com.mongodb.operation.OperationHelper.withConnection; // an operation that executes an explain on an aggregation pipeline class AggregateExplainOperation implements AsyncReadOperation<BsonDocument>, ReadOperation<BsonDocument> { private final MongoNamespace namespace; private final List<BsonDocument> pipeline; private Boolean allowDiskUse; private long maxTimeMS; private Collation collation; AggregateExplainOperation(final MongoNamespace namespace, final List<BsonDocument> pipeline) { this.namespace = notNull("namespace", namespace); this.pipeline = notNull("pipeline", pipeline); } /** * Enables writing to temporary files. A null value indicates that it's unspecified. * * @param allowDiskUse true if writing to temporary files is enabled * @return this * @mongodb.driver.manual reference/command/aggregate/ Aggregation * @mongodb.server.release 2.6 */ public AggregateExplainOperation allowDiskUse(final Boolean allowDiskUse) { this.allowDiskUse = allowDiskUse; return this; } /** * Sets the maximum execution time on the server for this operation. * * @param maxTime the max time * @param timeUnit the time unit, which may not be null * @return this * @mongodb.driver.manual reference/method/cursor.maxTimeMS/#cursor.maxTimeMS Max Time */ public AggregateExplainOperation maxTime(final long maxTime, final TimeUnit timeUnit) { notNull("timeUnit", timeUnit); this.maxTimeMS = TimeUnit.MILLISECONDS.convert(maxTime, timeUnit); return this; } /** * Sets the collation options * * <p>A null value represents the server default.</p> * @param collation the collation options to use * @return this * @since 3.4 * @mongodb.driver.manual reference/command/aggregate/ Aggregation * @mongodb.server.release 3.4 */ public AggregateExplainOperation collation(final Collation collation) { this.collation = collation; return this; } @Override public BsonDocument execute(final ReadBinding binding) { return withConnection(binding, new CallableWithConnection<BsonDocument>() { @Override public BsonDocument call(final Connection connection) { validateCollation(connection, collation); return executeWrappedCommandProtocol(binding, namespace.getDatabaseName(), getCommand(), connection); } }); } @Override public void executeAsync(final AsyncReadBinding binding, final SingleResultCallback<BsonDocument> callback) { withConnection(binding, new AsyncCallableWithConnection() { @Override public void call(final AsyncConnection connection, final Throwable t) { SingleResultCallback<BsonDocument> errHandlingCallback = errorHandlingCallback(callback, LOGGER); if (t != null) { errHandlingCallback.onResult(null, t); } else { final SingleResultCallback<BsonDocument> wrappedCallback = releasingCallback(errHandlingCallback, connection); validateCollation(connection, collation, new AsyncCallableWithConnection() { @Override public void call(final AsyncConnection connection, final Throwable t) { if (t != null) { wrappedCallback.onResult(null, t); } else { executeWrappedCommandProtocolAsync(binding, namespace.getDatabaseName(), getCommand(), connection, new IdentityTransformer<BsonDocument>(), wrappedCallback); } } }); } } }); } private BsonDocument getCommand() { BsonDocument commandDocument = new BsonDocument("aggregate", new BsonString(namespace.getCollectionName())); commandDocument.put("pipeline", new BsonArray(pipeline)); commandDocument.put("explain", BsonBoolean.TRUE); if (maxTimeMS > 0) { commandDocument.put("maxTimeMS", new BsonInt64(maxTimeMS)); } if (allowDiskUse != null) { commandDocument.put("allowDiskUse", BsonBoolean.valueOf(allowDiskUse)); } if (collation != null) { commandDocument.put("collation", collation.asDocument()); } return commandDocument; } }