1 // Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. 2 package org.rocksdb; 3 4 import java.util.*; 5 6 public abstract class AbstractMutableOptions { 7 8 protected static final String KEY_VALUE_PAIR_SEPARATOR = ";"; 9 protected static final char KEY_VALUE_SEPARATOR = '='; 10 static final String INT_ARRAY_INT_SEPARATOR = ","; 11 12 protected final String[] keys; 13 private final String[] values; 14 15 /** 16 * User must use builder pattern, or parser. 17 * 18 * @param keys the keys 19 * @param values the values 20 */ AbstractMutableOptions(final String[] keys, final String[] values)21 protected AbstractMutableOptions(final String[] keys, final String[] values) { 22 this.keys = keys; 23 this.values = values; 24 } 25 getKeys()26 String[] getKeys() { 27 return keys; 28 } 29 getValues()30 String[] getValues() { 31 return values; 32 } 33 34 /** 35 * Returns a string representation of MutableOptions which 36 * is suitable for consumption by {@code #parse(String)}. 37 * 38 * @return String representation of MutableOptions 39 */ 40 @Override toString()41 public String toString() { 42 final StringBuilder buffer = new StringBuilder(); 43 for(int i = 0; i < keys.length; i++) { 44 buffer 45 .append(keys[i]) 46 .append(KEY_VALUE_SEPARATOR) 47 .append(values[i]); 48 49 if(i + 1 < keys.length) { 50 buffer.append(KEY_VALUE_PAIR_SEPARATOR); 51 } 52 } 53 return buffer.toString(); 54 } 55 56 public static abstract class AbstractMutableOptionsBuilder< 57 T extends AbstractMutableOptions, 58 U extends AbstractMutableOptionsBuilder<T, U, K>, 59 K extends MutableOptionKey> { 60 61 private final Map<K, MutableOptionValue<?>> options = new LinkedHashMap<>(); 62 self()63 protected abstract U self(); 64 65 /** 66 * Get all of the possible keys 67 * 68 * @return A map of all keys, indexed by name. 69 */ allKeys()70 protected abstract Map<String, K> allKeys(); 71 72 /** 73 * Construct a sub-class instance of {@link AbstractMutableOptions}. 74 * 75 * @param keys the keys 76 * @param values the values 77 * 78 * @return an instance of the options. 79 */ build(final String[] keys, final String[] values)80 protected abstract T build(final String[] keys, final String[] values); 81 build()82 public T build() { 83 final String keys[] = new String[options.size()]; 84 final String values[] = new String[options.size()]; 85 86 int i = 0; 87 for (final Map.Entry<K, MutableOptionValue<?>> option : options.entrySet()) { 88 keys[i] = option.getKey().name(); 89 values[i] = option.getValue().asString(); 90 i++; 91 } 92 93 return build(keys, values); 94 } 95 setDouble( final K key, final double value)96 protected U setDouble( 97 final K key, final double value) { 98 if (key.getValueType() != MutableOptionKey.ValueType.DOUBLE) { 99 throw new IllegalArgumentException( 100 key + " does not accept a double value"); 101 } 102 options.put(key, MutableOptionValue.fromDouble(value)); 103 return self(); 104 } 105 getDouble(final K key)106 protected double getDouble(final K key) 107 throws NoSuchElementException, NumberFormatException { 108 final MutableOptionValue<?> value = options.get(key); 109 if(value == null) { 110 throw new NoSuchElementException(key.name() + " has not been set"); 111 } 112 return value.asDouble(); 113 } 114 setLong( final K key, final long value)115 protected U setLong( 116 final K key, final long value) { 117 if(key.getValueType() != MutableOptionKey.ValueType.LONG) { 118 throw new IllegalArgumentException( 119 key + " does not accept a long value"); 120 } 121 options.put(key, MutableOptionValue.fromLong(value)); 122 return self(); 123 } 124 getLong(final K key)125 protected long getLong(final K key) 126 throws NoSuchElementException, NumberFormatException { 127 final MutableOptionValue<?> value = options.get(key); 128 if(value == null) { 129 throw new NoSuchElementException(key.name() + " has not been set"); 130 } 131 return value.asLong(); 132 } 133 setInt( final K key, final int value)134 protected U setInt( 135 final K key, final int value) { 136 if(key.getValueType() != MutableOptionKey.ValueType.INT) { 137 throw new IllegalArgumentException( 138 key + " does not accept an integer value"); 139 } 140 options.put(key, MutableOptionValue.fromInt(value)); 141 return self(); 142 } 143 getInt(final K key)144 protected int getInt(final K key) 145 throws NoSuchElementException, NumberFormatException { 146 final MutableOptionValue<?> value = options.get(key); 147 if(value == null) { 148 throw new NoSuchElementException(key.name() + " has not been set"); 149 } 150 return value.asInt(); 151 } 152 setBoolean( final K key, final boolean value)153 protected U setBoolean( 154 final K key, final boolean value) { 155 if(key.getValueType() != MutableOptionKey.ValueType.BOOLEAN) { 156 throw new IllegalArgumentException( 157 key + " does not accept a boolean value"); 158 } 159 options.put(key, MutableOptionValue.fromBoolean(value)); 160 return self(); 161 } 162 getBoolean(final K key)163 protected boolean getBoolean(final K key) 164 throws NoSuchElementException, NumberFormatException { 165 final MutableOptionValue<?> value = options.get(key); 166 if(value == null) { 167 throw new NoSuchElementException(key.name() + " has not been set"); 168 } 169 return value.asBoolean(); 170 } 171 setIntArray( final K key, final int[] value)172 protected U setIntArray( 173 final K key, final int[] value) { 174 if(key.getValueType() != MutableOptionKey.ValueType.INT_ARRAY) { 175 throw new IllegalArgumentException( 176 key + " does not accept an int array value"); 177 } 178 options.put(key, MutableOptionValue.fromIntArray(value)); 179 return self(); 180 } 181 getIntArray(final K key)182 protected int[] getIntArray(final K key) 183 throws NoSuchElementException, NumberFormatException { 184 final MutableOptionValue<?> value = options.get(key); 185 if(value == null) { 186 throw new NoSuchElementException(key.name() + " has not been set"); 187 } 188 return value.asIntArray(); 189 } 190 setEnum( final K key, final N value)191 protected <N extends Enum<N>> U setEnum( 192 final K key, final N value) { 193 if(key.getValueType() != MutableOptionKey.ValueType.ENUM) { 194 throw new IllegalArgumentException( 195 key + " does not accept a Enum value"); 196 } 197 options.put(key, MutableOptionValue.fromEnum(value)); 198 return self(); 199 } 200 201 @SuppressWarnings("unchecked") getEnum(final K key)202 protected <N extends Enum<N>> N getEnum(final K key) 203 throws NoSuchElementException, NumberFormatException { 204 final MutableOptionValue<?> value = options.get(key); 205 if (value == null) { 206 throw new NoSuchElementException(key.name() + " has not been set"); 207 } 208 209 if (!(value instanceof MutableOptionValue.MutableOptionEnumValue)) { 210 throw new NoSuchElementException(key.name() + " is not of Enum type"); 211 } 212 213 return ((MutableOptionValue.MutableOptionEnumValue<N>) value).asObject(); 214 } 215 fromString( final String keyStr, final String valueStr)216 public U fromString( 217 final String keyStr, final String valueStr) 218 throws IllegalArgumentException { 219 Objects.requireNonNull(keyStr); 220 Objects.requireNonNull(valueStr); 221 222 final K key = allKeys().get(keyStr); 223 switch(key.getValueType()) { 224 case DOUBLE: 225 return setDouble(key, Double.parseDouble(valueStr)); 226 227 case LONG: 228 return setLong(key, Long.parseLong(valueStr)); 229 230 case INT: 231 return setInt(key, Integer.parseInt(valueStr)); 232 233 case BOOLEAN: 234 return setBoolean(key, Boolean.parseBoolean(valueStr)); 235 236 case INT_ARRAY: 237 final String[] strInts = valueStr 238 .trim().split(INT_ARRAY_INT_SEPARATOR); 239 if(strInts == null || strInts.length == 0) { 240 throw new IllegalArgumentException( 241 "int array value is not correctly formatted"); 242 } 243 244 final int value[] = new int[strInts.length]; 245 int i = 0; 246 for(final String strInt : strInts) { 247 value[i++] = Integer.parseInt(strInt); 248 } 249 return setIntArray(key, value); 250 } 251 252 throw new IllegalStateException( 253 key + " has unknown value type: " + key.getValueType()); 254 } 255 } 256 } 257