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.io;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.net.URL;
22  
23  import org.apache.commons.lang3.StringUtils;
24  import org.apache.commons.lang3.SystemProperties;
25  
26  /**
27   * A specialized implementation of {@code FileLocationStrategy} which searches for files in the user's home directory or
28   * another special configurable directory.
29   * <p>
30   * This strategy implementation ignores the URL stored in the passed in {@link FileLocator}. It constructs a file path
31   * from the configured home directory (which is the user's home directory per default, but can be changed to another
32   * path), optionally the base path, and the file name. If the resulting path points to an existing file, its URL is
33   * returned.
34   * </p>
35   * <p>
36   * When constructing an instance it can be configured whether the base path should be taken into account. If this option
37   * is set, the base path is appended to the home directory if it is not {@code null}. This is useful for instance to
38   * select a specific sub directory of the user's home directory. If this option is set to <strong>false</strong>, the base path is
39   * always ignored, and only the file name is evaluated.
40   * </p>
41   * <p>
42   * See {@link AbstractFileLocationStrategy} learn how to grant an deny URL schemes and hosts.
43   * </p>
44   *
45   * @see AbstractFileLocationStrategy
46   */
47  public class HomeDirectoryLocationStrategy extends AbstractFileLocationStrategy {
48  
49      /**
50       * Builds new instances of {@link HomeDirectoryLocationStrategy}.
51       *
52       * @since 2.15.0
53       */
54      public static class Builder extends AbstractBuilder<HomeDirectoryLocationStrategy, Builder> {
55  
56          /** The flag whether the base path is to be taken into account. */
57          private boolean evaluateBasePath;
58  
59          /** The home directory to be searched for the requested file. */
60          private String homeDirectory;
61  
62          /**
63           * Constructs a new instance.
64           */
65          public Builder() {
66              // empty
67          }
68  
69          @Override
70          public HomeDirectoryLocationStrategy get() throws IOException {
71              return new HomeDirectoryLocationStrategy(this);
72          }
73  
74          /**
75           * Sets whether the base path should be evaluated.
76           *
77           * @param evaluateBasePath whether the base path should be evaluated.
78           * @return {@code this} instance..
79           */
80          public Builder setEvaluateBasePath(final boolean evaluateBasePath) {
81              this.evaluateBasePath = evaluateBasePath;
82              return asThis();
83          }
84  
85          /**
86           * Sets the path to the home directory (may be {@code null}).
87           *
88           * @param homeDirectory the path to the home directory (may be {@code null})
89           * @return {@code this} instance..
90           */
91          public Builder setHomeDirectory(final String homeDirectory) {
92              this.homeDirectory = homeDirectory;
93              return asThis();
94          }
95      }
96  
97      /**
98       * Gets the home directory to be used by a new instance. If a directory name is provided, it is used. Otherwise, the
99       * user's home directory is looked up.
100      *
101      * @param homeDir the passed in home directory
102      * @return the directory to be used
103      */
104     private static String getHomeDirectory(final String homeDir) {
105         return homeDir != null ? homeDir : SystemProperties.getUserHome();
106     }
107 
108     /** The flag whether the base path is to be taken into account. */
109     private final boolean evaluateBasePath;
110 
111     /** The home directory to be searched for the requested file. */
112     private final String homeDirectory;
113 
114     /**
115      * Creates a new instance of {@code HomeDirectoryLocationStrategy} with default settings. The home directory is set to
116      * the user's home directory. The base path flag is set to <strong>false</strong> (which means that the base path is ignored).
117      */
118     public HomeDirectoryLocationStrategy() {
119         this(false);
120     }
121 
122     /**
123      * Creates a new instance of {@code HomeDirectoryLocationStrategy} and initializes the base path flag. The home
124      * directory is set to the user's home directory.
125      *
126      * @param withBasePath a flag whether the base path should be evaluated.
127      * @deprecated Use {@link Builder#setEvaluateBasePath(boolean)}.
128      */
129     @Deprecated
130     public HomeDirectoryLocationStrategy(final boolean withBasePath) {
131         this(new Builder().setHomeDirectory(null).setEvaluateBasePath(withBasePath));
132     }
133 
134     /**
135      * Constructs a new instance.
136      *
137      * @param builder How to build the instance.
138      */
139     private HomeDirectoryLocationStrategy(final Builder builder) {
140         super(builder);
141         homeDirectory = getHomeDirectory(builder.homeDirectory);
142         evaluateBasePath = builder.evaluateBasePath;
143     }
144 
145     /**
146      * Creates a new instance of {@code HomeDirectoryLocationStrategy} and initializes it with the specified settings.
147      *
148      * @param homeDir the path to the home directory (may be {@code null}).
149      * @param withBasePath a flag whether the base path should be evaluated.
150      * @deprecated Use {@link Builder#setHomeDirectory(String)}.
151      */
152     @Deprecated
153     public HomeDirectoryLocationStrategy(final String homeDir, final boolean withBasePath) {
154         this(new Builder().setHomeDirectory(homeDir).setEvaluateBasePath(withBasePath));
155     }
156 
157     /**
158      * Determines the base path to be used for the current locate() operation.
159      *
160      * @param locator the {@code FileLocator}
161      * @return the base path to be used
162      */
163     private String getBasePath(final FileLocator locator) {
164         if (isEvaluateBasePath() && StringUtils.isNotEmpty(locator.getBasePath())) {
165             return FileLocatorUtils.appendPath(getHomeDirectory(), locator.getBasePath());
166         }
167         return getHomeDirectory();
168     }
169 
170     /**
171      * Gets the home directory. In this directory the strategy searches for files.
172      *
173      * @return the home directory used by this object.
174      */
175     public String getHomeDirectory() {
176         return homeDirectory;
177     }
178 
179     /**
180      * Returns a flag whether the base path is to be taken into account when searching for a file.
181      *
182      * @return the flag whether the base path is evaluated
183      */
184     public boolean isEvaluateBasePath() {
185         return evaluateBasePath;
186     }
187 
188     /**
189      * {@inheritDoc} This implementation searches in the home directory for a file described by the passed in
190      * {@code FileLocator}. If the locator defines a base path and the {@code evaluateBasePath} property is <strong>true</strong>, a
191      * sub directory of the home directory is searched.
192      */
193     @Override
194     public URL locate(final FileSystem fileSystem, final FileLocator locator) {
195         if (StringUtils.isNotEmpty(locator.getFileName())) {
196             final String basePath = getBasePath(locator);
197             final File file = FileLocatorUtils.constructFile(basePath, locator.getFileName());
198             if (file.isFile()) {
199                 return check(FileLocatorUtils.convertFileToURL(file));
200             }
201         }
202         return null;
203     }
204 }