1 package net.sourceforge.argval.utils.impl;
2
3
4 import java.io.File;
5 import java.io.FileNotFoundException;
6 import java.util.ArrayList;
7 import java.util.List;
8
9 import org.slf4j.Logger;
10
11 import net.sourceforge.argval.ArgumentValidation;
12 import net.sourceforge.argval.collection.CollectionUtil;
13 import net.sourceforge.argval.impl.ArgumentValidationImpl;
14 import net.sourceforge.argval.lang.SystemConstants;
15 import net.sourceforge.argval.utils.LocateFile;
16 import net.sourceforge.argval.utils.StringUtil;
17
18
19 /**
20 * This LocateFile implementation provides a way for locating an file, based on a property,
21 * or based on a default name in the current working directory, or based on a default
22 * application (configuration) directory (which contains file, with the default name).
23 *
24 * The file is located as follows:
25 * <ul>
26 * <li>The properties are loaded from the configuration file, but any of these properties may be
27 * overruled by system properties.
28 * <li>The configuration file is located as follows
29 * <ul>
30 * <li>If the system property <code>property-key-name-configuration-file</code> is set, that
31 * file is returned.
32 * <li>Otherwise, if there exist a file 'default-properties-filename' in the current working
33 * directory that file is returned
34 * <li>Otherwise, if there exist an application configuration directory (under the users home
35 * directory '${user.home}/configuration-path'), containing a default configuration file,
36 * that file is returned.
37 * <li>Otherwise, the loading will fail with a runtime exception with a descriptive message.
38 * </ul>
39 * </ul>
40 *
41 * @author T. Verhagen
42 */
43 public class PropertyLocatedFile implements LocateFile {
44 /**
45 * The key name, used to reference the file to return from the system environment.
46 * <p>
47 * Example key name '<code>application-name.configuration</code>', which then can be used as Java VM option:
48 * <pre>java -Dapplication-name.configuration=<path-to-file></pre>
49 */
50 private final String propKeyNameFile;
51 /** The application configuration directory, in the users home directory, when it has one. */
52 private final String configDirName;
53 /** The applications default configuration file name. */
54 private final String defaultFileName;
55 /** A message about where the file is located from. Can be used for logging / reporting. */
56 private String locationMessage;
57
58 private final Logger logger;
59
60 /**
61 * Creates a <code>LocateFile</code> specific for an application / utility.
62 * <p>
63 * Specify the <code>propKeyNameFile</code> as a property key. This key can be used
64 * to specify the location of the file to locate, as system property / environment variable.
65 * As in:
66 * <pre>java -Dmy-application-name.configuration.path=<the location of the file>
67 * org.organisation.application.Start</pre>
68 * The <code>folderName</code> is optional, use it when the application has a default configuration folder
69 * in the users home directory. Like <code>${user.home/.my-application-config/</code>.
70 * The <code>defaultFileName</code> required, used to find load the default configuration file, from the
71 * configuration application configuration directory
72 * (<code>${user.home}/.my-application-config/defaultFileName</code>). Or the current working directory
73 * (<code>${user.dir}/defaultFileName</code>).
74 *
75 * @param propKeyNameFile - the system property key, for locating the configuration file (not <code>null</code>)
76 * @param configDirName - the applications configuration directory (when it has one) (can be <code>null</code>)
77 * @param defaultFileName - the default configuration file name (not <code>null</code>).
78 * @param logger - the logging instance (not <code>null</code>)
79 */
80 public PropertyLocatedFile(String propKeyNameFile, String configDirName, String defaultFileName, Logger logger) {
81 propKeyNameFile = StringUtil.polish(propKeyNameFile);
82 configDirName = StringUtil.polish(configDirName);
83 defaultFileName = StringUtil.polish(defaultFileName);
84
85 ArgumentValidation argVal = new ArgumentValidationImpl();
86 argVal.isValidStringMinLength("propKeyConfigurationFile", propKeyNameFile, 1);
87 argVal.isValidStringMinLength("defaultFileName", defaultFileName, 1);
88 argVal.isValidWhenNotNull("logger", logger);
89 if (argVal.containsIllegalArgument()) throw argVal.createIllegalArgumentException();
90
91 if (configDirName != null) {
92 File path = new File(System.getProperty("user.home"), configDirName);
93 if (! path.isDirectory()) {
94 configDirName = null;
95 logger.info("The application configuration directory '" + path + "' is not available.");
96 }
97 }
98
99 this.propKeyNameFile = propKeyNameFile;
100 this.configDirName = configDirName;
101 this.defaultFileName = defaultFileName;
102 this.logger = logger;
103 }
104
105
106 public File getFile() throws FileNotFoundException {
107 locationMessage = null;
108 // Locate file through set environment variable
109 final String configFileName = System.getProperty(propKeyNameFile);
110
111 final File theFile;
112 if (configFileName != null) {
113 locationMessage = "Loaded property through specified property-key '" + propKeyNameFile + "'.";
114 theFile = new File(configFileName);
115 if (! theFile.exists()) {
116 locationMessage = "Unable to load the file '" + configFileName
117 + "', specified through the property-key '" + propKeyNameFile + "'.";
118 }
119 }
120 else {
121 // The collection of directories, where to search for the file.
122 final List<File> fileLocationDirList = new ArrayList<File>();
123 // The collection of existing files. In the order in which they are relevant.
124 final List<File> fileLocationList = new ArrayList<File>();
125
126 // Locate file from current working directory
127 final File workDir = new File(System.getProperty(SystemConstants.USER_DIR));
128 // final File workDirFile = new File(workDir, defaultFileName);
129 fileLocationDirList.add(workDir);
130
131 // Locate file from the configuration specific directory
132 final String homeDirName = System.getProperty(SystemConstants.USER_HOME);
133 final File homeDir = new File(homeDirName);
134
135 final File configDir = (configDirName != null) ? new File(homeDir, configDirName) : null;
136 // final File configDirFile = (configDirName != null) ? new File(configDir, defaultFileName) : null;
137 if (configDir != null) {
138 fileLocationDirList.add(configDir);
139 }
140
141 for (File dir : fileLocationDirList) {
142 if (dir.exists()) {
143 List<String> fileNameList = getFileNameList();
144 for (String fileName : fileNameList) {
145 File newFile = new File(dir, fileName);
146 if (newFile.exists()) {
147 fileLocationList.add(newFile);
148 }
149 }
150 }
151 }
152
153 if (! fileLocationList.isEmpty()) {
154 logger.warn(CollectionUtil.toString(fileLocationList));
155 theFile = fileLocationList.get(0);
156 locationMessage = "Located file '" + theFile + "'.";
157 }
158 else {
159 theFile = null;
160 locationMessage = "No file with a name " + CollectionUtil.toString(getFileNameList())
161 + " was located in one of the directories " + CollectionUtil.toString(fileLocationDirList);
162 }
163 }
164
165 if (theFile == null || (! theFile.exists())) {
166 throw new FileNotFoundException(locationMessage);
167 }
168 return theFile;
169 }
170
171
172 /**
173 * Returns a series of files, based on the default file name. At minimum the default
174 * file name added to the list. If the filename, contains an extension (like {@code *.html}),
175 * also the file name extended with the current user name is returned.
176 * <p>
177 * When the default file name is {@code application.properties} and the current user name is 'peter',
178 * this will lead to the following file names in the list:
179 * {@code application.properties application_goofy.properties application-goofy.properties}
180 * </p>
181 * @return The list of file names.
182 */
183 private List<String> getFileNameList() {
184 List<String> fileNameList = new ArrayList<String>();
185
186 // Check if there is an extension (and also not only a starting dot)
187 int indexOfDot = defaultFileName.lastIndexOf('.');
188 if (indexOfDot > 0) {
189 String fileName = defaultFileName.substring(0, indexOfDot);
190 String fileExt = defaultFileName.substring(indexOfDot);
191 String userName = System.getProperty(SystemConstants.USER_NAME);
192 fileNameList.add(fileName + "_" + userName + fileExt);
193 fileNameList.add(fileName + "-" + userName + fileExt);
194 }
195 fileNameList.add(defaultFileName);
196 return fileNameList ;
197 }
198
199
200 public String getFileMessage() {
201 return locationMessage;
202 }
203
204 }