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.Arrays; 020 021import org.apache.commons.configuration2.Configuration; 022import org.apache.commons.configuration2.ConfigurationUtils; 023import org.apache.commons.configuration2.HierarchicalConfiguration; 024import org.apache.commons.configuration2.builder.BuilderConfigurationWrapperFactory; 025import org.apache.commons.configuration2.builder.BuilderConfigurationWrapperFactory.EventSourceSupport; 026import org.apache.commons.configuration2.builder.ConfigurationBuilder; 027import org.apache.commons.configuration2.event.Event; 028import org.apache.commons.configuration2.event.EventListener; 029import org.apache.commons.configuration2.event.EventType; 030import org.apache.commons.configuration2.ex.ConfigurationException; 031import org.apache.commons.configuration2.reloading.ReloadingController; 032import org.apache.commons.configuration2.reloading.ReloadingControllerSupport; 033 034/** 035 * <p> 036 * A specialized {@code ConfigurationBuilderProvider} implementation for 037 * integrating {@link MultiFileConfigurationBuilder} with 038 * {@code CombinedConfigurationBuilder}. 039 * </p> 040 * <p> 041 * When using a configuration source managed by 042 * {@code MultiFileConfigurationBuilder} it is not sufficient to store the 043 * configuration once obtained from the builder in the resulting combined 044 * configuration. Rather, it has to be ensured that each access to this 045 * configuration queries the builder anew so that it can evaluate its file 046 * pattern and return a different configuration if necessary. Therefore, this 047 * class returns a specialized wrapper over a 048 * {@code MultiFileConfigurationBuilder} which returns a configuration wrapping 049 * the builder; so accessing the configuration's properties actually calls back 050 * to the builder. This constellation is compatible with the way 051 * {@code DynamicCombinedConfiguration} manages its data. 052 * </p> 053 * 054 * @version $Id: MultiFileConfigurationBuilderProvider.java 1706911 2015-10-05 20:01:32Z oheger $ 055 * @since 2.0 056 */ 057public class MultiFileConfigurationBuilderProvider extends 058 BaseConfigurationBuilderProvider 059{ 060 /** Constant for the name of the builder class. */ 061 private static final String BUILDER_CLASS = 062 "org.apache.commons.configuration2.builder.combined.MultiFileConfigurationBuilder"; 063 064 /** Constant for the name of the reloading builder class. */ 065 private static final String RELOADING_BUILDER_CLASS = 066 "org.apache.commons.configuration2.builder.combined.ReloadingMultiFileConfigurationBuilder"; 067 068 /** Constant for the name of the parameters class. */ 069 private static final String PARAM_CLASS = 070 "org.apache.commons.configuration2.builder.combined.MultiFileBuilderParametersImpl"; 071 072 /** 073 * Creates a new instance of {@code MultiFileConfigurationBuilderProvider} 074 * and sets the name of the configuration class to be returned by 075 * {@code MultiFileConfigurationBuilder}. 076 * 077 * @param configCls the name of the managed configuration class 078 * @param paramCls the name of the class of the parameters object to 079 * configure the managed configuration 080 */ 081 public MultiFileConfigurationBuilderProvider(String configCls, 082 String paramCls) 083 { 084 super(BUILDER_CLASS, RELOADING_BUILDER_CLASS, configCls, Arrays.asList( 085 paramCls, PARAM_CLASS)); 086 } 087 088 /** 089 * {@inheritDoc} This implementation lets the super class create a fully 090 * configured builder. Then it returns a special wrapper around it. 091 */ 092 @Override 093 public ConfigurationBuilder<? extends Configuration> getConfigurationBuilder( 094 ConfigurationDeclaration decl) throws ConfigurationException 095 { 096 ConfigurationBuilder<? extends Configuration> multiBuilder = 097 super.getConfigurationBuilder(decl); 098 Configuration wrapConfig = createWrapperConfiguration(multiBuilder); 099 return createWrapperBuilder(multiBuilder, wrapConfig); 100 } 101 102 /** 103 * Creates a configuration which wraps the specified builder. 104 * 105 * @param builder the builder 106 * @return the wrapping configuration 107 */ 108 // It is safe to disable any type checks because we manually determine 109 // the interface class to be passed to BuilderConfigurationWrapperFactory 110 @SuppressWarnings({ 111 "unchecked", "rawtypes" 112 }) 113 private Configuration createWrapperConfiguration( 114 ConfigurationBuilder builder) 115 { 116 Class<?> configClass = 117 ConfigurationUtils.loadClassNoEx(getConfigurationClass()); 118 Class ifcClass = 119 HierarchicalConfiguration.class.isAssignableFrom(configClass) ? HierarchicalConfiguration.class 120 : Configuration.class; 121 return (Configuration) BuilderConfigurationWrapperFactory 122 .createBuilderConfigurationWrapper(ifcClass, builder, 123 EventSourceSupport.BUILDER); 124 } 125 126 /** 127 * Creates the {@code ConfigurationBuilder} to be returned by this provider. 128 * This is a very simple implementation which always returns the same 129 * wrapper configuration instance. The handling of builder listeners is 130 * delegated to the wrapped {@code MultiFileConfigurationBuilder}. If 131 * reloading is support, the builder returned by this method also implements 132 * the {@link ReloadingControllerSupport} interface. 133 * 134 * @param multiBuilder the {@code MultiFileConfigurationBuilder} 135 * @param wrapConfig the configuration to be returned 136 * @return the wrapper builder 137 */ 138 private static ConfigurationBuilder<? extends Configuration> createWrapperBuilder( 139 ConfigurationBuilder<? extends Configuration> multiBuilder, 140 Configuration wrapConfig) 141 { 142 if (multiBuilder instanceof ReloadingControllerSupport) 143 { 144 return new ReloadableWrapperBuilder(wrapConfig, multiBuilder); 145 } 146 else 147 { 148 return new WrapperBuilder(wrapConfig, multiBuilder); 149 } 150 } 151 152 /** 153 * A simple wrapper implementation of the {@code ConfigurationBuilder} 154 * interface which returns a fix configuration and delegates to another 155 * builder for event listener management. 156 */ 157 private static class WrapperBuilder implements 158 ConfigurationBuilder<Configuration> 159 { 160 /** The configuration managed by this builder. */ 161 private final Configuration configuration; 162 163 /** The builder to which this instance delegates. */ 164 private final ConfigurationBuilder<? extends Configuration> builder; 165 166 /** 167 * Creates a new instance of {@code WrapperBuilder}. 168 * 169 * @param conf the managed configuration 170 * @param bldr the underlying builder 171 */ 172 public WrapperBuilder(Configuration conf, 173 ConfigurationBuilder<? extends Configuration> bldr) 174 { 175 configuration = conf; 176 builder = bldr; 177 } 178 179 @Override 180 public Configuration getConfiguration() throws ConfigurationException 181 { 182 return configuration; 183 } 184 185 @Override 186 public <T extends Event> void addEventListener( 187 EventType<T> eventType, EventListener<? super T> listener) 188 { 189 builder.addEventListener(eventType, listener); 190 } 191 192 @Override 193 public <T extends Event> boolean removeEventListener( 194 EventType<T> eventType, EventListener<? super T> listener) 195 { 196 return builder.removeEventListener(eventType, listener); 197 } 198 } 199 200 /** 201 * A wrapper builder implementation which also provides a 202 * {@code ReloadingController}. This class assumes that the wrapped builder 203 * implements {@code ReloadingControllerSupport}. So the reloading 204 * controller can be obtained from this object. 205 */ 206 private static class ReloadableWrapperBuilder extends WrapperBuilder 207 implements ReloadingControllerSupport 208 { 209 /** The object for obtaining the reloading controller. */ 210 private final ReloadingControllerSupport ctrlSupport; 211 212 /** 213 * Creates a new instance of {@code ReloadableWrapperBuilder}. 214 * 215 * @param conf the managed configuration 216 * @param bldr the underlying builder (must implement 217 * {@code ReloadingControllerSupport}) 218 */ 219 public ReloadableWrapperBuilder(Configuration conf, 220 ConfigurationBuilder<? extends Configuration> bldr) 221 { 222 super(conf, bldr); 223 ctrlSupport = (ReloadingControllerSupport) bldr; 224 } 225 226 @Override 227 public ReloadingController getReloadingController() 228 { 229 return ctrlSupport.getReloadingController(); 230 } 231 } 232}