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 * https://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.Collection; 020 021import org.apache.commons.configuration2.builder.BuilderParameters; 022import org.apache.commons.configuration2.builder.FileBasedBuilderParametersImpl; 023import org.apache.commons.configuration2.ex.ConfigurationException; 024 025/** 026 * <p> 027 * A specialized implementation of {@link ConfigurationBuilderProvider} which determines the name of the result 028 * configuration class based on the extension of the file to load. 029 * </p> 030 * <p> 031 * This class works analogously to its base class {@link BaseConfigurationBuilderProvider}; especially, the resulting 032 * builder is created based on reflection. It extends the super class's functionality by a specific mechanism for 033 * determining the resulting configuration class: At construction time two configuration class names and a file 034 * extension are passed in. If a file name is provided in the builder's initialization parameters and this file name has 035 * the specified extension, then the first configuration class name is used; otherwise the default configuration class 036 * name is selected. 037 * </p> 038 * <p> 039 * There are some tags for {@code CombinedConfigurationProvider} which can produce different results depending on the 040 * configuration files they have to load. This class can be used to implement this feature in a generic way. 041 * </p> 042 * 043 * @since 2.0 044 */ 045public class FileExtensionConfigurationBuilderProvider extends BaseConfigurationBuilderProvider { 046 047 /** Constant for the file extension separator. */ 048 private static final char EXT_SEPARATOR = '.'; 049 050 /** 051 * Extracts the extension from the given file name. The name can be <strong>null</strong>. 052 * 053 * @param fileName the file name 054 * @return the extension (<strong>null</strong> if there is none) 055 */ 056 private static String extractExtension(final String fileName) { 057 if (fileName == null) { 058 return null; 059 } 060 061 final int pos = fileName.lastIndexOf(EXT_SEPARATOR); 062 return pos < 0 ? null : fileName.substring(pos + 1); 063 } 064 065 /** 066 * Tries to obtain the current file name from the given list of parameter objects. 067 * 068 * @param params the parameter objects 069 * @return the file name or <strong>null</strong> if unspecified 070 */ 071 private static String fetchCurrentFileName(final Collection<BuilderParameters> params) { 072 for (final BuilderParameters p : params) { 073 if (p instanceof FileBasedBuilderParametersImpl) { 074 final FileBasedBuilderParametersImpl fp = (FileBasedBuilderParametersImpl) p; 075 return fp.getFileHandler().getFileName(); 076 } 077 } 078 return null; 079 } 080 081 /** The matching configuration class. */ 082 private final String matchingConfigurationClass; 083 084 /** The file extension. */ 085 private final String extension; 086 087 /** 088 * Creates a new instance of {@code FileExtensionConfigurationBuilderProvider}. 089 * 090 * @param bldrCls the name of the builder class 091 * @param reloadBldrCls the name of a builder class to be used if reloading support is required (<strong>null</strong> if 092 * reloading is not supported) 093 * @param matchingConfigCls the name of the configuration class to be used if the provided file extension matches (must 094 * not be <strong>null</strong>) 095 * @param defConfigClass the name of the configuration class to be used if the provided file extension does not match 096 * (must not be <strong>null</strong>) 097 * @param ext the file extension to select the configuration class (must not be <strong>null</strong>) 098 * @param paramCls a collection with the names of parameters classes; an instance of a parameters object with basic 099 * properties is created automatically and does not need to be contained in this list; the collection can be 100 * <strong>null</strong> if no additional parameter objects are needed 101 * @throws IllegalArgumentException if a required parameter is missing 102 */ 103 public FileExtensionConfigurationBuilderProvider(final String bldrCls, final String reloadBldrCls, final String matchingConfigCls, 104 final String defConfigClass, final String ext, final Collection<String> paramCls) { 105 super(bldrCls, reloadBldrCls, defConfigClass, paramCls); 106 if (matchingConfigCls == null) { 107 throw new IllegalArgumentException("Matching configuration class must not be null!"); 108 } 109 if (ext == null) { 110 throw new IllegalArgumentException("File extension must not be null!"); 111 } 112 113 matchingConfigurationClass = matchingConfigCls; 114 extension = ext; 115 } 116 117 /** 118 * {@inheritDoc} This implementation tries to find a {@link FileBasedBuilderParametersImpl} object in the parameter 119 * objects. If one is found, the extension of the file name is obtained and compared against the stored file extension. 120 * In case of a match, the matching configuration class is selected, otherwise the default one. 121 */ 122 @Override 123 protected String determineConfigurationClass(final ConfigurationDeclaration decl, final Collection<BuilderParameters> params) 124 throws ConfigurationException { 125 final String currentExt = extractExtension(fetchCurrentFileName(params)); 126 return getExtension().equalsIgnoreCase(currentExt) ? getMatchingConfigurationClass() : getConfigurationClass(); 127 } 128 129 /** 130 * Gets the file extension of this provider. 131 * 132 * @return the file extension to match 133 */ 134 public String getExtension() { 135 return extension; 136 } 137 138 /** 139 * Gets the name of the matching configuration class. This class is used if the file extension matches the extension 140 * of this provider. 141 * 142 * @return the matching configuration class 143 */ 144 public String getMatchingConfigurationClass() { 145 return matchingConfigurationClass; 146 } 147}