View Javadoc

1   /*
2    * FileConfigurationStore.java
3    *
4    * Created on October 20, 2004, 12:48 PM
5    */
6   
7   package gov.bnl.gums.configuration;
8   
9   import gov.bnl.gums.GUMS;
10  import gov.bnl.gums.persistence.HibernatePersistenceFactory;
11  import gov.bnl.gums.persistence.LocalPersistenceFactory;
12  import gov.bnl.gums.persistence.PersistenceFactory;
13  
14  import java.io.BufferedWriter;
15  import java.io.File;
16  import java.io.FileInputStream;
17  import java.io.FileNotFoundException;
18  import java.io.FileOutputStream;
19  import java.io.FileWriter;
20  import java.io.IOException;
21  import java.lang.ref.SoftReference;
22  import java.net.URL;
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.Collections;
26  import java.util.Date;
27  import java.util.Iterator;
28  
29  import org.apache.log4j.Logger;
30  
31  /** Implements the logic to retrieve the configuration from the gums.config file
32   * taken from the classpath. The file will be reloaded as soon as if it changes,
33   * on demand (no polling).
34   *
35   * @author Gabriele Carcassi, Jay Packard
36   */
37  public class FileConfigurationStore extends ConfigurationStore {
38  	private Logger log = Logger.getLogger(FileConfigurationStore.class);
39  	private Configuration conf;
40  	private Date curModification = null;
41  	private String configBackupDir = null;
42  	private String configPath = null;
43  
44  	/**
45  	 * Copy source to target
46  	 * 
47  	 * @param source
48  	 * @param target
49  	 */
50  	static public void copyFile(String source, String target) {
51  		try {
52  			if (System.getProperty("os.name").indexOf("Linux")!=-1) {
53  				// This will preserve soft links
54  				String[] cpArgs = new String[4];
55  				cpArgs[0] = "/bin/cp";
56  				cpArgs[1] = "-f";
57  				cpArgs[2] = source;
58  				cpArgs[3] = target;
59  				if (Runtime.getRuntime().exec(cpArgs).waitFor() != 0)
60  					throw new RuntimeException("Error copying file");
61  			}
62  			else {
63  				FileInputStream fis  = new FileInputStream(source);
64  				FileOutputStream fos = new FileOutputStream(target);
65  				byte[] buf = new byte[1024];
66  				int i = 0;
67  				while((i=fis.read(buf))!=-1)
68  					fos.write(buf, 0, i);
69  				fis.close();
70  				fos.close();
71  			}
72  		} catch (FileNotFoundException e) {
73  			e.printStackTrace();
74  		} catch (IOException e) {
75  			e.printStackTrace();
76  		} catch (InterruptedException e) {
77  			e.printStackTrace();
78  		}
79  	}
80  	
81  	/**
82  	 * Move source to target
83  	 * 
84  	 * @param source
85  	 * @param target
86  	 */
87  	static public void moveFile(String source, String target) {
88  		copyFile(source, target);
89  		new File(source).delete();
90  	}	
91  	
92  	/**
93  	 * Creates a new FileConfigurationStore object.
94  	 * Used to instantiate class when run as a unit test.
95  	 */
96  	public FileConfigurationStore() {
97  		URL resource = getClass().getClassLoader().getResource("gums.config");
98  		if (resource!=null) {
99  			String configDir = resource.getPath().replace("/gums.config", "");
100 			this.configPath = configDir+"/gums.config";
101 			this.configBackupDir = configDir+"/backup";
102 		}
103 	}
104 
105 	/**
106 	 * Creates a new FileConfigurationStore object.
107 	 * Allows for specifying the absolute name of the configuration file.
108 	 * Used to instantiate class when GUMS is run within servlet.
109 	 * 
110 	 * @param filename
111 	 * @param create if true, a new barbones configuration file will be created
112 	 * at given filename if no file currently exists there
113 	 */
114 	public FileConfigurationStore(String configDir) {
115 		this.configPath = configDir+"/gums.config";
116 		this.configBackupDir = configDir+"/backup";
117 	}
118 
119 	public void deleteBackupConfiguration(String name) {
120 		if (!new File(configBackupDir+"/gums.config."+name).delete())
121 			throw new RuntimeException("Could not delete backup configuration '"+name+"' from file");
122 	}
123 
124 	public Collection getBackupNames() {
125 		ArrayList backupConfigDates = new ArrayList();
126 		File dir = new File(configBackupDir);
127 		String[] children = dir.list();
128 		if (children!=null) {
129 			for (int i=0; i<children.length; i++) {
130 				String dateStr = children[i].substring("gums.config.".length());
131 				backupConfigDates.add( dateStr );
132 			}    	
133 		}
134 		Collections.sort(backupConfigDates);
135 		return backupConfigDates;
136 	}
137 
138 	public Date getLastModification() {
139 		try {
140 			File file = new File(configPath);
141 			Date date = new Date(file.lastModified());
142 			if (log.isTraceEnabled())
143 				log.trace("Last modification from file: "+date.toString());
144 			return date;
145 		} catch (Exception e) {
146 			log.error("Could not determine last modification time of configuration.", e);
147 			return null;
148 		}
149 	}
150 
151 	public boolean isActive() {
152 		log.debug("Checking whether gums.config is present");
153 		return new File(configPath).exists();
154 	}
155 	
156 	public synchronized Configuration restoreConfiguration(String name) {
157 		String path = "/gums.config." + name;
158 		File file = new File(configBackupDir+path);
159 		if (!file.exists())
160 			throw new RuntimeException("Backup configuration " + configBackupDir + path + " does not exist");
161 //		moveFile(configPath, configBackupDir + "/gums.config~");
162 		copyFile(configBackupDir + path, configPath);
163 //		moveFile(configBackupDir + "/gums.config~", configBackupDir + "/gums.config.prev" );
164 		log.debug("Configuration '" + name + "', "+conf+" restored from file");
165 		return retrieveConfiguration();
166 	}
167 	
168 	public synchronized Configuration retrieveConfiguration() {
169 		try {
170 			if (curModification==null || curModification.before(getLastModification())) {
171 				reloadConfiguration();
172 				log.debug("Configuration "+conf+" reloaded from file");
173 			}
174 		} catch (Exception e) {
175 			throw new RuntimeException(e.getMessage());
176 		}
177 		return conf;
178 	}
179 
180 	public synchronized void setConfiguration(Configuration conf, boolean backupCopy, String name, Date date) throws Exception {
181 		if (conf == null)
182 			throw new RuntimeException("Configuration cannot be null");
183                 if (date==null)
184                         date = new Date();
185 
186                 if (backupCopy && (name==null || name.length()==0))
187                         name = format.format(date);
188 
189 		String tempGumsConfigPath = configPath+"~";
190 		
191 		BufferedWriter out;
192 		out = new BufferedWriter(new FileWriter(tempGumsConfigPath));
193 		conf.write(out);
194 		out.close();
195 
196 		// Make sure configuration is valid
197 		FileInputStream fileInputStream = new FileInputStream(tempGumsConfigPath);
198 		try {
199 			StringBuffer configBuffer = new StringBuffer();
200 			int ch;
201 			while ((ch = fileInputStream.read()) != -1)
202 				configBuffer.append((char)ch);
203 	    	ConfigurationToolkit.parseConfiguration(configBuffer.toString(), true);
204 		} catch (Exception e) {
205 			log.error(e.getMessage());
206 			throw new Exception(e.getMessage());
207 		} finally {
208 			fileInputStream.close();
209 		}
210 		
211 		// copy gums.config to gums.config.prev
212 		File file = new File(configBackupDir);
213 		file.mkdir();
214 //		if (!backupCopy && new File(configPath).exists())
215 //			copyFile(configPath, configBackupDir+"/gums.config.prev" );
216 
217 		// move temp file to gums.config or gums.config.date
218 		if (name != null)
219 			moveFile(tempGumsConfigPath, (backupCopy?configBackupDir+"/gums.config."+name:configPath));
220 		else
221 			moveFile(tempGumsConfigPath, (backupCopy?configBackupDir+"/gums.config.":configPath));
222 
223 		this.conf = conf;
224 		
225 		log.debug("Configuration "+conf+" set to file");
226 
227 		// set timestamps
228 		if (!backupCopy) {
229 			new File(configPath).setLastModified(date.getTime());
230 			curModification = date;
231 		}
232 	}
233 
234 	private void reloadConfiguration() {
235 		try {
236 			FileInputStream fileInputStream = new FileInputStream(configPath);
237 			try {
238 				StringBuffer configBuffer = new StringBuffer();
239 				int ch;
240 				while ((ch = fileInputStream.read()) != -1)
241 					configBuffer.append((char)ch);
242 				this.conf = ConfigurationToolkit.parseConfiguration(configBuffer.toString(), true);
243 				curModification = new Date(new File(configPath).lastModified());
244 			} catch (Exception e) {
245 				throw new RuntimeException(e.getMessage());
246 			} finally {
247 				fileInputStream.close();
248 			}
249 		
250 			fileInputStream.close();
251 		} catch (Exception e) {
252 			log.error("The configuration wasn't read correctly.", e);
253 			throw new RuntimeException("The configuration wasn't read correctly: " + e.getMessage());
254 		}
255 	}
256 
257 }