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