|
| 1 | +/** |
| 2 | + * Copyright (C) 2011-2012 Typesafe Inc. <http://typesafe.com> |
| 3 | + */ |
| 4 | +package org.ekrich.config |
| 5 | + |
| 6 | +import org.ekrich.config.impl.ConfigImplUtil |
| 7 | +import org.ekrich.config.impl.PlatformThread |
| 8 | + |
| 9 | +/** |
| 10 | + * A set of options related to parsing. |
| 11 | + * |
| 12 | + * <p> This object is immutable, so the "setters" return a new object. |
| 13 | + * |
| 14 | + * <p> Here is an example of creating a custom `ConfigParseOptions`: |
| 15 | + * |
| 16 | + * <pre> ConfigParseOptions options = ConfigParseOptions.defaults() |
| 17 | + * .setSyntax(ConfigSyntax.JSON) .setAllowMissing(false) </pre> |
| 18 | + */ |
| 19 | +object ConfigParseOptions { |
| 20 | + |
| 21 | + /** |
| 22 | + * Gets an instance of `ConfigParseOptions` with all fields set to the default |
| 23 | + * values. Start with this instance and make any changes you need. |
| 24 | + * |
| 25 | + * @return |
| 26 | + * the default parse options |
| 27 | + */ |
| 28 | + def defaults = new ConfigParseOptions(null, null, true, null, null) |
| 29 | +} |
| 30 | + |
| 31 | +final class ConfigParseOptions private ( |
| 32 | + val syntax: ConfigSyntax, |
| 33 | + val originDescription: String, |
| 34 | + val allowMissing: Boolean, |
| 35 | + val includer: ConfigIncluder, |
| 36 | + val classLoader: ClassLoader |
| 37 | +) { |
| 38 | + |
| 39 | + /** |
| 40 | + * Set the file format. If set to null, try to guess from any available |
| 41 | + * filename extension; if guessing fails, assume [[ConfigSyntax#CONF]]. |
| 42 | + * |
| 43 | + * @param syntax |
| 44 | + * a syntax or `null` for best guess |
| 45 | + * @return |
| 46 | + * options with the syntax set |
| 47 | + */ |
| 48 | + def setSyntax(syntax: ConfigSyntax): ConfigParseOptions = |
| 49 | + if (this.syntax == syntax) this |
| 50 | + else |
| 51 | + new ConfigParseOptions( |
| 52 | + syntax, |
| 53 | + this.originDescription, |
| 54 | + this.allowMissing, |
| 55 | + this.includer, |
| 56 | + this.classLoader |
| 57 | + ) |
| 58 | + |
| 59 | + /** |
| 60 | + * Set the file format. If set to null, assume [[ConfigSyntax#CONF]]. |
| 61 | + * |
| 62 | + * @param filename |
| 63 | + * a configuration file name |
| 64 | + * @return |
| 65 | + * options with the syntax set |
| 66 | + */ |
| 67 | + def setSyntaxFromFilename(filename: String): ConfigParseOptions = { |
| 68 | + val syntax = ConfigImplUtil.syntaxFromExtension(filename) |
| 69 | + setSyntax(syntax) |
| 70 | + } |
| 71 | + |
| 72 | + /** |
| 73 | + * Gets the current syntax option, which may be null for "any". |
| 74 | + * |
| 75 | + * @return |
| 76 | + * the current syntax or null |
| 77 | + */ |
| 78 | + def getSyntax: ConfigSyntax = syntax |
| 79 | + |
| 80 | + /** |
| 81 | + * Set a description for the thing being parsed. In most cases this will be |
| 82 | + * set up for you to something like the filename, but if you provide just an |
| 83 | + * input stream you might want to improve on it. Set to null to allow the |
| 84 | + * library to come up with something automatically. This description is the |
| 85 | + * basis for the [[ConfigOrigin]] of the parsed values. |
| 86 | + * |
| 87 | + * @param originDescription |
| 88 | + * description to put in the [[ConfigOrigin]] |
| 89 | + * @return |
| 90 | + * options with the origin description set |
| 91 | + */ |
| 92 | + def setOriginDescription(originDescription: String): ConfigParseOptions = { // findbugs complains about == here but is wrong, do not "fix" |
| 93 | + if (this.originDescription == originDescription) |
| 94 | + this |
| 95 | + else if (this.originDescription != null && originDescription != null && this.originDescription == originDescription) |
| 96 | + this |
| 97 | + else |
| 98 | + new ConfigParseOptions( |
| 99 | + this.syntax, |
| 100 | + originDescription, |
| 101 | + this.allowMissing, |
| 102 | + this.includer, |
| 103 | + this.classLoader |
| 104 | + ) |
| 105 | + } |
| 106 | + |
| 107 | + /** |
| 108 | + * Gets the current origin description, which may be null for "automatic". |
| 109 | + * |
| 110 | + * @return |
| 111 | + * the current origin description or null |
| 112 | + */ |
| 113 | + def getOriginDescription: String = originDescription |
| 114 | + |
| 115 | + /** this is package-private, not public API */ |
| 116 | + private[config] def withFallbackOriginDescription(originDescription: String) = |
| 117 | + if (this.originDescription == null) |
| 118 | + setOriginDescription(originDescription) |
| 119 | + else |
| 120 | + this |
| 121 | + |
| 122 | + /** |
| 123 | + * Set to false to throw an exception if the item being parsed (for example a |
| 124 | + * file) is missing. Set to true to just return an empty document in that |
| 125 | + * case. Note that this setting applies on only to fetching the root document, |
| 126 | + * it has no effect on any nested includes. |
| 127 | + * |
| 128 | + * @param allowMissing |
| 129 | + * true to silently ignore missing item |
| 130 | + * @return |
| 131 | + * options with the "allow missing" flag set |
| 132 | + */ |
| 133 | + def setAllowMissing(allowMissing: Boolean): ConfigParseOptions = |
| 134 | + if (this.allowMissing == allowMissing) |
| 135 | + this |
| 136 | + else |
| 137 | + new ConfigParseOptions( |
| 138 | + this.syntax, |
| 139 | + this.originDescription, |
| 140 | + allowMissing, |
| 141 | + this.includer, |
| 142 | + this.classLoader |
| 143 | + ) |
| 144 | + |
| 145 | + /** |
| 146 | + * Gets the current "allow missing" flag. |
| 147 | + * |
| 148 | + * @return |
| 149 | + * whether we allow missing files |
| 150 | + */ |
| 151 | + def getAllowMissing: Boolean = allowMissing |
| 152 | + |
| 153 | + /** |
| 154 | + * Set a [[ConfigIncluder]] which customizes how includes are handled. null |
| 155 | + * means to use the default includer. |
| 156 | + * |
| 157 | + * @param includer |
| 158 | + * the includer to use or null for default |
| 159 | + * @return |
| 160 | + * new version of the parse options with different includer |
| 161 | + */ |
| 162 | + def setIncluder(includer: ConfigIncluder): ConfigParseOptions = |
| 163 | + if (this.includer == includer) |
| 164 | + this |
| 165 | + else |
| 166 | + new ConfigParseOptions( |
| 167 | + this.syntax, |
| 168 | + this.originDescription, |
| 169 | + this.allowMissing, |
| 170 | + includer, |
| 171 | + this.classLoader |
| 172 | + ) |
| 173 | + |
| 174 | + /** |
| 175 | + * Prepends a [[ConfigIncluder]] which customizes how includes are handled. To |
| 176 | + * prepend your includer, the library calls [[ConfigIncluder#withFallback]] on |
| 177 | + * your includer to append the existing includer to it. |
| 178 | + * |
| 179 | + * @param includer |
| 180 | + * the includer to prepend (may not be null) |
| 181 | + * @return |
| 182 | + * new version of the parse options with different includer |
| 183 | + */ |
| 184 | + def prependIncluder(includer: ConfigIncluder): ConfigParseOptions = { |
| 185 | + if (includer == null) |
| 186 | + throw new NullPointerException("null includer passed to prependIncluder") |
| 187 | + if (this.includer eq includer) |
| 188 | + this |
| 189 | + else if (this.includer != null) |
| 190 | + setIncluder(includer.withFallback(this.includer)) |
| 191 | + else |
| 192 | + setIncluder(includer) |
| 193 | + } |
| 194 | + |
| 195 | + /** |
| 196 | + * Appends a [[ConfigIncluder]] which customizes how includes are handled. To |
| 197 | + * append, the library calls [[ConfigIncluder#withFallback]] on the existing |
| 198 | + * includer. |
| 199 | + * |
| 200 | + * @param includer |
| 201 | + * the includer to append (may not be null) |
| 202 | + * @return |
| 203 | + * new version of the parse options with different includer |
| 204 | + */ |
| 205 | + def appendIncluder(includer: ConfigIncluder): ConfigParseOptions = { |
| 206 | + if (includer == null) |
| 207 | + throw new NullPointerException("null includer passed to appendIncluder") |
| 208 | + if (this.includer == includer) |
| 209 | + this |
| 210 | + else if (this.includer != null) |
| 211 | + setIncluder(this.includer.withFallback(includer)) |
| 212 | + else |
| 213 | + setIncluder(includer) |
| 214 | + } |
| 215 | + |
| 216 | + /** |
| 217 | + * Gets the current includer (will be null for the default includer). |
| 218 | + * |
| 219 | + * @return |
| 220 | + * current includer or null |
| 221 | + */ |
| 222 | + def getIncluder: ConfigIncluder = includer |
| 223 | + |
| 224 | + /** |
| 225 | + * Set the class loader. If set to null, |
| 226 | + * `Thread.currentThread().getContextClassLoader()` will be used. |
| 227 | + * |
| 228 | + * @param loader |
| 229 | + * a class loader or `null` to use thread context class loader |
| 230 | + * @return |
| 231 | + * options with the class loader set |
| 232 | + */ |
| 233 | + def setClassLoader(loader: ClassLoader): ConfigParseOptions = |
| 234 | + if (this.classLoader == loader) |
| 235 | + this |
| 236 | + else |
| 237 | + new ConfigParseOptions( |
| 238 | + this.syntax, |
| 239 | + this.originDescription, |
| 240 | + this.allowMissing, |
| 241 | + this.includer, |
| 242 | + loader |
| 243 | + ) |
| 244 | + |
| 245 | + /** |
| 246 | + * Get the class loader; never returns `null`, if the class loader was unset, |
| 247 | + * returns `Thread.currentThread().getContextClassLoader()`. |
| 248 | + * |
| 249 | + * @return |
| 250 | + * class loader to use |
| 251 | + */ |
| 252 | + def getClassLoader: ClassLoader = |
| 253 | + if (this.classLoader == null) { |
| 254 | + val thread = Thread.currentThread |
| 255 | + new PlatformThread(thread).getContextClassLoader() |
| 256 | + } else { |
| 257 | + this.classLoader |
| 258 | + } |
| 259 | +} |
0 commit comments