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