View Javadoc

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 }