View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     https://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.configuration2.builder.combined;
18  
19  import java.util.Collection;
20  
21  import org.apache.commons.configuration2.builder.BuilderParameters;
22  import org.apache.commons.configuration2.builder.FileBasedBuilderParametersImpl;
23  import org.apache.commons.configuration2.ex.ConfigurationException;
24  
25  /**
26   * <p>
27   * A specialized implementation of {@link ConfigurationBuilderProvider} which determines the name of the result
28   * configuration class based on the extension of the file to load.
29   * </p>
30   * <p>
31   * This class works analogously to its base class {@link BaseConfigurationBuilderProvider}; especially, the resulting
32   * builder is created based on reflection. It extends the super class's functionality by a specific mechanism for
33   * determining the resulting configuration class: At construction time two configuration class names and a file
34   * extension are passed in. If a file name is provided in the builder's initialization parameters and this file name has
35   * the specified extension, then the first configuration class name is used; otherwise the default configuration class
36   * name is selected.
37   * </p>
38   * <p>
39   * There are some tags for {@code CombinedConfigurationProvider} which can produce different results depending on the
40   * configuration files they have to load. This class can be used to implement this feature in a generic way.
41   * </p>
42   *
43   * @since 2.0
44   */
45  public class FileExtensionConfigurationBuilderProvider extends BaseConfigurationBuilderProvider {
46  
47      /** Constant for the file extension separator. */
48      private static final char EXT_SEPARATOR = '.';
49  
50      /**
51       * Extracts the extension from the given file name. The name can be <strong>null</strong>.
52       *
53       * @param fileName the file name
54       * @return the extension (<strong>null</strong> if there is none)
55       */
56      private static String extractExtension(final String fileName) {
57          if (fileName == null) {
58              return null;
59          }
60  
61          final int pos = fileName.lastIndexOf(EXT_SEPARATOR);
62          return pos < 0 ? null : fileName.substring(pos + 1);
63      }
64  
65      /**
66       * Tries to obtain the current file name from the given list of parameter objects.
67       *
68       * @param params the parameter objects
69       * @return the file name or <strong>null</strong> if unspecified
70       */
71      private static String fetchCurrentFileName(final Collection<BuilderParameters> params) {
72          for (final BuilderParameters p : params) {
73              if (p instanceof FileBasedBuilderParametersImpl) {
74                  final FileBasedBuilderParametersImpl fp = (FileBasedBuilderParametersImpl) p;
75                  return fp.getFileHandler().getFileName();
76              }
77          }
78          return null;
79      }
80  
81      /** The matching configuration class. */
82      private final String matchingConfigurationClass;
83  
84      /** The file extension. */
85      private final String extension;
86  
87      /**
88       * Creates a new instance of {@code FileExtensionConfigurationBuilderProvider}.
89       *
90       * @param bldrCls the name of the builder class
91       * @param reloadBldrCls the name of a builder class to be used if reloading support is required (<strong>null</strong> if
92       *        reloading is not supported)
93       * @param matchingConfigCls the name of the configuration class to be used if the provided file extension matches (must
94       *        not be <strong>null</strong>)
95       * @param defConfigClass the name of the configuration class to be used if the provided file extension does not match
96       *        (must not be <strong>null</strong>)
97       * @param ext the file extension to select the configuration class (must not be <strong>null</strong>)
98       * @param paramCls a collection with the names of parameters classes; an instance of a parameters object with basic
99       *        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 }