View Javadoc
1   /*
2    * #%L
3    * DurabilityEditor.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.Collections;
24  import java.util.HashSet;
25  import java.util.Map;
26  import java.util.Set;
27  
28  /**
29   * {@link java.beans.PropertyEditor} for the {@link Durability} class.
30   * <p>
31   * The string value must be one of the following tokens or parse-able by
32   * {@link Durability#valueOf(String)} method.
33   * </p>
34   * <p>
35   * Valid tokens are:
36   * <ul>
37   * <li>{@code NONE}</li>
38   * <li>{@code ACK}</li>
39   * <li>{@code FSYNC}</li>
40   * <li>{@code JOURNAL}</li>
41   * <li>{@code MAJORITY}</li>
42   * </ul>
43   * </p>
44   * <p>
45   * {@code FSYNC}, {@code JOURNAL}, and {@code MAJORITY} all use
46   * {@value #DEFAULT_WAIT_TIME_MS} milliseconds for the wait time.
47   * </p>
48   * <p>
49   * This editor will also parses a full MongoDB URI to extract the specified
50   * {@link Durability}. See the <a href=
51   * "http://docs.mongodb.org/manual/reference/connection-string/#write-concern-options"
52   * >Connection String URI Format</a> documentation for information on
53   * constructing a MongoDB URI.
54   * </p>
55   * 
56   * @api.yes This class is part of the driver's API. Public and protected members
57   *          will be deprecated for at least 1 non-bugfix release (version
58   *          numbers are &lt;major&gt;.&lt;minor&gt;.&lt;bugfix&gt;) before being
59   *          removed or modified.
60   * @copyright 2013-2014, Allanbank Consulting, Inc., All Rights Reserved
61   */
62  public class DurabilityEditor extends PropertyEditorSupport {
63  
64      /** The default wait time for tokenized durabilities: {@value} ms. */
65      public static final int DEFAULT_WAIT_TIME_MS = 30000;
66  
67      /** The set of fields used to determine a Durability from a MongoDB URI. */
68      public static final Set<String> MONGODB_URI_FIELDS;
69  
70      static {
71          final Set<String> fields = new HashSet<String>();
72          fields.add("safe");
73          fields.add("w");
74          fields.add("wtimeout");
75          fields.add("wtimeoutms");
76          fields.add("fsync");
77          fields.add("journal");
78  
79          MONGODB_URI_FIELDS = Collections.unmodifiableSet(fields);
80      }
81  
82      /**
83       * Creates a new DurabilityEditor.
84       */
85      public DurabilityEditor() {
86          super();
87      }
88  
89      /**
90       * {@inheritDoc}
91       * <p>
92       * Overridden to parse a string to a {@link Durability}.
93       * </p>
94       * 
95       * @throws IllegalArgumentException
96       *             If the string cannot be parsed into a {@link Durability}.
97       */
98      @Override
99      public void setAsText(final String durabilityString)
100             throws IllegalArgumentException {
101 
102         if ("NONE".equalsIgnoreCase(durabilityString)) {
103             setValue(Durability.NONE);
104         }
105         else if ("ACK".equalsIgnoreCase(durabilityString)) {
106             setValue(Durability.ACK);
107         }
108         else if ("FSYNC".equalsIgnoreCase(durabilityString)) {
109             setValue(Durability.fsyncDurable(DEFAULT_WAIT_TIME_MS));
110         }
111         else if ("JOURNAL".equalsIgnoreCase(durabilityString)) {
112             setValue(Durability.journalDurable(DEFAULT_WAIT_TIME_MS));
113         }
114         else if ("MAJORITY".equalsIgnoreCase(durabilityString)) {
115             setValue(Durability.replicaDurable(Durability.MAJORITY_MODE,
116                     DEFAULT_WAIT_TIME_MS));
117         }
118         else if (MongoDbUri.isUri(durabilityString)) {
119             final MongoDbUri uri = new MongoDbUri(durabilityString);
120             final Durability parsed = fromUriParameters(uri.getParsedOptions());
121             if (parsed != null) {
122                 setValue(parsed);
123             }
124         }
125         else {
126             final Durability durability = Durability.valueOf(durabilityString);
127             if (durability != null) {
128                 setValue(durability);
129             }
130             else {
131                 throw new IllegalArgumentException(
132                         "Could not determine the durability for '"
133                                 + durabilityString + "'.");
134             }
135         }
136     }
137 
138     /**
139      * Uses the URI parameters to determine a durability. May return null if the
140      * URI did not contain any durability settings.
141      * 
142      * @param parameters
143      *            The URI parameters.
144      * @return The {@link Durability} from the URI parameters.
145      */
146     private Durability fromUriParameters(final Map<String, String> parameters) {
147         boolean safe = false;
148         int w = 1;
149         String wTxt = null;
150         boolean fsync = false;
151         boolean journal = false;
152         int wtimeout = 0;
153 
154         // Without order surprising things happen.
155         for (final Map.Entry<String, String> entry : parameters.entrySet()) {
156             final String parameter = entry.getKey();
157             final String value = entry.getValue();
158 
159             if ("safe".equalsIgnoreCase(parameter)) {
160                 safe = Boolean.parseBoolean(value);
161             }
162             else if ("w".equalsIgnoreCase(parameter)) {
163                 safe = true;
164                 try {
165                     w = Integer.parseInt(value);
166                     wTxt = null;
167                 }
168                 catch (final NumberFormatException nfe) {
169                     w = 2;
170                     wTxt = value;
171                 }
172             }
173             else if ("wtimeout".equalsIgnoreCase(parameter)
174                     || "wtimeoutms".equalsIgnoreCase(parameter)) {
175                 safe = true;
176                 wtimeout = Integer.parseInt(value);
177                 if (w <= 1) {
178                     w = 2;
179                 }
180             }
181             else if ("fsync".equalsIgnoreCase(parameter)) {
182                 fsync = Boolean.parseBoolean(value);
183                 if (fsync) {
184                     journal = false;
185                     safe = true;
186                 }
187             }
188             else if ("journal".equalsIgnoreCase(parameter)) {
189                 journal = Boolean.parseBoolean(value);
190                 if (journal) {
191                     fsync = false;
192                     safe = true;
193                 }
194             }
195         }
196 
197         // Figure out the intended durability.
198         Durability result = null;
199         if (safe) {
200             if (fsync) {
201                 result = Durability.fsyncDurable(wtimeout);
202             }
203             else if (journal) {
204                 result = Durability.journalDurable(wtimeout);
205             }
206             else if (w == 1) {
207                 result = Durability.ACK;
208             }
209             else if (w > 1) {
210                 if (wTxt != null) {
211                     result = Durability.replicaDurable(wTxt, wtimeout);
212                 }
213                 else {
214                     result = Durability.replicaDurable(w, wtimeout);
215                 }
216             }
217             else if (w <= 0) {
218                 result = Durability.NONE;
219             }
220         }
221         return result;
222 
223     }
224 }