| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.commons.configuration2.builder.fluent; |
| |
| import java.lang.reflect.InvocationHandler; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Proxy; |
| |
| import org.apache.commons.configuration2.builder.BasicBuilderParameters; |
| import org.apache.commons.configuration2.builder.BuilderParameters; |
| import org.apache.commons.configuration2.builder.DatabaseBuilderParametersImpl; |
| import org.apache.commons.configuration2.builder.DefaultParametersHandler; |
| import org.apache.commons.configuration2.builder.DefaultParametersManager; |
| import org.apache.commons.configuration2.builder.FileBasedBuilderParametersImpl; |
| import org.apache.commons.configuration2.builder.HierarchicalBuilderParametersImpl; |
| import org.apache.commons.configuration2.builder.INIBuilderParametersImpl; |
| import org.apache.commons.configuration2.builder.JndiBuilderParametersImpl; |
| import org.apache.commons.configuration2.builder.PropertiesBuilderParametersImpl; |
| import org.apache.commons.configuration2.builder.XMLBuilderParametersImpl; |
| import org.apache.commons.configuration2.builder.combined.CombinedBuilderParametersImpl; |
| import org.apache.commons.configuration2.builder.combined.MultiFileBuilderParametersImpl; |
| |
| //@formatter:off |
| /** |
| * A convenience class for creating parameter objects for initializing configuration builder objects. |
| * <p> |
| * For setting initialization properties of new configuration objects, a number of specialized parameter classes exists. |
| * These classes use inheritance to organize the properties they support in a logic way. For instance, parameters for |
| * file-based configurations also support the basic properties common to all configuration implementations, parameters |
| * for XML configurations also include file-based and basic properties, etc. |
| * </p> |
| * <p> |
| * When constructing a configuration builder, an easy-to-use fluent API is desired to define specific properties for the |
| * configuration to be created. However, the inheritance structure of the parameter classes makes it surprisingly |
| * difficult to provide such an API. This class comes to rescue by defining a set of methods for the creation of |
| * interface-based parameter objects offering a truly fluent API. The methods provided can be called directly when |
| * setting up a configuration builder as shown in the following example code fragment: |
| * </p> |
| * <pre> |
| * Parameters params = new Parameters(); |
| * configurationBuilder.configure(params.fileBased() |
| * .setThrowExceptionOnMissing(true) |
| * .setEncoding("UTF-8") |
| * .setListDelimiter('#') |
| * .setFileName("test.xml")); |
| * </pre> |
| * <p> |
| * Using this class it is not only possible to create new parameters objects but also to initialize the newly created |
| * objects with default values. This is via the associated {@link DefaultParametersManager} object. Such an object can |
| * be passed to the constructor, or a new (uninitialized) instance is created. There are convenience methods for |
| * interacting with the associated {@code DefaultParametersManager}, namely to register or remove |
| * {@link DefaultParametersHandler} objects. On all newly created parameters objects the handlers registered at the |
| * associated {@code DefaultParametersHandler} are automatically applied. |
| * </p> |
| * <p> |
| * Implementation note: This class is thread-safe. |
| * </p> |
| * |
| * @since 2.0 |
| */ |
| //@formatter:off |
| public final class Parameters { |
| /** |
| * A specialized {@code InvocationHandler} implementation which maps the methods of a parameters interface to an |
| * implementation of the corresponding property interfaces. The parameters interface is a union of multiple property |
| * interfaces. The wrapped object implements all of these, but not the union interface. Therefore, a reflection-based |
| * approach is required. A special handling is required for the method of the {@code BuilderParameters} interface |
| * because here no fluent return value is used. |
| */ |
| private static final class ParametersIfcInvocationHandler implements InvocationHandler { |
| /** |
| * Checks whether the specified method belongs to an interface which requires fluent result values. |
| * |
| * @param method the method to be checked |
| * @return a flag whether the method's result should be handled as a fluent result value |
| */ |
| private static boolean isFluentResult(final Method method) { |
| final Class<?> declaringClass = method.getDeclaringClass(); |
| return declaringClass.isInterface() && !declaringClass.equals(BuilderParameters.class); |
| } |
| |
| /** The target object of reflection calls. */ |
| private final Object target; |
| |
| /** |
| * Creates a new instance of {@code ParametersIfcInvocationHandler} and sets the wrapped parameters object. |
| * |
| * @param targetObj the target object for reflection calls |
| */ |
| public ParametersIfcInvocationHandler(final Object targetObj) { |
| target = targetObj; |
| } |
| |
| /** |
| * {@inheritDoc} This implementation delegates method invocations to the target object and handles the return value |
| * correctly. |
| */ |
| @Override |
| public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { |
| final Object result = method.invoke(target, args); |
| return isFluentResult(method) ? proxy : result; |
| } |
| } |
| |
| /** The manager for default handlers. */ |
| private final DefaultParametersManager defaultParametersManager; |
| |
| /** |
| * Creates a new instance of {@code Parameters}. A new, uninitialized {@link DefaultParametersManager} is created. |
| */ |
| public Parameters() { |
| this(null); |
| } |
| |
| /** |
| * Creates a new instance of {@code Parameters} and initializes it with the given {@code DefaultParametersManager}. |
| * Because {@code DefaultParametersManager} is thread-safe, it makes sense to share a single instance between multiple |
| * {@code Parameters} objects; that way the same initialization is performed on newly created parameters objects. |
| * |
| * @param manager the {@code DefaultParametersHandler} (may be <b>null</b>, then a new default instance is created) |
| */ |
| public Parameters(final DefaultParametersManager manager) { |
| defaultParametersManager = manager != null ? manager : new DefaultParametersManager(); |
| } |
| |
| /** |
| * Creates a new instance of a parameters object for basic configuration properties. |
| * |
| * @return the new parameters object |
| */ |
| public BasicBuilderParameters basic() { |
| return new BasicBuilderParameters(); |
| } |
| |
| /** |
| * Creates a new instance of a parameters object for combined configuration builder properties. |
| * |
| * @return the new parameters object |
| */ |
| public CombinedBuilderParameters combined() { |
| return createParametersProxy(new CombinedBuilderParametersImpl(), CombinedBuilderParameters.class); |
| } |
| |
| /** |
| * Creates a proxy object for a given parameters interface based on the given implementation object. The newly created |
| * object is initialized with default values if there are matching {@link DefaultParametersHandler} objects. |
| * |
| * @param <T> the type of the parameters interface |
| * @param target the implementing target object |
| * @param ifcClass the interface class |
| * @param superIfcs an array with additional interface classes to be implemented |
| * @return the proxy object |
| */ |
| private <T> T createParametersProxy(final Object target, final Class<T> ifcClass, final Class<?>... superIfcs) { |
| final Class<?>[] ifcClasses = new Class<?>[1 + superIfcs.length]; |
| ifcClasses[0] = ifcClass; |
| System.arraycopy(superIfcs, 0, ifcClasses, 1, superIfcs.length); |
| final Object obj = Proxy.newProxyInstance(Parameters.class.getClassLoader(), ifcClasses, new ParametersIfcInvocationHandler(target)); |
| getDefaultParametersManager().initializeParameters((BuilderParameters) obj); |
| return ifcClass.cast(obj); |
| } |
| |
| /** |
| * Creates a new instance of a parameters object for database configurations. |
| * |
| * @return the new parameters object |
| */ |
| public DatabaseBuilderParameters database() { |
| return createParametersProxy(new DatabaseBuilderParametersImpl(), DatabaseBuilderParameters.class); |
| } |
| |
| /** |
| * Creates a new instance of a parameters object for file-based configuration properties. |
| * |
| * @return the new parameters object |
| */ |
| public FileBasedBuilderParameters fileBased() { |
| return createParametersProxy(new FileBasedBuilderParametersImpl(), FileBasedBuilderParameters.class); |
| } |
| |
| /** |
| * Gets the {@code DefaultParametersManager} associated with this object. |
| * |
| * @return the {@code DefaultParametersManager} |
| */ |
| public DefaultParametersManager getDefaultParametersManager() { |
| return defaultParametersManager; |
| } |
| |
| /** |
| * Creates a new instance of a parameters object for hierarchical configurations. |
| * |
| * @return the new parameters object |
| */ |
| public HierarchicalBuilderParameters hierarchical() { |
| return createParametersProxy(new HierarchicalBuilderParametersImpl(), HierarchicalBuilderParameters.class, FileBasedBuilderParameters.class); |
| } |
| |
| /** |
| * Creates a new instance of a parameters object for INI configurations. |
| * |
| * @return the new parameters object |
| */ |
| public INIBuilderParameters ini() { |
| return createParametersProxy(new INIBuilderParametersImpl(), INIBuilderParameters.class, FileBasedBuilderParameters.class, |
| HierarchicalBuilderParameters.class); |
| } |
| |
| /** |
| * Creates a new instance of a parameters object for JNDI configurations. |
| * |
| * @return the new parameters object |
| */ |
| public JndiBuilderParameters jndi() { |
| return createParametersProxy(new JndiBuilderParametersImpl(), JndiBuilderParameters.class); |
| } |
| |
| /** |
| * Creates a new instance of a parameters object for a builder for multiple file-based configurations. |
| * |
| * @return the new parameters object |
| */ |
| public MultiFileBuilderParameters multiFile() { |
| return createParametersProxy(new MultiFileBuilderParametersImpl(), MultiFileBuilderParameters.class); |
| } |
| |
| /** |
| * Creates a new instance of a parameters object for properties configurations. |
| * |
| * @return the new parameters object |
| */ |
| public PropertiesBuilderParameters properties() { |
| return createParametersProxy(new PropertiesBuilderParametersImpl(), PropertiesBuilderParameters.class, FileBasedBuilderParameters.class); |
| } |
| |
| /** |
| * Registers the specified {@code DefaultParametersHandler} object for the given parameters class. This is a convenience |
| * method which just delegates to the associated {@code DefaultParametersManager}. |
| * |
| * @param <T> the type of the parameters supported by this handler |
| * @param paramsClass the parameters class supported by this handler (must not be <b>null</b>) |
| * @param handler the {@code DefaultParametersHandler} to be registered (must not be <b>null</b>) |
| * @throws IllegalArgumentException if a required parameter is missing |
| * @see DefaultParametersManager |
| */ |
| public <T> void registerDefaultsHandler(final Class<T> paramsClass, final DefaultParametersHandler<? super T> handler) { |
| getDefaultParametersManager().registerDefaultsHandler(paramsClass, handler); |
| } |
| |
| /** |
| * Registers the specified {@code DefaultParametersHandler} object for the given parameters class and start class in the |
| * inheritance hierarchy. This is a convenience method which just delegates to the associated |
| * {@code DefaultParametersManager}. |
| * |
| * @param <T> the type of the parameters supported by this handler |
| * @param paramsClass the parameters class supported by this handler (must not be <b>null</b>) |
| * @param handler the {@code DefaultParametersHandler} to be registered (must not be <b>null</b>) |
| * @param startClass an optional start class in the hierarchy of parameter objects for which this handler should be |
| * applied |
| * @throws IllegalArgumentException if a required parameter is missing |
| */ |
| public <T> void registerDefaultsHandler(final Class<T> paramsClass, final DefaultParametersHandler<? super T> handler, final Class<?> startClass) { |
| getDefaultParametersManager().registerDefaultsHandler(paramsClass, handler, startClass); |
| } |
| |
| /** |
| * Creates a new instance of a parameters object for XML configurations. |
| * |
| * @return the new parameters object |
| */ |
| public XMLBuilderParameters xml() { |
| return createParametersProxy(new XMLBuilderParametersImpl(), XMLBuilderParameters.class, FileBasedBuilderParameters.class, |
| HierarchicalBuilderParameters.class); |
| } |
| } |