Coverage Report - com.allanbank.mongodb.ReadPreferenceEditor
 
Classes in this File Line Coverage Branch Coverage Complexity
ReadPreferenceEditor
100%
91/91
98%
51/52
9.25
ReadPreferenceEditor$1
100%
1/1
N/A
9.25
 
 1  
 /*
 2  
  * #%L
 3  
  * ReadPreferenceEditor.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.beans.PropertyEditorSupport;
 23  
 import java.util.ArrayList;
 24  
 import java.util.Collections;
 25  
 import java.util.HashSet;
 26  
 import java.util.List;
 27  
 import java.util.Map;
 28  
 import java.util.Set;
 29  
 
 30  
 import com.allanbank.mongodb.bson.Document;
 31  
 import com.allanbank.mongodb.bson.DocumentAssignable;
 32  
 import com.allanbank.mongodb.bson.Element;
 33  
 import com.allanbank.mongodb.bson.element.DocumentElement;
 34  
 import com.allanbank.mongodb.bson.impl.RootDocument;
 35  
 import com.allanbank.mongodb.bson.json.Json;
 36  
 import com.allanbank.mongodb.error.JsonException;
 37  
 import com.allanbank.mongodb.util.log.Log;
 38  
 import com.allanbank.mongodb.util.log.LogFactory;
 39  
 
 40  
 /**
 41  
  * {@link java.beans.PropertyEditor} for the {@link ReadPreference} class.
 42  
  * <p>
 43  
  * The string value must be one of the following tokens or a parsable JSON
 44  
  * document in the form of {@link ReadPreference#asDocument()}.
 45  
  * </p>
 46  
  * </p> Valid tokens are:
 47  
  * <ul>
 48  
  * <li>{@code PRIMARY}</li>
 49  
  * <li>{@code SECONDARY}</li>
 50  
  * <li>{@code CLOSEST}</li>
 51  
  * <li>{@code NEAREST}</li>
 52  
  * <li>{@code PREFER_PRIMARY}</li>
 53  
  * <li>{@code PREFER_SECONDARY}</li>
 54  
  * </ul>
 55  
  * <p>
 56  
  * This editor will also parse a full MongoDB URI to extract the specified
 57  
  * {@link ReadPreference}. See the <a href=
 58  
  * "http://docs.mongodb.org/manual/reference/connection-string/#read-preference-options"
 59  
  * >Connection String URI Format</a> documentation for information on
 60  
  * constructing a MongoDB URI.
 61  
  * </p>
 62  
  * 
 63  
  * @api.yes This class is part of the driver's API. Public and protected members
 64  
  *          will be deprecated for at least 1 non-bugfix release (version
 65  
  *          numbers are &lt;major&gt;.&lt;minor&gt;.&lt;bugfix&gt;) before being
 66  
  *          removed or modified.
 67  
  * @copyright 2013-2014, Allanbank Consulting, Inc., All Rights Reserved
 68  
  */
 69  
 public class ReadPreferenceEditor extends PropertyEditorSupport {
 70  
 
 71  
     /** The set of fields used to determine a Durability from a MongoDB URI. */
 72  
     public static final Set<String> MONGODB_URI_FIELDS;
 73  
 
 74  
     /** The logger for the {@link ReadPreferenceEditor}. */
 75  1
     protected static final Log LOG = LogFactory
 76  
             .getLog(ReadPreferenceEditor.class);
 77  
 
 78  
     /** Any empty array for tags. */
 79  1
     private static final DocumentAssignable[] EMPTY_TAGS = new DocumentAssignable[0];
 80  
 
 81  
     static {
 82  1
         final Set<String> fields = new HashSet<String>();
 83  1
         fields.add("readpreferencetags");
 84  1
         fields.add("readpreference");
 85  1
         fields.add("slaveok");
 86  
 
 87  1
         MONGODB_URI_FIELDS = Collections.unmodifiableSet(fields);
 88  1
     }
 89  
 
 90  
     /**
 91  
      * Creates a new ReadPreferenceEditor.
 92  
      */
 93  
     public ReadPreferenceEditor() {
 94  32
         super();
 95  32
     }
 96  
 
 97  
     /**
 98  
      * {@inheritDoc}
 99  
      * <p>
 100  
      * Overridden to parse a string to a {@link ReadPreference}.
 101  
      * </p>
 102  
      * 
 103  
      * @throws IllegalArgumentException
 104  
      *             If the string cannot be parsed into a {@link ReadPreference}.
 105  
      */
 106  
     @Override
 107  
     public void setAsText(final String readPreferenceString)
 108  
             throws IllegalArgumentException {
 109  33
         if ("PRIMARY".equalsIgnoreCase(readPreferenceString)) {
 110  1
             setValue(ReadPreference.primary());
 111  
         }
 112  32
         else if ("SECONDARY".equalsIgnoreCase(readPreferenceString)) {
 113  1
             setValue(ReadPreference.secondary());
 114  
         }
 115  31
         else if ("CLOSEST".equalsIgnoreCase(readPreferenceString)) {
 116  1
             setValue(ReadPreference.closest());
 117  
         }
 118  30
         else if ("NEAREST".equalsIgnoreCase(readPreferenceString)) {
 119  1
             setValue(ReadPreference.closest());
 120  
         }
 121  29
         else if ("PREFER_PRIMARY".equalsIgnoreCase(readPreferenceString)) {
 122  1
             setValue(ReadPreference.preferPrimary());
 123  
         }
 124  28
         else if ("PREFER_SECONDARY".equalsIgnoreCase(readPreferenceString)) {
 125  1
             setValue(ReadPreference.preferSecondary());
 126  
         }
 127  27
         else if (MongoDbUri.isUri(readPreferenceString)) {
 128  14
             final MongoDbUri uri = new MongoDbUri(readPreferenceString);
 129  14
             final ReadPreference parsed = fromUriParameters(uri);
 130  14
             if (parsed != null) {
 131  12
                 setValue(parsed);
 132  
             }
 133  14
         }
 134  
         else {
 135  
             // JSON Document?
 136  
             ReadPreference prefs;
 137  
             try {
 138  13
                 prefs = null;
 139  
 
 140  13
                 final Document doc = Json.parse(readPreferenceString);
 141  12
                 final List<DocumentElement> tagDocs = doc.find(
 142  
                         DocumentElement.class, "tags", ".*");
 143  12
                 final Document[] tagArray = new Document[tagDocs.size()];
 144  20
                 for (int i = 0; i < tagArray.length; ++i) {
 145  8
                     tagArray[i] = new RootDocument(tagDocs.get(i).getElements());
 146  
                 }
 147  
 
 148  12
                 final Element modeElement = doc.get("mode");
 149  12
                 if (modeElement != null) {
 150  11
                     final String token = modeElement.getValueAsString();
 151  11
                     final ReadPreference.Mode mode = ReadPreference.Mode
 152  
                             .valueOf(token);
 153  
 
 154  1
                     switch (mode) {
 155  
                     case NEAREST: {
 156  2
                         prefs = ReadPreference.closest(tagArray);
 157  2
                         break;
 158  
                     }
 159  
                     case PRIMARY_ONLY: {
 160  1
                         prefs = ReadPreference.primary();
 161  1
                         break;
 162  
                     }
 163  
                     case PRIMARY_PREFERRED: {
 164  1
                         prefs = ReadPreference.preferPrimary(tagArray);
 165  1
                         break;
 166  
                     }
 167  
                     case SECONDARY_ONLY: {
 168  1
                         prefs = ReadPreference.secondary(tagArray);
 169  1
                         break;
 170  
                     }
 171  
                     case SECONDARY_PREFERRED: {
 172  3
                         prefs = ReadPreference.preferSecondary(tagArray);
 173  3
                         break;
 174  
                     }
 175  
                     case SERVER: {
 176  2
                         final Element serverElement = doc.get("server");
 177  2
                         if (serverElement != null) {
 178  1
                             prefs = ReadPreference.server(serverElement
 179  
                                     .getValueAsString());
 180  
                         }
 181  
                         break;
 182  
                     }
 183  
                     }
 184  
                 }
 185  
             }
 186  1
             catch (final JsonException parseError) {
 187  
                 // Fall through.
 188  1
                 prefs = null;
 189  
             }
 190  1
             catch (final IllegalArgumentException invalidMode) {
 191  
                 // Fall through.
 192  1
                 prefs = null;
 193  12
             }
 194  
 
 195  13
             if (prefs != null) {
 196  9
                 setValue(prefs);
 197  
             }
 198  
             else {
 199  4
                 throw new IllegalArgumentException(
 200  
                         "Could not determine the read preferences for '"
 201  
                                 + readPreferenceString + "'.");
 202  
             }
 203  
         }
 204  29
     }
 205  
 
 206  
     /**
 207  
      * Uses the URI parameters to determine a {@link ReadPreference}. May return
 208  
      * null if the URI did not contain any read preference settings.
 209  
      * 
 210  
      * @param uri
 211  
      *            The URI.
 212  
      * @return The {@link ReadPreference} from the URI parameters.
 213  
      */
 214  
     private ReadPreference fromUriParameters(final MongoDbUri uri) {
 215  
 
 216  14
         final Map<String, String> parameters = uri.getParsedOptions();
 217  
 
 218  14
         ReadPreference result = null;
 219  
 
 220  14
         String value = parameters.remove("slaveok");
 221  14
         if (value != null) {
 222  4
             if (Boolean.parseBoolean(value)) {
 223  2
                 result = ReadPreference.SECONDARY;
 224  
             }
 225  
             else {
 226  2
                 result = ReadPreference.PRIMARY;
 227  
             }
 228  
         }
 229  
 
 230  14
         value = parameters.remove("readpreference");
 231  14
         final List<String> tagsValue = uri.getValuesFor("readpreferencetags");
 232  14
         if (value != null) {
 233  8
             if ("primary".equalsIgnoreCase(value)) {
 234  1
                 result = ReadPreference.PRIMARY;
 235  
             }
 236  7
             else if ("primaryPreferred".equalsIgnoreCase(value)) {
 237  1
                 result = ReadPreference.preferPrimary(parseTags(tagsValue));
 238  
             }
 239  6
             else if ("secondary".equalsIgnoreCase(value)) {
 240  3
                 result = ReadPreference.secondary(parseTags(tagsValue));
 241  
             }
 242  3
             else if ("secondaryPreferred".equalsIgnoreCase(value)) {
 243  1
                 result = ReadPreference.preferSecondary(parseTags(tagsValue));
 244  
             }
 245  2
             else if ("nearest".equalsIgnoreCase(value)) {
 246  1
                 result = ReadPreference.closest(parseTags(tagsValue));
 247  
             }
 248  
             else {
 249  1
                 LOG.warn("Unknown readPreference: '{}'. "
 250  
                         + "Defaulting to primary.", value);
 251  1
                 result = ReadPreference.PRIMARY;
 252  
             }
 253  
         }
 254  
 
 255  14
         return result;
 256  
     }
 257  
 
 258  
     /**
 259  
      * Parses out the tags documents.
 260  
      * 
 261  
      * @param tagsValue
 262  
      *            The list of tags entries.
 263  
      * @return The tags documents.
 264  
      */
 265  
     private DocumentAssignable[] parseTags(final List<String> tagsValue) {
 266  6
         if ((tagsValue == null) || tagsValue.isEmpty()) {
 267  4
             return EMPTY_TAGS;
 268  
         }
 269  
 
 270  2
         final List<DocumentAssignable> docs = new ArrayList<DocumentAssignable>(
 271  
                 tagsValue.size());
 272  2
         for (final String tagValue : tagsValue) {
 273  3
             docs.add(Json.parse("{" + tagValue + "}"));
 274  3
         }
 275  2
         return docs.toArray(EMPTY_TAGS);
 276  
     }
 277  
 }