001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.configuration2.builder.combined; 018 019import java.util.ArrayList; 020import java.util.Collection; 021import java.util.Collections; 022import java.util.HashMap; 023import java.util.LinkedList; 024import java.util.Map; 025 026import org.apache.commons.configuration2.ConfigurationUtils; 027import org.apache.commons.configuration2.HierarchicalConfiguration; 028import org.apache.commons.configuration2.builder.BasicBuilderParameters; 029import org.apache.commons.configuration2.builder.BuilderParameters; 030import org.apache.commons.configuration2.builder.ConfigurationBuilder; 031import org.apache.commons.configuration2.builder.DefaultParametersHandler; 032import org.apache.commons.configuration2.builder.DefaultParametersManager; 033 034/** 035 * <p> 036 * A specialized parameters object for a {@link CombinedConfigurationBuilder}. 037 * </p> 038 * <p> 039 * This class defines methods for setting properties for customizing a builder 040 * for combined configurations. Note that some of these properties can also be 041 * set in the configuration definition file. If this is the case, the settings 042 * in the definition file override the content of this object. 043 * </p> 044 * <p> 045 * This class is not thread-safe. It is intended that an instance is constructed 046 * and initialized by a single thread during configuration of a 047 * {@code ConfigurationBuilder}. 048 * </p> 049 * 050 * @since 2.0 051 */ 052public class CombinedBuilderParametersImpl extends BasicBuilderParameters 053 implements CombinedBuilderProperties<CombinedBuilderParametersImpl> 054{ 055 /** Constant for the key in the parameters map used by this class. */ 056 private static final String PARAM_KEY = RESERVED_PARAMETER_PREFIX 057 + CombinedBuilderParametersImpl.class.getName(); 058 059 /** The definition configuration builder. */ 060 private ConfigurationBuilder<? extends HierarchicalConfiguration<?>> definitionBuilder; 061 062 /** A parameters object for the definition configuration builder. */ 063 private BuilderParameters definitionBuilderParameters; 064 065 /** A map with registered configuration builder providers. */ 066 private final Map<String, ConfigurationBuilderProvider> providers; 067 068 /** A list with default parameters for child configuration sources. */ 069 private final Collection<BuilderParameters> childParameters; 070 071 /** The manager for default handlers. */ 072 private DefaultParametersManager childDefaultParametersManager; 073 074 /** The base path for configuration sources to be loaded. */ 075 private String basePath; 076 077 /** A flag whether settings should be inherited by child builders. */ 078 private boolean inheritSettings; 079 080 /** 081 * Creates a new instance of {@code CombinedBuilderParametersImpl}. 082 */ 083 public CombinedBuilderParametersImpl() 084 { 085 providers = new HashMap<>(); 086 childParameters = new LinkedList<>(); 087 inheritSettings = true; 088 } 089 090 /** 091 * Looks up an instance of this class in the specified parameters map. This 092 * is equivalent to {@code fromParameters(params, false);} 093 * 094 * @param params the map with parameters (must not be <b>null</b> 095 * @return the instance obtained from the map or <b>null</b> 096 * @throws NullPointerException if the map is <b>null</b> 097 */ 098 public static CombinedBuilderParametersImpl fromParameters( 099 final Map<String, ?> params) 100 { 101 return fromParameters(params, false); 102 } 103 104 /** 105 * Looks up an instance of this class in the specified parameters map and 106 * optionally creates a new one if none is found. This method can be used to 107 * obtain an instance of this class which has been stored in a parameters 108 * map. It is compatible with the {@code getParameters()} method. 109 * 110 * @param params the map with parameters (must not be <b>null</b> 111 * @param createIfMissing determines the behavior if no instance is found in 112 * the map; if <b>true</b>, a new instance with default settings is 113 * created; if <b>false</b>, <b>null</b> is returned 114 * @return the instance obtained from the map or <b>null</b> 115 * @throws NullPointerException if the map is <b>null</b> 116 */ 117 public static CombinedBuilderParametersImpl fromParameters( 118 final Map<String, ?> params, final boolean createIfMissing) 119 { 120 CombinedBuilderParametersImpl result = 121 (CombinedBuilderParametersImpl) params.get(PARAM_KEY); 122 if (result == null && createIfMissing) 123 { 124 result = new CombinedBuilderParametersImpl(); 125 } 126 return result; 127 } 128 129 /** 130 * {@inheritDoc} This implementation additionally copies some properties 131 * defined by this class. 132 */ 133 @Override 134 public void inheritFrom(final Map<String, ?> source) 135 { 136 super.inheritFrom(source); 137 138 final CombinedBuilderParametersImpl srcParams = fromParameters(source); 139 if (srcParams != null) 140 { 141 setChildDefaultParametersManager( 142 srcParams.getChildDefaultParametersManager()); 143 setInheritSettings(srcParams.isInheritSettings()); 144 } 145 } 146 147 /** 148 * Returns the current value of the flag that controls whether the settings 149 * of the parent combined configuration builder should be inherited by its 150 * child configurations. 151 * 152 * @return the flag whether settings should be inherited by child 153 * configurations 154 */ 155 public boolean isInheritSettings() 156 { 157 return inheritSettings; 158 } 159 160 @Override 161 public CombinedBuilderParametersImpl setInheritSettings( 162 final boolean inheritSettings) 163 { 164 this.inheritSettings = inheritSettings; 165 return this; 166 } 167 168 /** 169 * Returns the {@code ConfigurationBuilder} object for obtaining the 170 * definition configuration. 171 * 172 * @return the definition {@code ConfigurationBuilder} 173 */ 174 public ConfigurationBuilder<? extends HierarchicalConfiguration<?>> getDefinitionBuilder() 175 { 176 return definitionBuilder; 177 } 178 179 /** 180 * Sets the {@code ConfigurationBuilder} for the definition configuration. 181 * This is the configuration which contains the configuration sources that 182 * form the combined configuration. 183 * 184 * @param builder the definition {@code ConfigurationBuilder} 185 * @return a reference to this object for method chaining 186 */ 187 @Override 188 public CombinedBuilderParametersImpl setDefinitionBuilder( 189 final ConfigurationBuilder<? extends HierarchicalConfiguration<?>> builder) 190 { 191 definitionBuilder = builder; 192 return this; 193 } 194 195 /** 196 * Registers the given {@code ConfigurationBuilderProvider} for the 197 * specified tag name. This means that whenever this tag is encountered in a 198 * configuration definition file, the corresponding builder provider is 199 * invoked. 200 * 201 * @param tagName the name of the tag (must not be <b>null</b>) 202 * @param provider the {@code ConfigurationBuilderProvider} (must not be 203 * <b>null</b>) 204 * @return a reference to this object for method chaining 205 * @throws IllegalArgumentException if a required parameter is missing 206 */ 207 @Override 208 public CombinedBuilderParametersImpl registerProvider(final String tagName, 209 final ConfigurationBuilderProvider provider) 210 { 211 if (tagName == null) 212 { 213 throw new IllegalArgumentException("Tag name must not be null!"); 214 } 215 if (provider == null) 216 { 217 throw new IllegalArgumentException("Provider must not be null!"); 218 } 219 220 providers.put(tagName, provider); 221 return this; 222 } 223 224 /** 225 * Registers all {@code ConfigurationBuilderProvider}s in the given map to 226 * this object which have not yet been registered. This method is mainly 227 * used for internal purposes: a {@code CombinedConfigurationBuilder} takes 228 * the providers contained in a parameters object and adds all standard 229 * providers. This way it is possible to override a standard provider by 230 * registering a provider object for the same tag name at the parameters 231 * object. 232 * 233 * @param providers a map with tag names and corresponding providers (must 234 * not be <b>null</b> or contain <b>null</b> entries) 235 * @return a reference to this object for method chaining 236 * @throws IllegalArgumentException if the map with providers is <b>null</b> 237 * or contains <b>null</b> entries 238 */ 239 public CombinedBuilderParametersImpl registerMissingProviders( 240 final Map<String, ConfigurationBuilderProvider> providers) 241 { 242 if (providers == null) 243 { 244 throw new IllegalArgumentException( 245 "Map with providers must not be null!"); 246 } 247 248 for (final Map.Entry<String, ConfigurationBuilderProvider> e : providers 249 .entrySet()) 250 { 251 if (!this.providers.containsKey(e.getKey())) 252 { 253 registerProvider(e.getKey(), e.getValue()); 254 } 255 } 256 return this; 257 } 258 259 /** 260 * Registers all {@code ConfigurationBuilderProvider}s in the given 261 * parameters object which have not yet been registered. This method works 262 * like the method with the same name, but the map with providers is 263 * obtained from the passed in parameters object. 264 * 265 * @param params the parameters object from which to copy providers(must not 266 * be <b>null</b>) 267 * @return a reference to this object for method chaining 268 * @throws IllegalArgumentException if the source parameters object is 269 * <b>null</b> 270 */ 271 public CombinedBuilderParametersImpl registerMissingProviders( 272 final CombinedBuilderParametersImpl params) 273 { 274 if (params == null) 275 { 276 throw new IllegalArgumentException( 277 "Source parameters must not be null!"); 278 } 279 return registerMissingProviders(params.getProviders()); 280 } 281 282 /** 283 * Returns an (unmodifiable) map with the currently registered 284 * {@code ConfigurationBuilderProvider} objects. 285 * 286 * @return the map with {@code ConfigurationBuilderProvider} objects (the 287 * keys are the tag names) 288 */ 289 public Map<String, ConfigurationBuilderProvider> getProviders() 290 { 291 return Collections.unmodifiableMap(providers); 292 } 293 294 /** 295 * Returns the {@code ConfigurationBuilderProvider} which is registered for 296 * the specified tag name or <b>null</b> if there is no registration for 297 * this tag. 298 * 299 * @param tagName the tag name 300 * @return the provider registered for this tag or <b>null</b> 301 */ 302 public ConfigurationBuilderProvider providerForTag(final String tagName) 303 { 304 return providers.get(tagName); 305 } 306 307 /** 308 * Returns the base path for relative names of configuration sources. Result 309 * may be <b>null</b> if no base path has been set. 310 * 311 * @return the base path for resolving relative file names 312 */ 313 public String getBasePath() 314 { 315 return basePath; 316 } 317 318 /** 319 * Sets the base path for this combined configuration builder. Normally it 320 * it not necessary to set the base path explicitly. Per default, relative 321 * file names of configuration sources are resolved based on the location of 322 * the definition file. If this is not desired or if the definition 323 * configuration is loaded by a different means, the base path for relative 324 * file names can be specified using this method. 325 * 326 * @param path the base path for resolving relative file names 327 * @return a reference to this object for method chaining 328 */ 329 @Override 330 public CombinedBuilderParametersImpl setBasePath(final String path) 331 { 332 basePath = path; 333 return this; 334 } 335 336 /** 337 * Returns the parameters object for the definition configuration builder if 338 * present. 339 * 340 * @return the parameters object for the definition configuration builder or 341 * <b>null</b> 342 */ 343 public BuilderParameters getDefinitionBuilderParameters() 344 { 345 return definitionBuilderParameters; 346 } 347 348 /** 349 * Sets the parameters object for the definition configuration builder. This 350 * property is evaluated only if the definition configuration builder is not 351 * set explicitly (using the 352 * {@link #setDefinitionBuilder(ConfigurationBuilder)} method). In this 353 * case, a builder for an XML configuration is created and configured with 354 * this parameters object. 355 * 356 * @param params the parameters object for the definition configuration 357 * builder 358 * @return a reference to this object for method chaining 359 */ 360 @Override 361 public CombinedBuilderParametersImpl setDefinitionBuilderParameters( 362 final BuilderParameters params) 363 { 364 definitionBuilderParameters = params; 365 return this; 366 } 367 368 /** 369 * Returns a collection with default parameter objects for child 370 * configuration sources. This collection contains the same objects (in the 371 * same order) that were passed to {@code addChildParameters()}. The 372 * returned collection is a defensive copy; it can be modified, but this has 373 * no effect on the parameters stored in this object. 374 * 375 * @return a map with default parameters for child sources 376 */ 377 public Collection<? extends BuilderParameters> getDefaultChildParameters() 378 { 379 return new ArrayList<>(childParameters); 380 } 381 382 /** 383 * Returns the {@code DefaultParametersManager} object for initializing 384 * parameter objects for child configuration sources. This method never 385 * returns <b>null</b>. If no manager was set, a new instance is created 386 * right now. 387 * 388 * @return the {@code DefaultParametersManager} for child configuration 389 * sources 390 */ 391 public DefaultParametersManager getChildDefaultParametersManager() 392 { 393 if (childDefaultParametersManager == null) 394 { 395 childDefaultParametersManager = new DefaultParametersManager(); 396 } 397 return childDefaultParametersManager; 398 } 399 400 /** 401 * {@inheritDoc} This implementation stores the passed in manager object. An 402 * already existing manager object (either explicitly set or created on 403 * demand) is overridden. This also removes all default handlers registered 404 * before! 405 */ 406 @Override 407 public CombinedBuilderParametersImpl setChildDefaultParametersManager( 408 final DefaultParametersManager manager) 409 { 410 childDefaultParametersManager = manager; 411 return this; 412 } 413 414 /** 415 * {@inheritDoc} This implementation registers the passed in handler at an 416 * internal {@link DefaultParametersManager} instance. If none was set, a 417 * new instance is created now. 418 */ 419 @Override 420 public <D> CombinedBuilderParametersImpl registerChildDefaultsHandler( 421 final Class<D> paramClass, final DefaultParametersHandler<? super D> handler) 422 { 423 getChildDefaultParametersManager().registerDefaultsHandler(paramClass, 424 handler); 425 return this; 426 } 427 428 /** 429 * {@inheritDoc} This implementation registers the passed in handler at an 430 * internal {@link DefaultParametersManager} instance. If none was set, a 431 * new instance is created now. 432 */ 433 @Override 434 public <D> CombinedBuilderParametersImpl registerChildDefaultsHandler( 435 final Class<D> paramClass, final DefaultParametersHandler<? super D> handler, 436 final Class<?> startClass) 437 { 438 getChildDefaultParametersManager().registerDefaultsHandler(paramClass, 439 handler, startClass); 440 return this; 441 } 442 443 /** 444 * {@inheritDoc} This implementation returns a map which contains this 445 * object itself under a specific key. The static {@code fromParameters()} 446 * method can be used to extract an instance from a parameters map. 447 */ 448 @Override 449 public Map<String, Object> getParameters() 450 { 451 final Map<String, Object> params = super.getParameters(); 452 params.put(PARAM_KEY, this); 453 return params; 454 } 455 456 /** 457 * {@inheritDoc} This implementation also clones the parameters object for 458 * the definition builder if possible. 459 */ 460 @Override 461 public CombinedBuilderParametersImpl clone() 462 { 463 final CombinedBuilderParametersImpl copy = 464 (CombinedBuilderParametersImpl) super.clone(); 465 copy.setDefinitionBuilderParameters((BuilderParameters) ConfigurationUtils 466 .cloneIfPossible(getDefinitionBuilderParameters())); 467 return copy; 468 } 469}