Coverage Report - com.allanbank.mongodb.ReadPreference
 
Classes in this File Line Coverage Branch Coverage Complexity
ReadPreference
100%
122/122
92%
78/84
3.042
ReadPreference$Mode
100%
12/12
100%
2/2
3.042
 
 1  
 /*
 2  
  * #%L
 3  
  * ReadPreference.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;
 21  
 
 22  
 import java.io.Serializable;
 23  
 import java.util.ArrayList;
 24  
 import java.util.Collections;
 25  
 import java.util.Iterator;
 26  
 import java.util.List;
 27  
 
 28  
 import com.allanbank.mongodb.bson.Document;
 29  
 import com.allanbank.mongodb.bson.DocumentAssignable;
 30  
 import com.allanbank.mongodb.bson.Element;
 31  
 import com.allanbank.mongodb.bson.NumericElement;
 32  
 import com.allanbank.mongodb.bson.builder.ArrayBuilder;
 33  
 import com.allanbank.mongodb.bson.builder.BuilderFactory;
 34  
 import com.allanbank.mongodb.bson.builder.DocumentBuilder;
 35  
 
 36  
 /**
 37  
  * ReadPreference encapsulates a {@link Mode} and a set of tag matching
 38  
  * documents. The {@link Mode} specified if primary and/or secondary servers in
 39  
  * a replica set can be used and which should be tried first. The tag matching
 40  
  * documents control which secondary servers can be used.
 41  
  * <p>
 42  
  * Each tag matching document specified the minimum set of key/values that the
 43  
  * secondary server must be tagged with. As an example a tag matching document
 44  
  * of <code>{ a : 1, b : 2 }</code> would match a server with the tags
 45  
  * <code>{ a : 1, b : 2, c : 3 }</code> but would not match a server with tags
 46  
  * <code>{ a : 1, c : 3, d : 4 }</code>.
 47  
  * </p>
 48  
  * <p>
 49  
  * The tag matching documents and server tags must match exactly so a server
 50  
  * with tags <code>{ a: true, b : 2 }</code> would not match the
 51  
  * <code>{ a : 1, b : 2 }</code> tag matching document. Neither would a server
 52  
  * with the tags <code>{ c: 1, b : 2 }</code>.
 53  
  * </p>
 54  
  * </p> Each tag matching document specifies a disjoint condition so a server
 55  
  * has to match only one for the tag matching document. If the tag matching
 56  
  * documents <code>{ a : 1, b : 2 }</code> and <code>{ a : 1, c : 3 }</code> are
 57  
  * provided then both the server <code>{ a : 1, b : 2, c : 3 }</code> and
 58  
  * <code>{ a : 1, c : 3, d : 4 }</code> would match. </p>
 59  
  * <p>
 60  
  * If no tag matching documents are specified then all secondary servers may be
 61  
  * used.
 62  
  * </p>
 63  
  * 
 64  
  * @api.yes This class is part of the driver's API. Public and protected members
 65  
  *          will be deprecated for at least 1 non-bugfix release (version
 66  
  *          numbers are &lt;major&gt;.&lt;minor&gt;.&lt;bugfix&gt;) before being
 67  
  *          removed or modified.
 68  
  * @copyright 2012-2013, Allanbank Consulting, Inc., All Rights Reserved
 69  
  */
 70  
 public class ReadPreference implements Serializable, DocumentAssignable {
 71  
 
 72  
     /**
 73  
      * {@link ReadPreference} to read from the closest/{@link Mode#NEAREST}
 74  
      * primary of secondary server.
 75  
      */
 76  1
     public static final ReadPreference CLOSEST = new ReadPreference(
 77  
             Mode.NEAREST);
 78  
 
 79  
     /** The name of the field in the query document for the read preferences. */
 80  
     public static final String FIELD_NAME = "$readPreference";
 81  
 
 82  
     /**
 83  
      * {@link ReadPreference} to prefer reading from the primary but to fallback
 84  
      * to a secondary if the primary is not available.
 85  
      */
 86  1
     public static final ReadPreference PREFER_PRIMARY = new ReadPreference(
 87  
             Mode.PRIMARY_PREFERRED);
 88  
 
 89  
     /**
 90  
      * {@link ReadPreference} to prefer reading from a secondary but to
 91  
      * 'fallback' to a primary if a secondary is not available.
 92  
      */
 93  1
     public static final ReadPreference PREFER_SECONDARY = new ReadPreference(
 94  
             Mode.SECONDARY_PREFERRED);
 95  
 
 96  
     /** The default {@link ReadPreference} to read from the primary only. */
 97  1
     public static final ReadPreference PRIMARY = new ReadPreference(
 98  
             Mode.PRIMARY_ONLY);
 99  
 
 100  
     /**
 101  
      * {@link ReadPreference} to read only from a secondary but using any
 102  
      * secondary.
 103  
      */
 104  1
     public static final ReadPreference SECONDARY = new ReadPreference(
 105  
             Mode.SECONDARY_ONLY);
 106  
 
 107  
     /** The serialization version of the class. */
 108  
     private static final long serialVersionUID = -2135959854336511332L;
 109  
 
 110  
     /**
 111  
      * Creates a {@link ReadPreference} to read from the closest/
 112  
      * {@link Mode#NEAREST} primary of secondary server.
 113  
      * <p>
 114  
      * If tag matching documents are specified then only servers matching the
 115  
      * specified tag matching documents would be used.
 116  
      * </p>
 117  
      * <p>
 118  
      * If no tag matching documents are specified then returns {@link #CLOSEST}.
 119  
      * </p>
 120  
      * 
 121  
      * @param tagMatchDocuments
 122  
      *            Set of tag matching "documents" controlling which servers are
 123  
      *            used.
 124  
      * @return The creates {@link ReadPreference}.
 125  
      */
 126  
     public static ReadPreference closest(
 127  
             final DocumentAssignable... tagMatchDocuments) {
 128  16
         if (tagMatchDocuments.length == 0) {
 129  10
             return CLOSEST;
 130  
         }
 131  6
         return new ReadPreference(Mode.NEAREST, tagMatchDocuments);
 132  
     }
 133  
 
 134  
     /**
 135  
      * Creates a {@link ReadPreference} to prefer reading from the primary but
 136  
      * to fallback to a secondary if the primary is not available.
 137  
      * <p>
 138  
      * If tag matching documents are specified then only secondary servers
 139  
      * matching the specified tag matching documents would be used.
 140  
      * </p>
 141  
      * <p>
 142  
      * If no tag matching documents are specified then returns
 143  
      * {@link #PREFER_PRIMARY}.
 144  
      * </p>
 145  
      * 
 146  
      * @param tagMatchDocuments
 147  
      *            Set of tag matching "documents" controlling which secondary
 148  
      *            servers are used.
 149  
      * @return The creates {@link ReadPreference}.
 150  
      */
 151  
     public static ReadPreference preferPrimary(
 152  
             final DocumentAssignable... tagMatchDocuments) {
 153  15
         if (tagMatchDocuments.length == 0) {
 154  7
             return PREFER_PRIMARY;
 155  
         }
 156  8
         return new ReadPreference(Mode.PRIMARY_PREFERRED, tagMatchDocuments);
 157  
     }
 158  
 
 159  
     /**
 160  
      * Creates a {@link ReadPreference} to prefer reading from a secondary but
 161  
      * to 'fallback' to a primary if a secondary is not available.
 162  
      * <p>
 163  
      * If tag matching documents are specified then only secondary servers
 164  
      * matching the specified tag matching documents would be used.
 165  
      * </p>
 166  
      * <p>
 167  
      * If no tag matching documents are specified then returns
 168  
      * {@link #PREFER_SECONDARY}.
 169  
      * </p>
 170  
      * 
 171  
      * @param tagMatchDocuments
 172  
      *            Set of tag matching "documents" controlling which secondary
 173  
      *            servers are used.
 174  
      * @return The creates {@link ReadPreference}.
 175  
      */
 176  
     public static ReadPreference preferSecondary(
 177  
             final DocumentAssignable... tagMatchDocuments) {
 178  22
         if (tagMatchDocuments.length == 0) {
 179  16
             return PREFER_SECONDARY;
 180  
         }
 181  6
         return new ReadPreference(Mode.SECONDARY_PREFERRED, tagMatchDocuments);
 182  
     }
 183  
 
 184  
     /**
 185  
      * Returns the default {@link ReadPreference} to read from the primary only:
 186  
      * {@link #PRIMARY}.
 187  
      * 
 188  
      * @return The {@link #PRIMARY} {@link ReadPreference}.
 189  
      */
 190  
     public static ReadPreference primary() {
 191  8
         return PRIMARY;
 192  
     }
 193  
 
 194  
     /**
 195  
      * Creates a {@link ReadPreference} to read only from a secondary.
 196  
      * <p>
 197  
      * If tag matching documents are specified then only secondary servers
 198  
      * matching the specified tag matching documents would be used.
 199  
      * </p>
 200  
      * <p>
 201  
      * If no tag matching documents are specified then returns
 202  
      * {@link #PREFER_SECONDARY}.
 203  
      * </p>
 204  
      * 
 205  
      * @param tagMatchDocuments
 206  
      *            Set of tag matching "documents" controlling which secondary
 207  
      *            servers are used.
 208  
      * @return The creates {@link ReadPreference}.
 209  
      */
 210  
     public static ReadPreference secondary(
 211  
             final DocumentAssignable... tagMatchDocuments) {
 212  37
         if (tagMatchDocuments.length == 0) {
 213  26
             return SECONDARY;
 214  
         }
 215  11
         return new ReadPreference(Mode.SECONDARY_ONLY, tagMatchDocuments);
 216  
     }
 217  
 
 218  
     /**
 219  
      * Creates a {@link ReadPreference} to read only from a specific server.
 220  
      * <p>
 221  
      * Used by the {@link MongoIterator} to ensure cursor fetch and terminate
 222  
      * requests use the originating server.
 223  
      * </p>
 224  
      * <p>
 225  
      * <b>Note:</b> Use this form of {@link ReadPreference} with caution. If the
 226  
      * specified server fails all requests will fail.
 227  
      * </p>
 228  
      * 
 229  
      * @param address
 230  
      *            The server to read from.
 231  
      * @return The creates {@link ReadPreference}.
 232  
      */
 233  
     public static ReadPreference server(final String address) {
 234  79
         return new ReadPreference(Mode.SERVER, address);
 235  
     }
 236  
 
 237  
     /** The document form for the ReadPreference. */
 238  
     private final Document myDocumentForm;
 239  
 
 240  
     /**
 241  
      * The read preference mode controlling if primary or secondary servers can
 242  
      * be used and which to prefer.
 243  
      */
 244  
     private final Mode myMode;
 245  
 
 246  
     /**
 247  
      * The server to read from. Used by the {@link MongoIterator} to ensure
 248  
      * cursor fetch and terminate requests use the originating server.
 249  
      */
 250  
     private final String myServer;
 251  
 
 252  
     /** The list of tag matching documents to control the secondaries used. */
 253  
     private final List<Document> myTagMatchingDocuments;
 254  
 
 255  
     /**
 256  
      * Creates a new ReadPreference.
 257  
      * 
 258  
      * @param mode
 259  
      *            The read preference mode controlling if primary or secondary
 260  
      *            servers can be used and which to prefer.
 261  
      * @param tagMatchDocuments
 262  
      *            Set of tag matching "documents" controlling which secondary
 263  
      *            servers are used.
 264  
      */
 265  
     protected ReadPreference(final Mode mode,
 266  162
             final DocumentAssignable... tagMatchDocuments) {
 267  162
         final DocumentBuilder builder = BuilderFactory.start();
 268  162
         builder.addString("mode", mode.getToken());
 269  
 
 270  162
         myMode = mode;
 271  162
         myServer = null;
 272  162
         if (tagMatchDocuments.length == 0) {
 273  23
             myTagMatchingDocuments = Collections.emptyList();
 274  
         }
 275  
         else {
 276  139
             myTagMatchingDocuments = new ArrayList<Document>(
 277  
                     tagMatchDocuments.length);
 278  
 
 279  139
             final ArrayBuilder tagsBuilder = builder.pushArray("tags");
 280  401
             for (final DocumentAssignable assignable : tagMatchDocuments) {
 281  262
                 final Document tags = assignable.asDocument();
 282  
 
 283  262
                 myTagMatchingDocuments.add(tags);
 284  262
                 tagsBuilder.addDocument(tags);
 285  
             }
 286  
         }
 287  
 
 288  162
         myDocumentForm = builder.build();
 289  162
     }
 290  
 
 291  
     /**
 292  
      * Creates a new ReadPreference.
 293  
      * 
 294  
      * @param mode
 295  
      *            The read preference mode controlling if primary or secondary
 296  
      *            servers can be used and which to prefer.
 297  
      * @param address
 298  
      *            The server to read from.
 299  
      */
 300  79
     protected ReadPreference(final Mode mode, final String address) {
 301  79
         myMode = mode;
 302  79
         myServer = address;
 303  79
         myTagMatchingDocuments = Collections.emptyList();
 304  
 
 305  79
         final DocumentBuilder builder = BuilderFactory.start();
 306  79
         builder.addString("mode", mode.getToken());
 307  79
         if (address != null) {
 308  79
             builder.addString("server", address);
 309  
         }
 310  79
         myDocumentForm = builder.build();
 311  
 
 312  79
     }
 313  
 
 314  
     /**
 315  
      * {@inheritDoc}
 316  
      * <p>
 317  
      * Overridden to return the read preference document.
 318  
      * </p>
 319  
      * <p>
 320  
      * The document contains:
 321  
      * <ul>
 322  
      * <li>The {@code mode} string value as returned by {@link Mode#getToken()}.
 323  
      * </li>
 324  
      * <li>An optional {@code tags} array containing the
 325  
      * {@link #getTagMatchingDocuments() tag matching documents}</li>
 326  
      * <li>An optional {@code server} containing the server to read from. This
 327  
      * should only used for cursors to ensure the correct server is used to
 328  
      * request more documents.</li>
 329  
      * </ul>
 330  
      * </p>
 331  
      */
 332  
     @Override
 333  
     public Document asDocument() {
 334  28
         return myDocumentForm;
 335  
     }
 336  
 
 337  
     /**
 338  
      * Determines if the passed object is of this same type as this object and
 339  
      * if so that its fields are equal.
 340  
      * 
 341  
      * @param object
 342  
      *            The object to compare to.
 343  
      * 
 344  
      * @see java.lang.Object#equals(java.lang.Object)
 345  
      */
 346  
     @Override
 347  
     public boolean equals(final Object object) {
 348  68216
         boolean result = false;
 349  68216
         if (this == object) {
 350  53311
             result = true;
 351  
         }
 352  14905
         else if ((object != null) && (getClass() == object.getClass())) {
 353  14869
             final ReadPreference other = (ReadPreference) object;
 354  
 
 355  14869
             result = myMode.equals(other.myMode)
 356  
                     && myTagMatchingDocuments
 357  
                             .equals(other.myTagMatchingDocuments)
 358  
                     && nullSafeEquals(myServer, other.myServer);
 359  
         }
 360  68216
         return result;
 361  
     }
 362  
 
 363  
     /**
 364  
      * Returns the read preference mode controlling if primary or secondary
 365  
      * servers can be used and which to prefer.
 366  
      * 
 367  
      * @return The read preference mode controlling if primary or secondary
 368  
      *         servers can be used and which to prefer.
 369  
      */
 370  
     public Mode getMode() {
 371  68
         return myMode;
 372  
     }
 373  
 
 374  
     /**
 375  
      * Returns the server to read from. Used by the {@link MongoIterator} to
 376  
      * ensure cursor fetch and terminate requests use the originating server.
 377  
      * 
 378  
      * @return The server to read from.
 379  
      */
 380  
     public String getServer() {
 381  19
         return myServer;
 382  
     }
 383  
 
 384  
     /**
 385  
      * Returns the list of tag matching documents to control the secondaries
 386  
      * used.
 387  
      * 
 388  
      * @return The list of tag matching documents to control the secondaries
 389  
      *         used.
 390  
      */
 391  
     public List<Document> getTagMatchingDocuments() {
 392  17
         return myTagMatchingDocuments;
 393  
     }
 394  
 
 395  
     /**
 396  
      * Computes a reasonable hash code.
 397  
      * 
 398  
      * @return The hash code value.
 399  
      */
 400  
     @Override
 401  
     public int hashCode() {
 402  5875066
         int result = 1;
 403  5875066
         result = (31 * result) + myMode.ordinal();
 404  5875066
         result = (31 * result) + myTagMatchingDocuments.hashCode();
 405  5875066
         return result;
 406  
     }
 407  
 
 408  
     /**
 409  
      * Returns true if the read preference is compatible with the legacy
 410  
      * "slaveOk", e.g., is one of {@link Mode#PRIMARY_ONLY},
 411  
      * {@link Mode#SECONDARY_ONLY}, or {@link Mode#SERVER} and has no tag
 412  
      * matching documents.
 413  
      * 
 414  
      * @return True if the mode allows reading from secondaries, false
 415  
      *         otherwise.
 416  
      */
 417  
     public boolean isLegacy() {
 418  136
         return ((myMode == Mode.PRIMARY_ONLY)
 419  
                 || (myMode == Mode.SECONDARY_ONLY) || (myMode == Mode.SERVER))
 420  
                 && myTagMatchingDocuments.isEmpty();
 421  
     }
 422  
 
 423  
     /**
 424  
      * Returns true if the mode allows reading from secondaries, false
 425  
      * otherwise.
 426  
      * 
 427  
      * @return True if the mode allows reading from secondaries, false
 428  
      *         otherwise.
 429  
      */
 430  
     public boolean isSecondaryOk() {
 431  744
         return myMode.isSecondaryOk();
 432  
     }
 433  
 
 434  
     /**
 435  
      * Returns true if this {@link ReadPreference} matches the <tt>tags</tt>
 436  
      * document.
 437  
      * 
 438  
      * @param tags
 439  
      *            The tags to be matched against.
 440  
      * @return True if this {@link ReadPreference} matches the tags, false
 441  
      *         otherwise.
 442  
      */
 443  
     public boolean matches(final Document tags) {
 444  214
         if (myTagMatchingDocuments.isEmpty()) {
 445  106
             return true;
 446  
         }
 447  
 
 448  108
         boolean matches = false;
 449  108
         final Iterator<Document> tagMatchingDocIter = myTagMatchingDocuments
 450  
                 .iterator();
 451  324
         while (tagMatchingDocIter.hasNext() && !matches) {
 452  216
             final Document tagMatchingDoc = tagMatchingDocIter.next();
 453  
 
 454  216
             if (tags == null) {
 455  46
                 if (!tagMatchingDoc.iterator().hasNext()) {
 456  
                     // Empty tag document matches all.
 457  6
                     matches = true;
 458  
                 }
 459  
             }
 460  
             else {
 461  170
                 matches = true;
 462  170
                 final Iterator<Element> tagMatchingElemIter = tagMatchingDoc
 463  
                         .iterator();
 464  340
                 while (tagMatchingElemIter.hasNext() && matches) {
 465  170
                     final Element tagMatchingElem = tagMatchingElemIter.next();
 466  170
                     final Element tag = tags.get(tagMatchingElem.getName());
 467  
 
 468  
                     // Note tag may be null...
 469  170
                     if (!fuzzyEquals(tagMatchingElem, tag)) {
 470  123
                         matches = false;
 471  
                     }
 472  170
                 }
 473  
             }
 474  216
         }
 475  
 
 476  108
         return matches;
 477  
     }
 478  
 
 479  
     /**
 480  
      * {@inheritDoc}
 481  
      * <p>
 482  
      * Overridden to return a string representation of the read preference..
 483  
      * </p>
 484  
      */
 485  
     @Override
 486  
     public String toString() {
 487  2281
         final StringBuilder builder = new StringBuilder();
 488  
 
 489  2281
         builder.append(myMode.name());
 490  
 
 491  2281
         if (myServer != null) {
 492  3
             builder.append('[');
 493  3
             builder.append(myServer);
 494  3
             builder.append(']');
 495  
         }
 496  2278
         else if (!myTagMatchingDocuments.isEmpty()) {
 497  2
             builder.append('[');
 498  2
             boolean first = true;
 499  2
             for (final Document tagDoc : myTagMatchingDocuments) {
 500  3
                 if (!first) {
 501  1
                     builder.append(", ");
 502  
                 }
 503  3
                 first = false;
 504  
 
 505  3
                 builder.append('{');
 506  3
                 boolean firstElem = true;
 507  3
                 for (final Element element : tagDoc) {
 508  4
                     if (!firstElem) {
 509  1
                         builder.append(", ");
 510  
                     }
 511  4
                     firstElem = false;
 512  
 
 513  4
                     builder.append(element);
 514  4
                 }
 515  3
                 builder.append('}');
 516  3
             }
 517  2
             builder.append(']');
 518  
         }
 519  
 
 520  2281
         return builder.toString();
 521  
     }
 522  
 
 523  
     /**
 524  
      * Does a null safe equals comparison.
 525  
      * 
 526  
      * @param rhs
 527  
      *            The right-hand-side of the comparison.
 528  
      * @param lhs
 529  
      *            The left-hand-side of the comparison.
 530  
      * @return True if the rhs equals the lhs. Note: nullSafeEquals(null, null)
 531  
      *         returns true.
 532  
      */
 533  
     protected boolean nullSafeEquals(final Object rhs, final Object lhs) {
 534  39
         return (rhs == lhs) || ((rhs != null) && rhs.equals(lhs));
 535  
     }
 536  
 
 537  
     /**
 538  
      * Compares if the two elements are equals allowing numeric values type to
 539  
      * not be a strict match but when casted as a long those values must still
 540  
      * compare equal.
 541  
      * 
 542  
      * @param lhs
 543  
      *            The first element to compare. May not be <code>null</code>.
 544  
      * @param rhs
 545  
      *            The second element to compare. May be <code>null</code>.
 546  
      * @return True if the two elements compare equal ignore two
 547  
      *         {@link NumericElement}s' specific type.
 548  
      */
 549  
     private boolean fuzzyEquals(final Element lhs, final Element rhs) {
 550  
         // Be fuzzy on the integer/long/double.
 551  170
         if ((rhs instanceof NumericElement) && (lhs instanceof NumericElement)) {
 552  53
             final long tagValue = ((NumericElement) rhs).getLongValue();
 553  53
             final long tagMatchingValue = ((NumericElement) lhs).getLongValue();
 554  53
             return (tagValue == tagMatchingValue);
 555  
         }
 556  
 
 557  
         // Otherwise exact match.
 558  117
         return lhs.equals(rhs);
 559  
     }
 560  
 
 561  
     /**
 562  
      * Hook into serialization to replace <tt>this</tt> object with the local
 563  
      * {@link #CLOSEST}, {@link #PREFER_PRIMARY}, {@link #PREFER_SECONDARY},
 564  
      * {@link #PRIMARY}, or {@link #SECONDARY} instance as appropriate.
 565  
      * 
 566  
      * @return Either the {@link #CLOSEST}, {@link #PREFER_PRIMARY},
 567  
      *         {@link #PREFER_SECONDARY}, {@link #PRIMARY}, or
 568  
      *         {@link #SECONDARY} instance if <tt>this</tt> instance equals one
 569  
      *         of those instances otherwise <tt>this</tt> instance.
 570  
      */
 571  
     private Object readResolve() {
 572  7
         if (this.equals(CLOSEST)) {
 573  1
             return CLOSEST;
 574  
         }
 575  6
         else if (this.equals(PREFER_PRIMARY)) {
 576  1
             return PREFER_PRIMARY;
 577  
         }
 578  5
         else if (this.equals(PREFER_SECONDARY)) {
 579  1
             return PREFER_SECONDARY;
 580  
         }
 581  4
         else if (this.equals(PRIMARY)) {
 582  2
             return PRIMARY;
 583  
         }
 584  2
         else if (this.equals(SECONDARY)) {
 585  1
             return SECONDARY;
 586  
         }
 587  
         else {
 588  1
             return this;
 589  
         }
 590  
     }
 591  
 
 592  
     /**
 593  
      * Enumeration of the basic {@link ReadPreference} modes of service.
 594  
      * 
 595  
      * @copyright 2012-2013, Allanbank Consulting, Inc., All Rights Reserved
 596  
      */
 597  31
     public static enum Mode {
 598  
         /**
 599  
          * Use the nearest (by latency measurement) member of the replica set:
 600  
          * either primary or secondary servers are allowed.
 601  
          * <p>
 602  
          * If tag matching documents are specified then only server matching the
 603  
          * specified tag matching documents would be used.
 604  
          * </p>
 605  
          */
 606  1
         NEAREST("nearest"),
 607  
 
 608  
         /**
 609  
          * Reads should only be attempted from the primary member of the replica
 610  
          * set.
 611  
          */
 612  1
         PRIMARY_ONLY("primary"),
 613  
 
 614  
         /**
 615  
          * Read from the primary but in the case of a fault may fallback to a
 616  
          * secondary.
 617  
          * <p>
 618  
          * If tag matching documents are specified and a fallback to a secondary
 619  
          * is required then only secondaries matching the specified tag matching
 620  
          * documents would be used.
 621  
          * </p>
 622  
          */
 623  1
         PRIMARY_PREFERRED("primaryPreferred"),
 624  
 
 625  
         /**
 626  
          * Do not attempt to read from the primary.
 627  
          * <p>
 628  
          * If tag matching documents are specified then only secondaries
 629  
          * matching the specified tag matching documents would be used.
 630  
          * </p>
 631  
          */
 632  1
         SECONDARY_ONLY("secondary"),
 633  
 
 634  
         /**
 635  
          * Try to first read from a secondary. If none are available "fallback"
 636  
          * to the primary.
 637  
          * <p>
 638  
          * If tag matching documents are specified then only secondaries
 639  
          * matching the specified tag matching documents would be used.
 640  
          * </p>
 641  
          */
 642  1
         SECONDARY_PREFERRED("secondaryPreferred"),
 643  
 
 644  
         /**
 645  
          * Do not attempt to read from any server other than the one specified.
 646  
          * Used by the {@link MongoIterator} to ensure cursor fetch and
 647  
          * terminate requests use the originating server.
 648  
          */
 649  1
         SERVER("server");
 650  
 
 651  
         /** The token passed to the mongos server when in a shared environment. */
 652  
         private final String myToken;
 653  
 
 654  
         /**
 655  
          * Creates a new Mode.
 656  
          * 
 657  
          * @param token
 658  
          *            The token passed to the mongos server when in a shared
 659  
          *            environment.
 660  
          */
 661  6
         private Mode(final String token) {
 662  6
             myToken = token;
 663  6
         }
 664  
 
 665  
         /**
 666  
          * Returns the token passed to the mongos server when in a shared
 667  
          * environment.
 668  
          * 
 669  
          * @return The token passed to the mongos server when in a shared
 670  
          *         environment.
 671  
          */
 672  
         public String getToken() {
 673  242
             return myToken;
 674  
         }
 675  
 
 676  
         /**
 677  
          * Returns true if the mode allows reading from secondaries, false
 678  
          * otherwise.
 679  
          * 
 680  
          * @return True if the mode allows reading from secondaries, false
 681  
          *         otherwise.
 682  
          */
 683  
         public boolean isSecondaryOk() {
 684  744
             return (this != PRIMARY_ONLY);
 685  
         }
 686  
     }
 687  
 }