View Javadoc

1   /*
2    * GUMS.java
3    *
4    * Created on June 3, 2004, 10:39 AM
5    */
6   
7   package gov.bnl.gums;
8   
9   import gov.bnl.gums.admin.CertCache;
10  import gov.bnl.gums.configuration.Configuration;
11  import gov.bnl.gums.configuration.ConfigurationStore;
12  import gov.bnl.gums.configuration.DBConfigurationStore;
13  import gov.bnl.gums.configuration.FileConfigurationStore;
14  import gov.bnl.gums.configuration.Version;
15  import gov.bnl.gums.persistence.PersistenceFactory;
16  import gov.bnl.gums.userGroup.UserGroup;
17  
18  import java.util.Date;
19  import java.util.Collection;
20  import java.util.Iterator;
21  import java.util.List;
22  import java.util.Timer;
23  import java.util.TimerTask;
24  import javax.naming.Context;
25  import javax.naming.InitialContext;
26  import javax.naming.NamingException;
27  
28  import org.apache.commons.digester.Digester;
29  import org.apache.log4j.Logger;
30  
31  /** 
32   * Facade for the whole business logic available in GUMS. Using GUMS means
33   * instanciating an object of this class, and use it to reach the rest of the
34   * functionalities.
35   *
36   * @author  Gabriele Carcassi, Jay Packard
37   */
38  public class GUMS {
39  	static final public String siteAdminLogName = "gums.siteAdmin";
40  	static final public String gumsAdminLogName = "gums.gumsAdmin";
41  	static private Logger log = Logger.getLogger(GUMS.class); // only use this log for particularly tricky aspects of this class - otherwise log within lower level classes
42  	static private Logger gumsAdminLog = Logger.getLogger(GUMS.gumsAdminLogName);
43  	static public QuietLog gumsAdminEmailLog = new QuietLog("gums.gumsAdminEmail");
44  	static private Timer timer;
45  	static private String version;
46  
47  	private CoreLogic resMan = new CoreLogic(this);
48  	protected ConfigurationStore confStore;
49  	protected DBConfigurationStore dbConfStore = null;
50  	protected Configuration lastConf = null;
51  
52  	/**
53  	 * Create a thread that updates user group membership every so often
54  	 * 
55  	 * @param gums
56  	 */
57  	static private synchronized void startWorkerThread(final GUMS gums) {
58  		// If JNDI property is set, run the update every x minutes
59  		if (timer == null) {
60  			timer = new Timer();
61  
62  			Integer updateMinutes = null;
63  			Integer updateBannedMinutes = null;
64  			Integer emailWarningHours = null;
65  			try {
66  				Context env = (Context) new InitialContext().lookup("java:comp/env");
67  				try {
68  					updateMinutes = (Integer) env.lookup("updateGroupsMinutes");
69  				} catch (Exception e) {}
70  				try {
71  					updateBannedMinutes = (Integer) env.lookup("updateBannedGroupsMinutes");
72  				} catch (Exception e) {}
73  				try {
74  					emailWarningHours = (Integer) env.lookup("emailWarningHours");
75  				} catch (Exception e) {}
76  			} catch (NamingException e) {
77  				log.warn("Couldn't set up JNDI context: " + e.getMessage(), e);
78  			}	
79  			
80  			if (updateMinutes != null) {
81  				TimerTask updateTask = 
82  					new TimerTask() {
83  					public void run() {
84  						synchronized(this) {
85  							try {
86  								gumsAdminLog.info("Starting automatic updateGroups");
87  								gums.getCoreLogic().updateGroups();
88  								gumsAdminLog.info("Automatic updateGroups ended");
89  							} catch (Exception e) {
90  								gumsAdminLog.warn("Automatic group update had failures - " + e.getMessage());
91  								gumsAdminEmailLog.put("updateUserGroup", e.getMessage(), false);
92  							}
93  						}
94  					}
95  				};
96  
97  				timer.scheduleAtFixedRate(updateTask, 0, updateMinutes.intValue()*60*1000);
98  				gumsAdminLog.info("Automatic group update set: will refresh every " + updateMinutes.intValue() + " minutes starting now.");
99  			}
100 			else {
101 				gumsAdminLog.warn("Didn't start the automatic group update: 'updateGroupsMinutes' was set to null.");
102 			}
103 			
104 			if (updateBannedMinutes != null) {
105 				TimerTask updateBannedTask = new TimerTask() {
106 					public void run() {
107 						synchronized(this) {
108 							try {
109 								gumsAdminLog.info("Starting automatic updateBannedGroups");
110 								gums.getCoreLogic().updateBannedGroups();
111 								gumsAdminLog.info("Automatic updateBannedGroups ended");
112 							} catch (Exception e) {
113 								gumsAdminLog.warn("Automatic banned group update had failures - " + e.getMessage());
114 								gumsAdminEmailLog.put("updateBannedGroups", e.getMessage(), false);
115 							}
116 						}
117 					}
118 				};
119 
120 				timer.scheduleAtFixedRate(updateBannedTask, 0, updateBannedMinutes.intValue()*60*1000);
121 				gumsAdminLog.info("Automatic banned group update set: will refresh every " + updateBannedMinutes.intValue() + " minutes starting now.");
122 			}
123 			else {
124 				gumsAdminLog.warn("Didn't start the automatic banned group update: 'updateBannedMinutes' was set to null.");
125 			}			
126 
127 			if (emailWarningHours != null) {
128 				TimerTask emailWarningTask = new TimerTask() {
129 					public void run() {
130 						synchronized(this) {
131 							if (gumsAdminEmailLog.hasMessages()) {
132 								gumsAdminEmailLog.logMessages();
133 							}
134 						}
135 					}
136 				};      
137 
138 				timer.scheduleAtFixedRate(emailWarningTask, 5*60*1000, emailWarningHours.intValue()*60*60*1000);
139 				gumsAdminLog.info("Automatic email warning set: will refresh every " + emailWarningHours.intValue() + " hours starting in 5 minutes.");
140 			}
141 			else {
142 				gumsAdminLog.warn("Didn't start the email warning task: 'emailWarningTask' was set to null.");
143 			}
144 		}
145 	}
146 
147 	/**
148 	 * Creates and initilializes a new instance of GUMS
149 	 */
150 	public GUMS() {
151 		confStore = new FileConfigurationStore();
152 		if (!confStore.isActive()) {
153 			String message = "Couldn't read GUMS configuration file (gums.config)";
154 			gumsAdminLog.error(message);
155 			gumsAdminEmailLog.put("Configuration", message, true);
156 			throw new RuntimeException(message);
157 		}
158 
159 		startWorkerThread(this);
160 	}
161 
162 	/**
163 	 * Creates and initilializes a new instance of GUMS with a specified configuration store
164 	 * 
165 	 * @param confStore
166 	 */
167 	public GUMS(ConfigurationStore confStore) {
168 		this.confStore = confStore;
169 		if (!confStore.isActive()) {
170 			String message = "Couldn't read GUMS configuration file";
171 			gumsAdminLog.error(message);
172 			gumsAdminEmailLog.put("Configuration", message, true);
173 			throw new RuntimeException(message);
174 		}
175 
176 		startWorkerThread(this);
177 	}
178 
179 	/**
180 	 * Delete a backup configuration by date
181 	 * 
182 	 * @param dateStr
183 	 */
184 	public void deleteBackupConfiguration(String dateStr) {
185 		if (dbConfStore!=null)  {
186 			dbConfStore.deleteBackupConfiguration(dateStr);
187 			gumsAdminLog.info("Deleted backup configuration "+dateStr+" from database");
188 		}
189 		else {
190 			confStore.deleteBackupConfiguration(dateStr);
191 			gumsAdminLog.info("Deleted backup configuration "+dateStr+" from file");
192 		}
193 	}
194 
195 	/**
196 	 * Get a list of dates for which a backup gums.config exists
197 	 * 
198 	 * @return Collection of date strings
199 	 */
200 	public Collection getBackupNames() throws Exception {
201 		if (dbConfStore != null)
202 			return dbConfStore.getBackupNames();
203 		else
204 			return confStore.getBackupNames();
205 	}
206 
207 	/**
208 	 * Retrieves the configuration being used by GUMS. The configuration might
209 	 * change from one call to the other. Therefore, the business logic needs
210 	 * to cache the value returned for the duration of a whole call, and not
211 	 * further. 
212 	 * 
213 	 * @return current configuration or null.
214 	 */
215 	public synchronized Configuration getConfiguration() throws Exception {
216 		Configuration conf;
217 		
218 		// Load from most recent confStore and update other
219 		if (dbConfStore != null) {
220 			Date confStoreLastMod = confStore.getLastModification();
221 			Date dbConfStoreLastMod = dbConfStore.getLastModification();
222 			if (confStoreLastMod.after(dbConfStoreLastMod)) {
223 				conf = confStore.retrieveConfiguration();
224 				if (lastConf != conf) {
225 					gumsAdminLog.info("Reloaded configuration "+conf+" from file, which was modified on " + confStoreLastMod + ", and setting to database");
226 					updateConfStoreTypes(conf);
227 					if (dbConfStore!=null)
228 						dbConfStore.setConfiguration(conf, false, null, confStoreLastMod);
229 					System.gc();
230 				}
231 			}
232 			else if (lastConf==null || dbConfStoreLastMod.after(confStoreLastMod)) {
233 				conf = dbConfStore.retrieveConfiguration();
234 				if (lastConf != conf) {
235 					gumsAdminLog.info("Reloaded configuration "+conf+" from database, which was modified on " + dbConfStoreLastMod + ", and setting to file");
236 					updateConfStoreTypes(conf);
237 					confStore.setConfiguration(conf, false, null, dbConfStoreLastMod);
238 					System.gc();
239 				}
240 			}
241 			else
242 				conf = lastConf;
243 		}
244 		else {
245 			conf = confStore.retrieveConfiguration();
246 			if (lastConf != conf) {
247 				gumsAdminLog.info("Reloaded configuration from file");
248 				updateConfStoreTypes(conf);
249 				System.gc();
250 			}
251 		}
252 		
253 		lastConf = conf;
254 		
255 		return conf;
256 	}
257 
258 	/**
259 	 * Retrieve the ResourceManager to perform actions on the business logic.
260 	 * 
261 	 * @return the resource manager.
262 	 */
263 	public CoreLogic getCoreLogic() {
264 		return resMan;
265 	}
266 	
267 	static public String getVersion() {
268 		if (version==null) {
269 			String pomFile = CertCache.getMetaDir()+"/maven/gums/gums-service/pom.xml";
270 			Digester digester = new Digester();
271 			digester.addObjectCreate("project/version", Version.class);
272 			digester.addCallMethod("project/version","setVersion",0);
273 			Version versionCls = null;
274 			try {
275 				versionCls = (Version)digester.parse("file://"+pomFile);
276 			} catch (Exception e) {
277 				gumsAdminLog.warn("Cannot get GUMS version from "+pomFile);
278 				return "?";
279 			}
280 			if (versionCls == null) {
281 				gumsAdminLog.warn("Cannot get GUMS version from "+pomFile);
282 				return "?";
283 			}
284 			else
285 				gumsAdminLog.debug("Loaded GUMS version " + versionCls.getVersion() + " from '" + pomFile + "'" );
286 			version = versionCls.getVersion();
287 		}
288 		return version;
289 	}
290 
291 	public boolean isUserBanned(GridUser user) throws Exception {
292 		Configuration config = getConfiguration();
293 		List bannedUserGroups = config.getBannedUserGroupList();
294 		Iterator it = bannedUserGroups.iterator();
295 		while (it.hasNext()) {
296 			UserGroup userGroup = config.getUserGroup((String)it.next());
297 			return userGroup.isInGroup(user);
298 		}
299 		return false;
300 	}
301 
302 	public void mergeConfiguration(Configuration configuration, String persistenceFactory, String hostToGroupMapping) throws Exception
303 	{
304 		getConfiguration().mergeConfiguration(configuration, persistenceFactory, hostToGroupMapping);
305 	}
306 
307 	/**
308 	 * Restore a configuration from a certain date
309 	 * 
310 	 * @param dateStr
311 	 */
312 	public void restoreConfiguration(String name) throws Exception {
313 		if (dbConfStore!=null)
314 		{
315 			dbConfStore.restoreConfiguration(name);
316 			gumsAdminLog.info("Restored configuration from db: " + name);
317 		}
318 		else
319 		{
320 			confStore.restoreConfiguration(name);
321 			gumsAdminLog.info("Restored configuration from file: " + name);
322 		}
323 	}
324 
325 	/**
326 	 * Changes the configuration used by GUMS.
327 	 * 
328 	 * @param conf the new configuration
329 	 */
330 	public void setConfiguration(Configuration conf, boolean backup, String name) throws Exception {
331 		Date date = new Date();
332 		if (backup) {
333 			if (dbConfStore!=null) {
334 				dbConfStore.setConfiguration(conf, true, name, date); 
335 				gumsAdminLog.info("Backed up configuration in database: "+name);
336 			}  			
337 			else {
338 				confStore.setConfiguration(conf, true, name, date);
339 				gumsAdminLog.info("Backed up configuration on file: "+name);
340 			}
341 		}
342 		else {
343 			confStore.setConfiguration(conf, false, null, date);
344 			gumsAdminLog.info("Set configuration on file");
345 		}
346 	}
347 
348 	private void updateConfStoreTypes(Configuration conf) {
349 		Iterator it = conf.getPersistenceFactories().values().iterator();
350 		boolean storeConfigFound = false;
351 		while (it.hasNext()) {
352 			PersistenceFactory persFact = (PersistenceFactory)it.next();
353 			if (persFact.getStoreConfig()) {
354 				// create database configuration store
355 				if (storeConfigFound) {
356 					String message = "Configuration may only contain one persistence factory set to store the configuration";
357 					log.error(message);
358 					throw new RuntimeException(message);
359 				}
360 				dbConfStore = new DBConfigurationStore(persFact.retrieveConfigurationDB());
361 				String message = "Created database configuration store for persistence factory "+persFact.getName();
362 				gumsAdminLog.debug(message);
363 				log.debug(message);
364 				storeConfigFound = true;
365 			}
366 		}
367 		
368 		if (!storeConfigFound) {
369 			// eliminate database configuration store 
370 			if (dbConfStore!=null) {
371 				String message = "Eliminated database configuration store";
372 				gumsAdminLog.debug(message);
373 				log.debug(message);
374 			}
375 			dbConfStore = null;
376 		}
377 	}
378 
379 }