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 <major>.<minor>.<bugfix>) 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 }