Coverage Report - com.allanbank.mongodb.client.MongoClientImpl
 
Classes in this File Line Coverage Branch Coverage Complexity
MongoClientImpl
90%
39/43
72%
13/18
1.833
 
 1  
 /*
 2  
  * #%L
 3  
  * MongoClientImpl.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.List;
 26  
 import java.util.concurrent.ConcurrentHashMap;
 27  
 import java.util.concurrent.ConcurrentMap;
 28  
 
 29  
 import com.allanbank.mongodb.LambdaCallback;
 30  
 import com.allanbank.mongodb.MongoClient;
 31  
 import com.allanbank.mongodb.MongoClientConfiguration;
 32  
 import com.allanbank.mongodb.MongoCursorControl;
 33  
 import com.allanbank.mongodb.MongoDatabase;
 34  
 import com.allanbank.mongodb.MongoIterator;
 35  
 import com.allanbank.mongodb.StreamCallback;
 36  
 import com.allanbank.mongodb.bson.Document;
 37  
 import com.allanbank.mongodb.bson.DocumentAssignable;
 38  
 import com.allanbank.mongodb.bson.element.StringElement;
 39  
 
 40  
 /**
 41  
  * Implements the bootstrap point for interactions with MongoDB.
 42  
  * 
 43  
  * @api.no This class is <b>NOT</b> part of the drivers API. This class may be
 44  
  *         mutated in incompatible ways between any two releases of the driver.
 45  
  * @copyright 2011-2013, Allanbank Consulting, Inc., All Rights Reserved
 46  
  */
 47  
 public class MongoClientImpl implements MongoClient {
 48  
 
 49  
     /** The client to interact with MongoDB. */
 50  
     private final Client myClient;
 51  
 
 52  
     /** The set of databases in use. */
 53  
     private final ConcurrentMap<String, Reference<MongoDatabase>> myDatabases;
 54  
 
 55  
     /** The queue of references to the databases that have been reclaimed. */
 56  32
     private final ReferenceQueue<MongoDatabase> myReferenceQueue = new ReferenceQueue<MongoDatabase>();
 57  
 
 58  
     /**
 59  
      * Create a new MongoClient.
 60  
      * 
 61  
      * @param client
 62  
      *            The client interface for interacting with the database.
 63  
      */
 64  32
     public MongoClientImpl(final Client client) {
 65  32
         myClient = client;
 66  
 
 67  32
         myDatabases = new ConcurrentHashMap<String, Reference<MongoDatabase>>();
 68  32
     }
 69  
 
 70  
     /**
 71  
      * Create a new MongoClient.
 72  
      * 
 73  
      * @param config
 74  
      *            The configuration for interacting with MongoDB.
 75  
      */
 76  
     public MongoClientImpl(final MongoClientConfiguration config) {
 77  12
         this(new ClientImpl(config));
 78  12
     }
 79  
 
 80  
     /**
 81  
      * {@inheritDoc}
 82  
      * <p>
 83  
      * Overridden to create a new Mongo instance around a SerialClientImpl.
 84  
      * </p>
 85  
      */
 86  
     @Override
 87  
     public MongoClient asSerializedClient() {
 88  4
         if (myClient instanceof SerialClientImpl) {
 89  2
             return this;
 90  
         }
 91  
 
 92  2
         return new MongoClientImpl(new SerialClientImpl((ClientImpl) myClient));
 93  
     }
 94  
 
 95  
     /**
 96  
      * {@inheritDoc}
 97  
      * <p>
 98  
      * Overridden to close the underlying client.
 99  
      * </p>
 100  
      */
 101  
     @Override
 102  
     public void close() {
 103  7
         myClient.close();
 104  7
     }
 105  
 
 106  
     /**
 107  
      * Returns the client value.
 108  
      * 
 109  
      * @return The client value.
 110  
      */
 111  
     public Client getClient() {
 112  13
         return myClient;
 113  
     }
 114  
 
 115  
     /**
 116  
      * {@inheritDoc}
 117  
      * <p>
 118  
      * Overridden to return the clients configuration.
 119  
      * </p>
 120  
      */
 121  
     @Override
 122  
     public MongoClientConfiguration getConfig() {
 123  2
         return myClient.getConfig();
 124  
     }
 125  
 
 126  
     /**
 127  
      * {@inheritDoc}
 128  
      * <p>
 129  
      * Overridden to create a {@link MongoDatabase} instance with the given
 130  
      * name.
 131  
      * </p>
 132  
      * 
 133  
      * @see MongoClient#getDatabase(String)
 134  
      */
 135  
     @Override
 136  
     public MongoDatabase getDatabase(final String name) {
 137  32
         MongoDatabase database = null;
 138  32
         Reference<MongoDatabase> ref = myDatabases.get(name);
 139  32
         if (ref != null) {
 140  7
             database = ref.get();
 141  7
             if (database == null) {
 142  
                 // Reference was take n from the map. Remove it from the map.
 143  0
                 myDatabases.remove(name, ref);
 144  
             }
 145  
         }
 146  
 
 147  
         // Create a new one.
 148  32
         if (database == null) {
 149  25
             database = new MongoDatabaseImpl(this, myClient, name);
 150  25
             ref = new NamedReference<MongoDatabase>(name, database,
 151  
                     myReferenceQueue);
 152  
 
 153  25
             final Reference<MongoDatabase> existing = myDatabases.putIfAbsent(
 154  
                     name, ref);
 155  25
             if (existing != null) {
 156  0
                 final MongoDatabase existingDb = existing.get();
 157  0
                 if (existingDb != null) {
 158  0
                     database = existingDb;
 159  
                 }
 160  
                 // else ... Extremely unlikely but if the reference came and
 161  
                 // went that quick it is the next guys problem to add one. We
 162  
                 // will return the one we created.
 163  
             }
 164  
         }
 165  
 
 166  
         // Clean out any garbage collected references.
 167  
         Reference<?> polled;
 168  45
         while ((polled = myReferenceQueue.poll()) != null) {
 169  13
             if (polled instanceof NamedReference) {
 170  13
                 myDatabases.remove(((NamedReference<?>) polled).getName(),
 171  
                         polled);
 172  
             }
 173  
         }
 174  
 
 175  32
         return database;
 176  
     }
 177  
 
 178  
     /**
 179  
      * {@inheritDoc}
 180  
      * <p>
 181  
      * Overridden to issue a listDatabases command against the 'admin' database.
 182  
      * </p>
 183  
      * 
 184  
      * @see com.allanbank.mongodb.Mongo#listDatabaseNames()
 185  
      */
 186  
     @Override
 187  
     public List<String> listDatabaseNames() {
 188  
 
 189  3
         final MongoDatabase db = getDatabase("admin");
 190  3
         final Document result = db.runAdminCommand("listDatabases");
 191  
 
 192  3
         final List<String> names = new ArrayList<String>();
 193  3
         for (final StringElement nameElement : result.find(StringElement.class,
 194  
                 "databases", ".*", "name")) {
 195  
 
 196  6
             names.add(nameElement.getValue());
 197  6
         }
 198  
 
 199  3
         return names;
 200  
     }
 201  
 
 202  
     /**
 203  
      * {@inheritDoc}
 204  
      */
 205  
     @Override
 206  
     @Deprecated
 207  
     public List<String> listDatabases() {
 208  1
         return listDatabaseNames();
 209  
     }
 210  
 
 211  
     /**
 212  
      * Restarts an iterator that was previously saved.
 213  
      * 
 214  
      * @param cursorDocument
 215  
      *            The document containing the state of the cursor.
 216  
      * @return The restarted iterator.
 217  
      * @throws IllegalArgumentException
 218  
      *             If the document does not contain a valid cursor state.
 219  
      */
 220  
     @Override
 221  
     public MongoIterator<Document> restart(
 222  
             final DocumentAssignable cursorDocument)
 223  
             throws IllegalArgumentException {
 224  1
         return myClient.restart(cursorDocument);
 225  
     }
 226  
 
 227  
     /**
 228  
      * {@inheritDoc}
 229  
      * <p>
 230  
      * Overridden to call {@link #restart(StreamCallback, DocumentAssignable)}
 231  
      * with an adapter for the {@link LambdaCallback}.
 232  
      * </p>
 233  
      */
 234  
     @Override
 235  
     public MongoCursorControl restart(final LambdaCallback<Document> results,
 236  
             final DocumentAssignable cursorDocument)
 237  
             throws IllegalArgumentException {
 238  1
         return restart(new LambdaCallbackAdapter<Document>(results),
 239  
                 cursorDocument);
 240  
     }
 241  
 
 242  
     /**
 243  
      * Restarts a document stream from a cursor that was previously saved.
 244  
      * 
 245  
      * @param results
 246  
      *            Callback that will be notified of the results of the cursor.
 247  
      * @param cursorDocument
 248  
      *            The document containing the state of the cursor.
 249  
      * @throws IllegalArgumentException
 250  
      *             If the document does not contain a valid cursor state.
 251  
      */
 252  
     @Override
 253  
     public MongoCursorControl restart(final StreamCallback<Document> results,
 254  
             final DocumentAssignable cursorDocument)
 255  
             throws IllegalArgumentException {
 256  2
         return myClient.restart(results, cursorDocument);
 257  
     }
 258  
 }