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