Coverage Report - com.allanbank.mongodb.client.MongoDatabaseImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
MongoDatabaseImpl
89%
142/159
91%
62/68
1.864
MongoDatabaseImpl$1
100%
1/1
N/A
1.864
 
 1  
 /*
 2  
  * #%L
 3  
  * MongoDatabaseImpl.java - mongodb-async-driver - Allanbank Consulting, Inc.
 4  
  * %%
 5  
  * Copyright (C) 2011 - 2014 Allanbank Consulting, Inc.
 6  
  * %%
 7  
  * Licensed under the Apache License, Version 2.0 (the "License");
 8  
  * you may not use this file except in compliance with the License.
 9  
  * You may obtain a copy of the License at
 10  
  * 
 11  
  *      http://www.apache.org/licenses/LICENSE-2.0
 12  
  * 
 13  
  * Unless required by applicable law or agreed to in writing, software
 14  
  * distributed under the License is distributed on an "AS IS" BASIS,
 15  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 16  
  * See the License for the specific language governing permissions and
 17  
  * limitations under the License.
 18  
  * #L%
 19  
  */
 20  
 package com.allanbank.mongodb.client;
 21  
 
 22  
 import java.lang.ref.Reference;
 23  
 import java.lang.ref.ReferenceQueue;
 24  
 import java.util.ArrayList;
 25  
 import java.util.Iterator;
 26  
 import java.util.List;
 27  
 import java.util.concurrent.ConcurrentHashMap;
 28  
 import java.util.concurrent.ConcurrentMap;
 29  
 
 30  
 import com.allanbank.mongodb.Callback;
 31  
 import com.allanbank.mongodb.Durability;
 32  
 import com.allanbank.mongodb.LambdaCallback;
 33  
 import com.allanbank.mongodb.ListenableFuture;
 34  
 import com.allanbank.mongodb.LockType;
 35  
 import com.allanbank.mongodb.MongoClient;
 36  
 import com.allanbank.mongodb.MongoCollection;
 37  
 import com.allanbank.mongodb.MongoDatabase;
 38  
 import com.allanbank.mongodb.MongoDbException;
 39  
 import com.allanbank.mongodb.MongoIterator;
 40  
 import com.allanbank.mongodb.ProfilingStatus;
 41  
 import com.allanbank.mongodb.ReadPreference;
 42  
 import com.allanbank.mongodb.Version;
 43  
 import com.allanbank.mongodb.bson.Document;
 44  
 import com.allanbank.mongodb.bson.DocumentAssignable;
 45  
 import com.allanbank.mongodb.bson.Element;
 46  
 import com.allanbank.mongodb.bson.NumericElement;
 47  
 import com.allanbank.mongodb.bson.builder.BuilderFactory;
 48  
 import com.allanbank.mongodb.bson.builder.DocumentBuilder;
 49  
 import com.allanbank.mongodb.bson.element.StringElement;
 50  
 import com.allanbank.mongodb.client.callback.CursorCallback;
 51  
 import com.allanbank.mongodb.client.callback.ReplyCommandCallback;
 52  
 import com.allanbank.mongodb.client.message.Command;
 53  
 import com.allanbank.mongodb.client.message.Query;
 54  
 import com.allanbank.mongodb.util.FutureUtils;
 55  
 
 56  
 /**
 57  
  * Implementation of the {@link MongoDatabase} interface.
 58  
  * 
 59  
  * @api.no This class is <b>NOT</b> part of the drivers API. This class may be
 60  
  *         mutated in incompatible ways between any two releases of the driver.
 61  
  * @copyright 2011-2014, Allanbank Consulting, Inc., All Rights Reserved
 62  
  */
 63  
 public class MongoDatabaseImpl implements MongoDatabase {
 64  
 
 65  
     /** An empty query document. */
 66  1
     public static final Document EMPTY_QUERY = MongoCollection.ALL;
 67  
 
 68  
     /** The client for interacting with MongoDB. */
 69  
     protected final Client myClient;
 70  
 
 71  
     /** The 'admin' database. */
 72  
     private MongoDatabase myAdminDatabase;
 73  
 
 74  
     /** The set of databases in use. */
 75  
     private final ConcurrentMap<String, Reference<MongoCollection>> myCollections;
 76  
 
 77  
     /** The {@link Durability} for writes from this database instance. */
 78  
     private Durability myDurability;
 79  
 
 80  
     /** The {@link MongoClient}. */
 81  
     private final MongoClient myMongoClient;
 82  
 
 83  
     /** The name of the database we interact with. */
 84  
     private final String myName;
 85  
 
 86  
     /** The {@link ReadPreference} for reads from this database instance. */
 87  
     private ReadPreference myReadPreference;
 88  
 
 89  
     /** The queue of references to the collections that have been reclaimed. */
 90  58
     private final ReferenceQueue<MongoCollection> myReferenceQueue = new ReferenceQueue<MongoCollection>();
 91  
 
 92  
     /**
 93  
      * Create a new MongoDatabaseClient.
 94  
      * 
 95  
      * @param mongoClient
 96  
      *            The {@link MongoClient}.
 97  
      * @param client
 98  
      *            The client for interacting with MongoDB.
 99  
      * @param name
 100  
      *            The name of the database we interact with.
 101  
      */
 102  
     public MongoDatabaseImpl(final MongoClient mongoClient,
 103  58
             final Client client, final String name) {
 104  58
         myMongoClient = mongoClient;
 105  58
         myClient = client;
 106  58
         myName = name;
 107  58
         myDurability = null;
 108  58
         myReadPreference = null;
 109  58
         myCollections = new ConcurrentHashMap<String, Reference<MongoCollection>>();
 110  58
     }
 111  
 
 112  
     /**
 113  
      * {@inheritDoc}
 114  
      * <p>
 115  
      * Issues a command to create the collection with the specified name and
 116  
      * options.
 117  
      * </p>
 118  
      */
 119  
     @Override
 120  
     public boolean createCappedCollection(final String name, final long size)
 121  
             throws MongoDbException {
 122  3
         return createCollection(name, BuilderFactory.start()
 123  
                 .add("capped", true).add("size", size));
 124  
     }
 125  
 
 126  
     /**
 127  
      * {@inheritDoc}
 128  
      * <p>
 129  
      * Issues a command to create the collection with the specified name and
 130  
      * options.
 131  
      * </p>
 132  
      */
 133  
     @Override
 134  
     public boolean createCollection(final String name,
 135  
             final DocumentAssignable options) throws MongoDbException {
 136  6
         final Document result = runCommand("create", name, options);
 137  6
         final NumericElement okElem = result.get(NumericElement.class, "ok");
 138  
 
 139  6
         return ((okElem != null) && (okElem.getIntValue() > 0));
 140  
     }
 141  
 
 142  
     /**
 143  
      * {@inheritDoc}
 144  
      * <p>
 145  
      * Overridden to issue a "dropDatabase" command.
 146  
      * </p>
 147  
      * 
 148  
      * @see MongoDatabase#drop()
 149  
      */
 150  
     @Override
 151  
     public boolean drop() {
 152  3
         final Document result = runCommand("dropDatabase");
 153  3
         final NumericElement okElem = result.get(NumericElement.class, "ok");
 154  
 
 155  3
         return ((okElem != null) && (okElem.getIntValue() > 0));
 156  
     }
 157  
 
 158  
     /**
 159  
      * {@inheritDoc}
 160  
      */
 161  
     @Override
 162  
     public boolean exists() {
 163  1
         return myMongoClient.listDatabaseNames().contains(getName());
 164  
     }
 165  
 
 166  
     /**
 167  
      * {@inheritDoc}
 168  
      * <p>
 169  
      * Overridden to create a new {@link SynchronousMongoCollectionImpl}.
 170  
      * </p>
 171  
      * 
 172  
      * @see MongoDatabase#getCollection(String)
 173  
      */
 174  
     @Override
 175  
     public MongoCollection getCollection(final String name) {
 176  30
         MongoCollection collection = null;
 177  30
         Reference<MongoCollection> ref = myCollections.get(name);
 178  30
         if (ref != null) {
 179  6
             collection = ref.get();
 180  6
             if (collection == null) {
 181  
                 // Reference was take n from the map. Remove it from the map.
 182  0
                 myCollections.remove(name, ref);
 183  
             }
 184  
         }
 185  
 
 186  
         // Create a new one.
 187  30
         if (collection == null) {
 188  24
             collection = new SynchronousMongoCollectionImpl(myClient, this,
 189  
                     name);
 190  24
             ref = new NamedReference<MongoCollection>(name, collection,
 191  
                     myReferenceQueue);
 192  
 
 193  24
             final Reference<MongoCollection> existing = myCollections
 194  
                     .putIfAbsent(name, ref);
 195  24
             if (existing != null) {
 196  0
                 final MongoCollection existingCollection = existing.get();
 197  0
                 if (existingCollection != null) {
 198  0
                     collection = existingCollection;
 199  
                 }
 200  
                 // Extremely unlikely but if the reference came and went that
 201  
                 // quick it is the next guys problem to add one. We will return
 202  
                 // the one we created.
 203  
             }
 204  
         }
 205  
 
 206  
         // Clean out any garbage collected references.
 207  
         Reference<?> polled;
 208  43
         while ((polled = myReferenceQueue.poll()) != null) {
 209  13
             if (polled instanceof NamedReference) {
 210  13
                 myCollections.remove(((NamedReference<?>) polled).getName(),
 211  
                         polled);
 212  
             }
 213  
         }
 214  
 
 215  30
         return collection;
 216  
     }
 217  
 
 218  
     /**
 219  
      * {@inheritDoc}
 220  
      */
 221  
     @Override
 222  
     public Durability getDurability() {
 223  3
         Durability result = myDurability;
 224  3
         if (result == null) {
 225  2
             result = myClient.getDefaultDurability();
 226  
         }
 227  3
         return result;
 228  
     }
 229  
 
 230  
     /**
 231  
      * {@inheritDoc}
 232  
      */
 233  
     @Override
 234  
     public String getName() {
 235  4
         return myName;
 236  
     }
 237  
 
 238  
     /**
 239  
      * {@inheritDoc}
 240  
      * <p>
 241  
      * Overridden to query the system.namespace collection for the names of all
 242  
      * of the collections.
 243  
      * </p>
 244  
      * 
 245  
      * @see MongoDatabase#getProfilingStatus()
 246  
      */
 247  
     @Override
 248  
     public ProfilingStatus getProfilingStatus() throws MongoDbException {
 249  6
         final Document result = runCommand("profile", -1, null);
 250  
 
 251  6
         final NumericElement level = result.get(NumericElement.class, "was");
 252  6
         final NumericElement millis = result
 253  
                 .get(NumericElement.class, "slowms");
 254  
 
 255  6
         if ((level != null) && (millis != null)) {
 256  4
             final ProfilingStatus.Level l = ProfilingStatus.Level
 257  
                     .fromValue(level.getIntValue());
 258  4
             if (l != null) {
 259  3
                 switch (l) {
 260  
                 case NONE:
 261  1
                     return ProfilingStatus.OFF;
 262  
                 case ALL:
 263  1
                     return ProfilingStatus.ON;
 264  
                 case SLOW_ONLY:
 265  1
                     return ProfilingStatus.slow(millis.getIntValue());
 266  
                 }
 267  
             }
 268  
         }
 269  
 
 270  
         // undefined?
 271  3
         return null;
 272  
 
 273  
     }
 274  
 
 275  
     /**
 276  
      * {@inheritDoc}
 277  
      */
 278  
     @Override
 279  
     public ReadPreference getReadPreference() {
 280  3
         ReadPreference result = myReadPreference;
 281  3
         if (result == null) {
 282  2
             result = myClient.getDefaultReadPreference();
 283  
         }
 284  3
         return result;
 285  
     }
 286  
 
 287  
     /**
 288  
      * {@inheritDoc}
 289  
      * <p>
 290  
      * Overridden to query the system.namespace collection for the names of all
 291  
      * of the collections.
 292  
      * </p>
 293  
      * 
 294  
      * @see MongoDatabase#listCollectionNames()
 295  
      */
 296  
     @Override
 297  
     public List<String> listCollectionNames() {
 298  2
         final Query query = new Query(myName, "system.namespaces", EMPTY_QUERY,
 299  
         /* fields= */null,
 300  
         /* batchSize= */0, /* limit= */0, /* numberToSkip= */0,
 301  
         /* tailable= */false, ReadPreference.PRIMARY,
 302  
         /* noCursorTimeout= */false, /* awaitData= */false,
 303  
         /* exhaust= */false, /* partial= */false);
 304  
 
 305  2
         final FutureCallback<MongoIterator<Document>> iterFuture = new FutureCallback<MongoIterator<Document>>(
 306  
                 getLockType());
 307  2
         final CursorCallback callback = new CursorCallback(myClient, query,
 308  
                 false, iterFuture);
 309  
 
 310  2
         myClient.send(query, callback);
 311  
 
 312  2
         final List<String> names = new ArrayList<String>();
 313  2
         final Iterator<Document> iter = FutureUtils.unwrap(iterFuture);
 314  6
         while (iter.hasNext()) {
 315  4
             final Document collection = iter.next();
 316  4
             for (final StringElement nameElement : collection.find(
 317  
                     StringElement.class, "name")) {
 318  4
                 final String name = nameElement.getValue();
 319  4
                 if ((name.indexOf('$') >= 0) && (name.indexOf(".oplog.$") < 0)) {
 320  0
                     continue;
 321  
                 }
 322  
 
 323  4
                 names.add(name.substring(myName.length() + 1));
 324  4
             }
 325  4
         }
 326  
 
 327  2
         return names;
 328  
     }
 329  
 
 330  
     /**
 331  
      * {@inheritDoc}
 332  
      * <p>
 333  
      * Overridden to query the system.namespace collection for the names of all
 334  
      * of the collections.
 335  
      * </p>
 336  
      * 
 337  
      * @see MongoDatabase#listCollectionNames()
 338  
      */
 339  
     @Override
 340  
     @Deprecated
 341  
     public List<String> listCollections() {
 342  1
         return listCollectionNames();
 343  
     }
 344  
 
 345  
     /**
 346  
      * {@inheritDoc}
 347  
      * <p>
 348  
      * Overridden to call {@link #runCommand(String)} on the 'admin' database.
 349  
      * </p>
 350  
      * 
 351  
      * @see #runCommandAsync(String, DocumentAssignable)
 352  
      */
 353  
     @Override
 354  
     public Document runAdminCommand(final String command)
 355  
             throws MongoDbException {
 356  4
         return getAdminDatabase().runCommand(command);
 357  
     }
 358  
 
 359  
     /**
 360  
      * {@inheritDoc}
 361  
      * <p>
 362  
      * Overridden to call the
 363  
      * {@link #runCommandAsync(String, DocumentAssignable)} method.
 364  
      * </p>
 365  
      * 
 366  
      * @see #runCommandAsync(String, DocumentAssignable)
 367  
      */
 368  
     @Override
 369  
     public Document runAdminCommand(final String command,
 370  
             final DocumentAssignable options) throws MongoDbException {
 371  2
         return getAdminDatabase().runCommand(command, options);
 372  
     }
 373  
 
 374  
     /**
 375  
      * {@inheritDoc}
 376  
      * <p>
 377  
      * Overridden to call the
 378  
      * {@link #runCommandAsync(String, String, DocumentAssignable)} method.
 379  
      * </p>
 380  
      * 
 381  
      * @see #runCommandAsync(String, String, DocumentAssignable)
 382  
      */
 383  
     @Override
 384  
     public Document runAdminCommand(final String commandName,
 385  
             final String commandValue, final DocumentAssignable options)
 386  
             throws MongoDbException {
 387  1
         return getAdminDatabase()
 388  
                 .runCommand(commandName, commandValue, options);
 389  
     }
 390  
 
 391  
     /**
 392  
      * {@inheritDoc}
 393  
      * <p>
 394  
      * Overridden to call the {@link #runCommandAsync(DocumentAssignable)}
 395  
      * method.
 396  
      * </p>
 397  
      * 
 398  
      * @see #runCommandAsync(DocumentAssignable)
 399  
      */
 400  
     @Override
 401  
     public Document runCommand(final DocumentAssignable command)
 402  
             throws MongoDbException {
 403  1
         return FutureUtils.unwrap(runCommandAsync(command));
 404  
     }
 405  
 
 406  
     /**
 407  
      * {@inheritDoc}
 408  
      * <p>
 409  
      * Overridden to call the
 410  
      * {@link #runCommandAsync(String, DocumentAssignable)} method with
 411  
      * <code>null</code> options.
 412  
      * </p>
 413  
      * 
 414  
      * @see #runCommandAsync(String, DocumentAssignable)
 415  
      */
 416  
     @Override
 417  
     public Document runCommand(final String command) throws MongoDbException {
 418  9
         return FutureUtils.unwrap(runCommandAsync(command, null));
 419  
     }
 420  
 
 421  
     /**
 422  
      * {@inheritDoc}
 423  
      * <p>
 424  
      * Overridden to call the
 425  
      * {@link #runCommandAsync(String, DocumentAssignable)} method.
 426  
      * </p>
 427  
      * 
 428  
      * @see #runCommandAsync(String, DocumentAssignable)
 429  
      */
 430  
     @Override
 431  
     public Document runCommand(final String command,
 432  
             final DocumentAssignable options) throws MongoDbException {
 433  3
         return FutureUtils.unwrap(runCommandAsync(command, options));
 434  
     }
 435  
 
 436  
     /**
 437  
      * {@inheritDoc}
 438  
      * <p>
 439  
      * Overridden to call the
 440  
      * {@link #runCommandAsync(String, int, DocumentAssignable)} method.
 441  
      * </p>
 442  
      * 
 443  
      * @see #runCommandAsync(String, int, DocumentAssignable)
 444  
      */
 445  
     @Override
 446  
     public Document runCommand(final String commandName,
 447  
             final int commandValue, final DocumentAssignable options)
 448  
             throws MongoDbException {
 449  15
         return FutureUtils.unwrap(runCommandAsync(commandName, commandValue,
 450  
                 options));
 451  
     }
 452  
 
 453  
     /**
 454  
      * {@inheritDoc}
 455  
      * <p>
 456  
      * Overridden to call the
 457  
      * {@link #runCommandAsync(String, String, DocumentAssignable)} method.
 458  
      * </p>
 459  
      * 
 460  
      * @see #runCommandAsync(String, String, DocumentAssignable)
 461  
      */
 462  
     @Override
 463  
     public Document runCommand(final String commandName,
 464  
             final String commandValue, final DocumentAssignable options)
 465  
             throws MongoDbException {
 466  8
         return FutureUtils.unwrap(runCommandAsync(commandName, commandValue,
 467  
                 options));
 468  
     }
 469  
 
 470  
     /**
 471  
      * {@inheritDoc}
 472  
      * <p>
 473  
      * Overridden to call the
 474  
      * {@link #runCommandAsync(Callback, DocumentAssignable, Version)} method
 475  
      * with {@code null} as the version.
 476  
      * </p>
 477  
      * 
 478  
      * @see #runCommandAsync(Callback, DocumentAssignable, Version)
 479  
      */
 480  
     @Override
 481  
     public void runCommandAsync(final Callback<Document> reply,
 482  
             final DocumentAssignable command) throws MongoDbException {
 483  43
         runCommandAsync(reply, command, null);
 484  43
     }
 485  
 
 486  
     /**
 487  
      * {@inheritDoc}
 488  
      * <p>
 489  
      * Overridden to build a {@link Command} message and send it to the server.
 490  
      * </p>
 491  
      */
 492  
     @Override
 493  
     public void runCommandAsync(final Callback<Document> reply,
 494  
             final DocumentAssignable command, final Version requireServerVersion)
 495  
             throws MongoDbException {
 496  43
         final Command commandMessage = new Command(myName,
 497  
                 Command.COMMAND_COLLECTION, command.asDocument(),
 498  
                 ReadPreference.PRIMARY,
 499  
                 VersionRange.minimum(requireServerVersion));
 500  
 
 501  43
         myClient.send(commandMessage, new ReplyCommandCallback(reply));
 502  43
     }
 503  
 
 504  
     /**
 505  
      * {@inheritDoc}
 506  
      * <p>
 507  
      * Overridden to call the
 508  
      * {@link #runCommandAsync(Callback, String, DocumentAssignable)} method
 509  
      * with <code>null</code> for the options.
 510  
      * </p>
 511  
      * 
 512  
      * @see #runCommandAsync(Callback, String, DocumentAssignable)
 513  
      */
 514  
     @Override
 515  
     public void runCommandAsync(final Callback<Document> reply,
 516  
             final String command) throws MongoDbException {
 517  1
         runCommandAsync(reply, command, null);
 518  1
     }
 519  
 
 520  
     /**
 521  
      * {@inheritDoc}
 522  
      * <p>
 523  
      * Overridden to build the command document and call
 524  
      * {@link #runCommandAsync(Callback, DocumentAssignable)}.
 525  
      * </p>
 526  
      */
 527  
     @Override
 528  
     public void runCommandAsync(final Callback<Document> reply,
 529  
             final String command, final DocumentAssignable options)
 530  
             throws MongoDbException {
 531  16
         final DocumentBuilder builder = BuilderFactory.start();
 532  16
         builder.addInteger(command, 1);
 533  16
         addOptions(command, options, builder);
 534  
 
 535  16
         runCommandAsync(reply, builder);
 536  16
     }
 537  
 
 538  
     /**
 539  
      * {@inheritDoc}
 540  
      * <p>
 541  
      * Overridden to build the command document and call
 542  
      * {@link #runCommandAsync(Callback, DocumentAssignable)}.
 543  
      * </p>
 544  
      */
 545  
     @Override
 546  
     public void runCommandAsync(final Callback<Document> reply,
 547  
             final String commandName, final int commandValue,
 548  
             final DocumentAssignable options) throws MongoDbException {
 549  15
         final DocumentBuilder builder = BuilderFactory.start();
 550  15
         builder.add(commandName, commandValue);
 551  15
         addOptions(commandName, options, builder);
 552  
 
 553  15
         runCommandAsync(reply, builder);
 554  15
     }
 555  
 
 556  
     /**
 557  
      * {@inheritDoc}
 558  
      * <p>
 559  
      * Overridden to build the command document and call
 560  
      * {@link #runCommandAsync(Callback, DocumentAssignable)}.
 561  
      * </p>
 562  
      */
 563  
     @Override
 564  
     public void runCommandAsync(final Callback<Document> reply,
 565  
             final String commandName, final String commandValue,
 566  
             final DocumentAssignable options) throws MongoDbException {
 567  10
         final DocumentBuilder builder = BuilderFactory.start();
 568  10
         builder.add(commandName, commandValue);
 569  10
         addOptions(commandName, options, builder);
 570  
 
 571  10
         runCommandAsync(reply, builder);
 572  10
     }
 573  
 
 574  
     /**
 575  
      * {@inheritDoc}
 576  
      * <p>
 577  
      * Overridden to call the
 578  
      * {@link #runCommandAsync(Callback, DocumentAssignable)} method.
 579  
      * </p>
 580  
      * 
 581  
      * @see #runCommandAsync(Callback, DocumentAssignable)
 582  
      */
 583  
     @Override
 584  
     public ListenableFuture<Document> runCommandAsync(
 585  
             final DocumentAssignable command) throws MongoDbException {
 586  2
         final FutureCallback<Document> future = new FutureCallback<Document>(
 587  
                 getLockType());
 588  
 
 589  2
         runCommandAsync(future, command);
 590  
 
 591  2
         return future;
 592  
     }
 593  
 
 594  
     /**
 595  
      * {@inheritDoc}
 596  
      * <p>
 597  
      * Overridden to call {@link #runCommandAsync(Callback, DocumentAssignable)}
 598  
      * with an adapter for the {@link LambdaCallback}.
 599  
      * </p>
 600  
      */
 601  
     @Override
 602  
     public void runCommandAsync(final LambdaCallback<Document> reply,
 603  
             final DocumentAssignable command) throws MongoDbException {
 604  0
         runCommandAsync(new LambdaCallbackAdapter<Document>(reply), command);
 605  0
     }
 606  
 
 607  
     /**
 608  
      * {@inheritDoc}
 609  
      * <p>
 610  
      * Overridden to call
 611  
      * {@link #runCommandAsync(Callback, DocumentAssignable, Version)} with an
 612  
      * adapter for the {@link LambdaCallback}.
 613  
      * </p>
 614  
      */
 615  
     @Override
 616  
     public void runCommandAsync(final LambdaCallback<Document> reply,
 617  
             final DocumentAssignable command,
 618  
             final Version requiredServerVersion) throws MongoDbException {
 619  0
         runCommandAsync(new LambdaCallbackAdapter<Document>(reply), command,
 620  
                 requiredServerVersion);
 621  0
     }
 622  
 
 623  
     /**
 624  
      * {@inheritDoc}
 625  
      * <p>
 626  
      * Overridden to call {@link #runCommandAsync(Callback, String)} with an
 627  
      * adapter for the {@link LambdaCallback}.
 628  
      * </p>
 629  
      */
 630  
     @Override
 631  
     public void runCommandAsync(final LambdaCallback<Document> reply,
 632  
             final String command) throws MongoDbException {
 633  0
         runCommandAsync(new LambdaCallbackAdapter<Document>(reply), command);
 634  0
     }
 635  
 
 636  
     /**
 637  
      * {@inheritDoc}
 638  
      * <p>
 639  
      * Overridden to call
 640  
      * {@link #runCommandAsync(Callback, String, DocumentAssignable)} with an
 641  
      * adapter for the {@link LambdaCallback}.
 642  
      * </p>
 643  
      */
 644  
     @Override
 645  
     public void runCommandAsync(final LambdaCallback<Document> reply,
 646  
             final String command, final DocumentAssignable options)
 647  
             throws MongoDbException {
 648  0
         runCommandAsync(new LambdaCallbackAdapter<Document>(reply), command,
 649  
                 options);
 650  0
     }
 651  
 
 652  
     /**
 653  
      * {@inheritDoc}
 654  
      * <p>
 655  
      * Overridden to call
 656  
      * {@link #runCommandAsync(Callback, String, int, DocumentAssignable)} with
 657  
      * an adapter for the {@link LambdaCallback}.
 658  
      * </p>
 659  
      */
 660  
     @Override
 661  
     public void runCommandAsync(final LambdaCallback<Document> reply,
 662  
             final String commandName, final int commandValue,
 663  
             final DocumentAssignable options) throws MongoDbException {
 664  0
         runCommandAsync(new LambdaCallbackAdapter<Document>(reply),
 665  
                 commandName, commandValue, options);
 666  0
     }
 667  
 
 668  
     /**
 669  
      * {@inheritDoc}
 670  
      * <p>
 671  
      * Overridden to call
 672  
      * {@link #runCommandAsync(Callback, String, String, DocumentAssignable)}
 673  
      * with an adapter for the {@link LambdaCallback}.
 674  
      * </p>
 675  
      */
 676  
     @Override
 677  
     public void runCommandAsync(final LambdaCallback<Document> reply,
 678  
             final String commandName, final String commandValue,
 679  
             final DocumentAssignable options) throws MongoDbException {
 680  0
         runCommandAsync(new LambdaCallbackAdapter<Document>(reply),
 681  
                 commandName, commandValue, options);
 682  0
     }
 683  
 
 684  
     /**
 685  
      * {@inheritDoc}
 686  
      * <p>
 687  
      * Overridden to call the
 688  
      * {@link #runCommandAsync(Callback, String, DocumentAssignable)} method
 689  
      * with <code>null</code> options.
 690  
      * </p>
 691  
      * 
 692  
      * @see #runCommandAsync(Callback, String, DocumentAssignable)
 693  
      */
 694  
     @Override
 695  
     public ListenableFuture<Document> runCommandAsync(final String command)
 696  
             throws MongoDbException {
 697  1
         final FutureCallback<Document> future = new FutureCallback<Document>(
 698  
                 getLockType());
 699  
 
 700  1
         runCommandAsync(future, command, null);
 701  
 
 702  1
         return future;
 703  
     }
 704  
 
 705  
     /**
 706  
      * {@inheritDoc}
 707  
      * <p>
 708  
      * Overridden to call the
 709  
      * {@link #runCommandAsync(Callback, String, DocumentAssignable)} method.
 710  
      * </p>
 711  
      * 
 712  
      * @see #runCommandAsync(Callback, String, DocumentAssignable)
 713  
      */
 714  
     @Override
 715  
     public ListenableFuture<Document> runCommandAsync(final String command,
 716  
             final DocumentAssignable options) throws MongoDbException {
 717  13
         final FutureCallback<Document> future = new FutureCallback<Document>(
 718  
                 getLockType());
 719  
 
 720  13
         runCommandAsync(future, command, options);
 721  
 
 722  13
         return future;
 723  
     }
 724  
 
 725  
     /**
 726  
      * {@inheritDoc}
 727  
      * <p>
 728  
      * Overridden to call the
 729  
      * {@link #runCommandAsync(Callback, String, int, DocumentAssignable)}
 730  
      * method.
 731  
      * </p>
 732  
      * 
 733  
      * @see #runCommandAsync(Callback, String, int, DocumentAssignable)
 734  
      */
 735  
     @Override
 736  
     public ListenableFuture<Document> runCommandAsync(final String commandName,
 737  
             final int commandValue, final DocumentAssignable options)
 738  
             throws MongoDbException {
 739  15
         final FutureCallback<Document> future = new FutureCallback<Document>(
 740  
                 getLockType());
 741  
 
 742  15
         runCommandAsync(future, commandName, commandValue, options);
 743  
 
 744  15
         return future;
 745  
     }
 746  
 
 747  
     /**
 748  
      * {@inheritDoc}
 749  
      * <p>
 750  
      * Overridden to call the
 751  
      * {@link #runCommandAsync(Callback, String, String, DocumentAssignable)}
 752  
      * method.
 753  
      * </p>
 754  
      * 
 755  
      * @see #runCommandAsync(Callback, String, String, DocumentAssignable)
 756  
      */
 757  
     @Override
 758  
     public ListenableFuture<Document> runCommandAsync(final String commandName,
 759  
             final String commandValue, final DocumentAssignable options)
 760  
             throws MongoDbException {
 761  9
         final FutureCallback<Document> future = new FutureCallback<Document>(
 762  
                 getLockType());
 763  
 
 764  9
         runCommandAsync(future, commandName, commandValue, options);
 765  
 
 766  9
         return future;
 767  
     }
 768  
 
 769  
     /**
 770  
      * {@inheritDoc}
 771  
      */
 772  
     @Override
 773  
     public void setDurability(final Durability durability) {
 774  2
         myDurability = durability;
 775  2
     }
 776  
 
 777  
     /**
 778  
      * {@inheritDoc}
 779  
      * <p>
 780  
      * Overridden to update the databases profile level.
 781  
      * </p>
 782  
      * 
 783  
      * @see MongoDatabase#setProfilingStatus
 784  
      */
 785  
     @Override
 786  
     public boolean setProfilingStatus(final ProfilingStatus profileLevel)
 787  
             throws MongoDbException {
 788  9
         final Document result = runCommand(
 789  
                 "profile",
 790  
                 profileLevel.getLevel().getValue(),
 791  
                 BuilderFactory.start().add("slowms",
 792  
                         profileLevel.getSlowMillisThreshold()));
 793  
 
 794  9
         final NumericElement level = result.get(NumericElement.class, "was");
 795  9
         final NumericElement millis = result
 796  
                 .get(NumericElement.class, "slowms");
 797  
 
 798  9
         if ((level != null) && (millis != null)) {
 799  7
             final ProfilingStatus.Level l = ProfilingStatus.Level
 800  
                     .fromValue(level.getIntValue());
 801  7
             if (l != null) {
 802  6
                 switch (l) {
 803  
                 case NONE:
 804  2
                     return !ProfilingStatus.Level.NONE.equals(profileLevel
 805  
                             .getLevel());
 806  
                 case ALL:
 807  2
                     return !ProfilingStatus.Level.ALL.equals(profileLevel
 808  
                             .getLevel());
 809  
                 case SLOW_ONLY:
 810  2
                     final ProfilingStatus before = ProfilingStatus.slow(millis
 811  
                             .getIntValue());
 812  2
                     return !before.equals(profileLevel);
 813  
                 }
 814  
             }
 815  
         }
 816  
 
 817  
         // From undefined to defined is a change?
 818  3
         return true;
 819  
     }
 820  
 
 821  
     /**
 822  
      * {@inheritDoc}
 823  
      */
 824  
     @Override
 825  
     public void setReadPreference(final ReadPreference readPreference) {
 826  2
         myReadPreference = readPreference;
 827  2
     }
 828  
 
 829  
     /**
 830  
      * {@inheritDoc}
 831  
      * <p>
 832  
      * Overridden to send a {@code dbStats} command to the MongoDB server.
 833  
      * </p>
 834  
      * 
 835  
      * @see MongoDatabase#stats
 836  
      */
 837  
     @Override
 838  
     public Document stats() throws MongoDbException {
 839  1
         return runCommand("dbStats");
 840  
     }
 841  
 
 842  
     /**
 843  
      * Adds the options to the document builder.
 844  
      * 
 845  
      * @param command
 846  
      *            The command to make sure is removed from the options.
 847  
      * @param options
 848  
      *            The options to be added. May be <code>null</code>.
 849  
      * @param builder
 850  
      *            The builder to add the options to.
 851  
      */
 852  
     protected void addOptions(final String command,
 853  
             final DocumentAssignable options, final DocumentBuilder builder) {
 854  41
         if (options != null) {
 855  20
             for (final Element element : options.asDocument()) {
 856  25
                 if (!command.equals(element.getName())) {
 857  23
                     builder.add(element);
 858  
                 }
 859  25
             }
 860  
         }
 861  41
     }
 862  
 
 863  
     /**
 864  
      * Returns the type of lock to use.
 865  
      * 
 866  
      * @return The type of lock to use.
 867  
      */
 868  
     protected LockType getLockType() {
 869  42
         return myClient.getConfig().getLockType();
 870  
     }
 871  
 
 872  
     /**
 873  
      * Returns a {@link MongoDatabase} interface to the 'admin' database.
 874  
      * 
 875  
      * @return A reference to a {@link MongoDatabase} for interacting with the
 876  
      *         'admin' database.
 877  
      */
 878  
     private MongoDatabase getAdminDatabase() {
 879  7
         if (myAdminDatabase == null) {
 880  6
             if (myName.equals("admin")) {
 881  4
                 myAdminDatabase = this;
 882  
             }
 883  
             else {
 884  2
                 myAdminDatabase = myMongoClient.getDatabase("admin");
 885  
             }
 886  
         }
 887  
 
 888  7
         return myAdminDatabase;
 889  
     }
 890  
 }