| /* |
| * 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.combined; |
| |
| import java.util.Arrays; |
| |
| import org.apache.commons.configuration2.Configuration; |
| import org.apache.commons.configuration2.ConfigurationUtils; |
| import org.apache.commons.configuration2.HierarchicalConfiguration; |
| import org.apache.commons.configuration2.builder.BuilderConfigurationWrapperFactory; |
| import org.apache.commons.configuration2.builder.BuilderConfigurationWrapperFactory.EventSourceSupport; |
| import org.apache.commons.configuration2.builder.ConfigurationBuilder; |
| import org.apache.commons.configuration2.event.Event; |
| import org.apache.commons.configuration2.event.EventListener; |
| import org.apache.commons.configuration2.event.EventType; |
| import org.apache.commons.configuration2.ex.ConfigurationException; |
| import org.apache.commons.configuration2.reloading.ReloadingController; |
| import org.apache.commons.configuration2.reloading.ReloadingControllerSupport; |
| |
| /** |
| * <p> |
| * A specialized {@code ConfigurationBuilderProvider} implementation for |
| * integrating {@link MultiFileConfigurationBuilder} with |
| * {@code CombinedConfigurationBuilder}. |
| * </p> |
| * <p> |
| * When using a configuration source managed by |
| * {@code MultiFileConfigurationBuilder} it is not sufficient to store the |
| * configuration once obtained from the builder in the resulting combined |
| * configuration. Rather, it has to be ensured that each access to this |
| * configuration queries the builder anew so that it can evaluate its file |
| * pattern and return a different configuration if necessary. Therefore, this |
| * class returns a specialized wrapper over a |
| * {@code MultiFileConfigurationBuilder} which returns a configuration wrapping |
| * the builder; so accessing the configuration's properties actually calls back |
| * to the builder. This constellation is compatible with the way |
| * {@code DynamicCombinedConfiguration} manages its data. |
| * </p> |
| * |
| * @version $Id$ |
| * @since 2.0 |
| */ |
| public class MultiFileConfigurationBuilderProvider extends |
| BaseConfigurationBuilderProvider |
| { |
| /** Constant for the name of the builder class. */ |
| private static final String BUILDER_CLASS = |
| "org.apache.commons.configuration2.builder.combined.MultiFileConfigurationBuilder"; |
| |
| /** Constant for the name of the reloading builder class. */ |
| private static final String RELOADING_BUILDER_CLASS = |
| "org.apache.commons.configuration2.builder.combined.ReloadingMultiFileConfigurationBuilder"; |
| |
| /** Constant for the name of the parameters class. */ |
| private static final String PARAM_CLASS = |
| "org.apache.commons.configuration2.builder.combined.MultiFileBuilderParametersImpl"; |
| |
| /** |
| * Creates a new instance of {@code MultiFileConfigurationBuilderProvider} |
| * and sets the name of the configuration class to be returned by |
| * {@code MultiFileConfigurationBuilder}. |
| * |
| * @param configCls the name of the managed configuration class |
| * @param paramCls the name of the class of the parameters object to |
| * configure the managed configuration |
| */ |
| public MultiFileConfigurationBuilderProvider(String configCls, |
| String paramCls) |
| { |
| super(BUILDER_CLASS, RELOADING_BUILDER_CLASS, configCls, Arrays.asList( |
| paramCls, PARAM_CLASS)); |
| } |
| |
| /** |
| * {@inheritDoc} This implementation lets the super class create a fully |
| * configured builder. Then it returns a special wrapper around it. |
| */ |
| @Override |
| public ConfigurationBuilder<? extends Configuration> getConfigurationBuilder( |
| ConfigurationDeclaration decl) throws ConfigurationException |
| { |
| ConfigurationBuilder<? extends Configuration> multiBuilder = |
| super.getConfigurationBuilder(decl); |
| Configuration wrapConfig = createWrapperConfiguration(multiBuilder); |
| return createWrapperBuilder(multiBuilder, wrapConfig); |
| } |
| |
| /** |
| * Creates a configuration which wraps the specified builder. |
| * |
| * @param builder the builder |
| * @return the wrapping configuration |
| */ |
| // It is safe to disable any type checks because we manually determine |
| // the interface class to be passed to BuilderConfigurationWrapperFactory |
| @SuppressWarnings({ |
| "unchecked", "rawtypes" |
| }) |
| private Configuration createWrapperConfiguration( |
| ConfigurationBuilder builder) |
| { |
| Class<?> configClass = |
| ConfigurationUtils.loadClassNoEx(getConfigurationClass()); |
| Class ifcClass = |
| HierarchicalConfiguration.class.isAssignableFrom(configClass) ? HierarchicalConfiguration.class |
| : Configuration.class; |
| return (Configuration) BuilderConfigurationWrapperFactory |
| .createBuilderConfigurationWrapper(ifcClass, builder, |
| EventSourceSupport.BUILDER); |
| } |
| |
| /** |
| * Creates the {@code ConfigurationBuilder} to be returned by this provider. |
| * This is a very simple implementation which always returns the same |
| * wrapper configuration instance. The handling of builder listeners is |
| * delegated to the wrapped {@code MultiFileConfigurationBuilder}. If |
| * reloading is support, the builder returned by this method also implements |
| * the {@link ReloadingControllerSupport} interface. |
| * |
| * @param multiBuilder the {@code MultiFileConfigurationBuilder} |
| * @param wrapConfig the configuration to be returned |
| * @return the wrapper builder |
| */ |
| private static ConfigurationBuilder<? extends Configuration> createWrapperBuilder( |
| ConfigurationBuilder<? extends Configuration> multiBuilder, |
| Configuration wrapConfig) |
| { |
| if (multiBuilder instanceof ReloadingControllerSupport) |
| { |
| return new ReloadableWrapperBuilder(wrapConfig, multiBuilder); |
| } |
| else |
| { |
| return new WrapperBuilder(wrapConfig, multiBuilder); |
| } |
| } |
| |
| /** |
| * A simple wrapper implementation of the {@code ConfigurationBuilder} |
| * interface which returns a fix configuration and delegates to another |
| * builder for event listener management. |
| */ |
| private static class WrapperBuilder implements |
| ConfigurationBuilder<Configuration> |
| { |
| /** The configuration managed by this builder. */ |
| private final Configuration configuration; |
| |
| /** The builder to which this instance delegates. */ |
| private final ConfigurationBuilder<? extends Configuration> builder; |
| |
| /** |
| * Creates a new instance of {@code WrapperBuilder}. |
| * |
| * @param conf the managed configuration |
| * @param bldr the underlying builder |
| */ |
| public WrapperBuilder(Configuration conf, |
| ConfigurationBuilder<? extends Configuration> bldr) |
| { |
| configuration = conf; |
| builder = bldr; |
| } |
| |
| @Override |
| public Configuration getConfiguration() throws ConfigurationException |
| { |
| return configuration; |
| } |
| |
| @Override |
| public <T extends Event> void addEventListener( |
| EventType<T> eventType, EventListener<? super T> listener) |
| { |
| builder.addEventListener(eventType, listener); |
| } |
| |
| @Override |
| public <T extends Event> boolean removeEventListener( |
| EventType<T> eventType, EventListener<? super T> listener) |
| { |
| return builder.removeEventListener(eventType, listener); |
| } |
| } |
| |
| /** |
| * A wrapper builder implementation which also provides a |
| * {@code ReloadingController}. This class assumes that the wrapped builder |
| * implements {@code ReloadingControllerSupport}. So the reloading |
| * controller can be obtained from this object. |
| */ |
| private static class ReloadableWrapperBuilder extends WrapperBuilder |
| implements ReloadingControllerSupport |
| { |
| /** The object for obtaining the reloading controller. */ |
| private final ReloadingControllerSupport ctrlSupport; |
| |
| /** |
| * Creates a new instance of {@code ReloadableWrapperBuilder}. |
| * |
| * @param conf the managed configuration |
| * @param bldr the underlying builder (must implement |
| * {@code ReloadingControllerSupport}) |
| */ |
| public ReloadableWrapperBuilder(Configuration conf, |
| ConfigurationBuilder<? extends Configuration> bldr) |
| { |
| super(conf, bldr); |
| ctrlSupport = (ReloadingControllerSupport) bldr; |
| } |
| |
| @Override |
| public ReloadingController getReloadingController() |
| { |
| return ctrlSupport.getReloadingController(); |
| } |
| } |
| } |