All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.commons.configuration2.builder.BuilderConfigurationWrapperFactory Maven / Gradle / Ivy

Go to download

Tools to assist in the reading of configuration/preferences files in various formats

There is a newer version: 2.11.0
Show newest version
/*
 * 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;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.apache.commons.configuration2.ConfigurationUtils;
import org.apache.commons.configuration2.ImmutableConfiguration;
import org.apache.commons.configuration2.event.EventSource;

/**
 * 

* A class that allows the creation of configuration objects wrapping a * {@link ConfigurationBuilder}. *

*

* Using this class special {@code ImmutableConfiguration} proxies can be created that * delegate all method invocations to another {@code ImmutableConfiguration} obtained * from a {@code ConfigurationBuilder}. For instance, if there is a * configuration {@code c} wrapping the builder {@code builder}, the call * {@code c.getString(myKey)} is transformed to * {@code builder.getConfiguration().getString(myKey)}. *

*

* There are multiple use cases for such a constellation. One example is that * client code can continue working with {@code ImmutableConfiguration} objects while * under the hood builders are used. Another example is that dynamic * configurations can be realized in a transparent way: a client holds a single * configuration (proxy) object, but the underlying builder may return a * different data object on each call. *

* * @since 2.0 */ public class BuilderConfigurationWrapperFactory { /** The current {@code EventSourceSupport} value. */ private final EventSourceSupport eventSourceSupport; /** * Creates a new instance of {@code BuilderConfigurationWrapperFactory} and * sets the property for supporting the {@code EventSource} interface. * * @param evSrcSupport the level of {@code EventSource} support */ public BuilderConfigurationWrapperFactory(final EventSourceSupport evSrcSupport) { eventSourceSupport = evSrcSupport; } /** * Creates a new instance of {@code BuilderConfigurationWrapperFactory} * setting the default {@code EventSourceSupport} NONE. */ public BuilderConfigurationWrapperFactory() { this(EventSourceSupport.NONE); } /** * Creates a wrapper {@code ImmutableConfiguration} on top of the specified * {@code ConfigurationBuilder}. This implementation delegates to * {@link #createBuilderConfigurationWrapper(Class, ConfigurationBuilder, EventSourceSupport)} * . * * @param the type of the configuration objects returned by this method * @param ifcClass the class of the configuration objects returned by this * method; this must be an interface class and must not be * null * @param builder the wrapped {@code ConfigurationBuilder} (must not be * null) * @return the wrapper configuration * @throws IllegalArgumentException if a required parameter is missing * @throws org.apache.commons.configuration2.ex.ConfigurationRuntimeException if an error * occurs when creating the result {@code ImmutableConfiguration} */ public T createBuilderConfigurationWrapper( final Class ifcClass, final ConfigurationBuilder builder) { return createBuilderConfigurationWrapper(ifcClass, builder, getEventSourceSupport()); } /** * Returns the level of {@code EventSource} support used when generating * {@code ImmutableConfiguration} objects. * * @return the level of {@code EventSource} support */ public EventSourceSupport getEventSourceSupport() { return eventSourceSupport; } /** * Returns a {@code ImmutableConfiguration} object which wraps the specified * {@code ConfigurationBuilder}. Each access of the configuration is * delegated to a corresponding call on the {@code ImmutableConfiguration} object * managed by the builder. This is a convenience method which allows * creating wrapper configurations without having to instantiate this class. * * @param the type of the configuration objects returned by this method * @param ifcClass the class of the configuration objects returned by this * method; this must be an interface class and must not be * null * @param builder the wrapped {@code ConfigurationBuilder} (must not be * null) * @param evSrcSupport the level of {@code EventSource} support * @return the wrapper configuration * @throws IllegalArgumentException if a required parameter is missing * @throws org.apache.commons.configuration2.ex.ConfigurationRuntimeException if an error * occurs when creating the result {@code ImmutableConfiguration} */ public static T createBuilderConfigurationWrapper( final Class ifcClass, final ConfigurationBuilder builder, final EventSourceSupport evSrcSupport) { if (ifcClass == null) { throw new IllegalArgumentException( "Interface class must not be null!"); } if (builder == null) { throw new IllegalArgumentException("Builder must not be null!"); } return ifcClass.cast(Proxy.newProxyInstance( BuilderConfigurationWrapperFactory.class.getClassLoader(), fetchSupportedInterfaces(ifcClass, evSrcSupport), new BuilderConfigurationWrapperInvocationHandler(builder, evSrcSupport))); } /** * Returns an array with the classes the generated proxy has to support. * * @param ifcClass the class of the configuration objects returned by this * method; this must be an interface class and must not be * null * @param evSrcSupport the level of {@code EventSource} support * @return an array with the interface classes to implement */ private static Class[] fetchSupportedInterfaces(final Class ifcClass, final EventSourceSupport evSrcSupport) { if (EventSourceSupport.NONE == evSrcSupport) { return new Class[] { ifcClass }; } final Class[] result = new Class[2]; result[0] = EventSource.class; result[1] = ifcClass; return result; } /** *

* An enumeration class with different options for supporting the * {@code EventSource} interface in generated {@code ImmutableConfiguration} proxies. *

*

* Using literals of this class it is possible to specify that a * {@code ImmutableConfiguration} object returned by * {@code BuilderConfigurationWrapperFactory} also implements the * {@code EventSource} interface and how this implementation should work. * See the documentation of the single constants for more details. *

*/ public enum EventSourceSupport { /** * No support of the {@code EventSource} interface. If this option is * set, {@code ImmutableConfiguration} objects generated by * {@code BuilderConfigurationWrapperFactory} do not implement the * {@code EventSource} interface. */ NONE, /** * Dummy support of the {@code EventSource} interface. This option * causes {@code ImmutableConfiguration} objects generated by * {@code BuilderConfigurationWrapperFactory} to implement the * {@code EventSource} interface, however, this implementation consists * only of empty dummy methods without real functionality. */ DUMMY, /** * {@code EventSource} support is implemented by delegating to the * associated {@code ConfigurationBuilder} object. If this option is * used, generated {@code ImmutableConfiguration} objects provide a fully * functional implementation of {@code EventSource} by delegating to the * builder. Because the {@code ConfigurationBuilder} interface extends * {@code EventSource} this delegation is always possible. */ BUILDER } /** * A specialized {@code InvocationHandler} implementation for wrapper * configurations. Here the logic of accessing a wrapped builder is * implemented. */ private static class BuilderConfigurationWrapperInvocationHandler implements InvocationHandler { /** The wrapped builder. */ private final ConfigurationBuilder builder; /** The level of {@code EventSource} support. */ private final EventSourceSupport eventSourceSupport; /** * Creates a new instance of * {@code BuilderConfigurationWrapperInvocationHandler}. * * @param wrappedBuilder the wrapped builder * @param evSrcSupport the level of {@code EventSource} support */ public BuilderConfigurationWrapperInvocationHandler( final ConfigurationBuilder wrappedBuilder, final EventSourceSupport evSrcSupport) { builder = wrappedBuilder; eventSourceSupport = evSrcSupport; } /** * Handles method invocations. This implementation handles methods of * two different interfaces: *
    *
  • Methods from the {@code EventSource} interface are handled * according to the current support level.
  • *
  • Other method calls are delegated to the builder's configuration * object.
  • *
* * @param proxy the proxy object * @param method the method to be invoked * @param args method arguments * @return the return value of the method * @throws Throwable if an error occurs */ @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { if (EventSource.class.equals(method.getDeclaringClass())) { return handleEventSourceInvocation(method, args); } return handleConfigurationInvocation(method, args); } /** * Handles a method invocation on the associated builder's configuration * object. * * @param method the method to be invoked * @param args method arguments * @return the return value of the method * @throws Exception if an error occurs */ private Object handleConfigurationInvocation(final Method method, final Object[] args) throws Exception { return method.invoke(builder.getConfiguration(), args); } /** * Handles a method invocation on the {@code EventSource} interface. * This method evaluates the current {@code EventSourceSupport} object * in order to find the appropriate target for the invocation. * * @param method the method to be invoked * @param args method arguments * @return the return value of the method * @throws Exception if an error occurs */ private Object handleEventSourceInvocation(final Method method, final Object... args) throws Exception { final Object target = EventSourceSupport.DUMMY == eventSourceSupport ? ConfigurationUtils .asEventSource(this, true) : builder; return method.invoke(target, args); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy