ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/i-scream/projects/cms/source/server/uk/org/iscream/cms/server/core/ConfigurationManagerServant.java
Revision: 1.23
Committed: Sat May 18 18:16:01 2002 UTC (22 years ago) by tdb
Branch: MAIN
Changes since 1.22: +21 -2 lines
Log Message:
i-scream is now licensed under the GPL. I've added the GPL headers to every
source file, and put a full copy of the license in the appropriate places.
I think I've covered everything. This is going to be a mad commit ;)

File Contents

# User Rev Content
1 tdb 1.23 /*
2     * i-scream central monitoring system
3     * Copyright (C) 2000-2002 i-scream
4     *
5     * This program is free software; you can redistribute it and/or
6     * modify it under the terms of the GNU General Public License
7     * as published by the Free Software Foundation; either version 2
8     * of the License, or (at your option) any later version.
9     *
10     * This program is distributed in the hope that it will be useful,
11     * but WITHOUT ANY WARRANTY; without even the implied warranty of
12     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13     * GNU General Public License for more details.
14     *
15     * You should have received a copy of the GNU General Public License
16     * along with this program; if not, write to the Free Software
17     * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18     */
19    
20 ajm 1.3 //---PACKAGE DECLARATION---
21 tdb 1.18 package uk.org.iscream.cms.server.core;
22 ajm 1.3
23     //---IMPORTS---
24 tdb 1.18 import uk.org.iscream.cms.server.util.*;
25     import uk.org.iscream.cms.server.componentmanager.*;
26 ajm 1.15 import java.net.InetAddress;
27     import java.net.UnknownHostException;
28 ajm 1.3 import java.util.*;
29     import java.io.*;
30    
31     /**
32     * This class is essentially a Configuration factory.
33     * This class implements the Configurator IDL and allows
34     * other classes in the system ot obtain their Configuration
35     *
36     * On construction it requires a reference to the RootPOA
37     * to allow it to create Configuration objects to be
38     * returned.
39     *
40     * It also relies on the System.properties to set internal values.
41     *
42 tdb 1.20 * @author $Author: tdb $
43 tdb 1.23 * @version $Id: ConfigurationManagerServant.java,v 1.22 2001/12/11 17:52:35 tdb Exp $
44 ajm 1.3 */
45     class ConfigurationManagerServant extends ConfigurationManagerPOA {
46    
47     //---FINAL ATTRIBUTES---
48    
49     /**
50     * The current CVS revision of this class
51     */
52 tdb 1.23 public final String REVISION = "$Revision: 1.22 $";
53 ajm 1.3
54     //---STATIC METHODS---
55    
56     //---CONSTRUCTORS---
57    
58     /**
59     * Creates a new ConfiguratorServant
60     * This class uses the System.properties to set internal values
61     */
62 ajm 1.6 ConfigurationManagerServant() {
63 ajm 1.3 // assign some local variables
64 tdb 1.18 _configPath = System.getProperty("uk.org.iscream.cms.server.ConfigurationLocation");
65     _systemConfigFile = System.getProperty("uk.org.iscream.cms.server.SystemConfigurationFile");
66 ajm 1.3
67     // load the system config
68     loadSystemConfig();
69    
70     // log our status
71 ajm 1.6 _logger.write(toString(), Logger.SYSINIT, "started");
72     _logger.write(toString(), Logger.SYSMSG, "configuration location - " + _configPath);
73     _logger.write(toString(), Logger.SYSMSG, "system configuration file - " + _systemConfigFile);
74 ajm 1.3 }
75    
76     //---PUBLIC METHODS---
77    
78     /**
79     * Returns a Configuration object which contains
80     * the configuration data requested by the calling
81     * object.
82     *
83     * This method will look in the systemConfig file
84     * for an entry for this "source", if there is no
85     * entry it returns a refernce to the system
86     * config. If there are any errors in reading the
87     * configuration, it returns null, the caller is
88     * expected to be able to handle this.
89     *
90     * This method also checks to see if the system.conf
91     * file has been updated and reloads its reference if
92     * needed.
93     *
94     * @param source the configuration required
95     * @return the Configuration
96     */
97     public Configuration getConfiguration(String source) {
98 ajm 1.6 _logger.write(toString(), Logger.SYSMSG, "got request for " + source);
99 ajm 1.8
100 ajm 1.3
101     // check to see if we need to reload the system config
102     // because it has changed
103     if (isModified(_systemConfig.getFileList(), _systemConfig.getLastModified())) {
104 ajm 1.6 _logger.write(toString(), Logger.SYSMSG, "system config changed");
105 ajm 1.3 loadSystemConfig();
106     }
107    
108 ajm 1.8 // search config for group membership
109 tdb 1.17 // and obain a list of groups by name
110     LinkedList nameGroups = getGroupMembership(source);
111     // add the hosts individual config to the start of the list
112     nameGroups.addFirst(source);
113 ajm 1.15
114 tdb 1.17 // this list will be used to compile the groupings
115     LinkedList groups = new LinkedList();
116    
117 ajm 1.15 // if we are dealing with a Host.<hostname> request, then we also
118     // want to look for ip address details, as configuration entries may relate to it
119     // if we can't resolve it, we don't look.
120 tdb 1.17 LinkedList ipGroups = null;
121 ajm 1.15 if (source.startsWith("Host.")) {
122     // hostname is after Host.
123     String hostname = source.substring(5);
124     try {
125     String ip = "Host." + InetAddress.getByName(hostname).getHostAddress();
126 tdb 1.17 ipGroups = getGroupMembership(ip);
127     ipGroups.addFirst(ip);
128     // add to our list of groups
129 ajm 1.15 groups.addAll(ipGroups);
130     } catch (UnknownHostException e) {
131     _logger.write(toString(), Logger.ERROR, "could not resolve hostname - " + hostname);
132     }
133     }
134 tdb 1.17
135     // add the rest of the groups to the end
136     groups.addAll(nameGroups);
137 ajm 1.3
138 ajm 1.8 Iterator i = groups.iterator();
139     String fileList = "";
140     while (i.hasNext()) {
141     String groupName = (String) i.next();
142 ajm 1.11 _logger.write(toString(), Logger.DEBUG, "looking for config entry for - " + groupName);
143 ajm 1.8 // we look for this entry in the systemConfig
144     String configFile = _systemConfig.getProperty("config." + groupName);
145 ajm 1.11 // if there is a config entry then
146     if (configFile != null) {
147     _logger.write(toString(), Logger.DEBUG, "looking for config tree in - " + configFile);
148    
149     // get the file list of includes etc + the system config
150     String groupFileList = null;
151     try {
152     groupFileList = getIncludedFiles(configFile, "") + ";";
153     } catch (Exception e) {
154     // not sure what to do here
155     // so we just log the error
156     _logger.write(toString(), Logger.ERROR, "ERROR - " + e);
157     }
158     if (groupFileList != null) {
159     fileList += groupFileList;
160     }
161     } else {
162     _logger.write(toString(), Logger.DEBUG, "no config entry for - " + groupName);
163 tdb 1.12 }
164 ajm 1.3 }
165 ajm 1.8 // add the system config as the final check
166 tdb 1.13 fileList = _systemConfigFile + ";" + fileList;
167 ajm 1.8 _logger.write(toString(), Logger.DEBUG, "config tree - " + fileList);
168    
169     // build the configuration
170     Configuration config = buildConfiguration(fileList);
171 ajm 1.3
172     // if this is null at this point, then there will have been an error
173     return config;
174     }
175    
176    
177     /**
178     * When passed a file list and a current value for the lastModified
179     * of the current configuration, this method compares the value
180     * to the actual value of the configuration files to determine
181     * whether or not the configuration has been modified.
182     *
183     * @param fileList a list of files that the caller uses for configuration
184     * @param lastModified the last modified date of the callers configuration
185     *
186     * @return whether or not the configuration has been modified
187     */
188     public boolean isModified(String fileList, long lastModified) {
189     StringTokenizer st = new StringTokenizer(fileList, ";");
190     long newLastModified;
191     File currentFile;
192     while (st.hasMoreTokens()) {
193     currentFile = new File(_configPath, st.nextToken());
194     newLastModified = currentFile.lastModified();
195     if (newLastModified > lastModified) {
196     return true;
197     }
198     }
199     return false;
200     }
201 ajm 1.6
202 ajm 1.3 /**
203     * Overrides the {@link java.lang.Object#toString() Object.toString()}
204     * method to provide clean logging (every class should have this).
205     *
206 tdb 1.18 * This uses the uk.org.iscream.cms.server.util.FormatName class
207 ajm 1.6 * to format the toString()
208     *
209 ajm 1.3 * @return the name of this class and its CVS revision
210     */
211     public String toString() {
212 ajm 1.6 return FormatName.getName(
213     _name,
214     getClass().getName(),
215     REVISION);
216 ajm 1.3 }
217    
218     //---PRIVATE METHODS---
219    
220     /**
221     * This is a recursive function private to this class.
222     * It constructs a hierarchy of files as a ";" serperated
223     * string which can be used to read in the configuration.
224     * This function calls itself.
225     *
226     * @param currentFile the current file to be processed
227 ajm 1.4 * @param readFiles used for recursion purposes only, these are the files it has read so far
228     *
229 ajm 1.3 * @return the current list that has been constructed
230     *
231     * @throws IOException if there is trouble reading the file
232     * @throws FileNotFoundException is there is trouble finding the file
233 ajm 1.4 * @throws CircularIncludeException this is if a circular include is detected
234 ajm 1.3 */
235 ajm 1.4 private String getIncludedFiles(String currentFile, String readFiles) throws IOException, FileNotFoundException, Exception {
236    
237     // check for circular include here
238     if (hasDuplicate(currentFile, readFiles) || currentFile.equals(_systemConfigFile)) {
239     throw new CircularIncludeException(currentFile + " is included more than once");
240     }
241    
242     // if there wasn't, we're gonna use this file, so make a note of it as read
243     // (note the use of the ";", this is for the hasDuplicate, function)
244     readFiles = readFiles + currentFile + ";";
245    
246 ajm 1.3 Properties properties = new Properties();
247     properties.load(new FileInputStream(new File(_configPath, currentFile)));
248 ajm 1.4
249     // get the include property
250 ajm 1.3 String includes = properties.getProperty("include");
251 ajm 1.4
252     // if we're the last file with no includes, return our name
253 ajm 1.3 if (includes == null) {
254     return currentFile;
255 ajm 1.4
256     // otherwise, recurse over our includes
257 ajm 1.3 } else {
258     StringTokenizer st = new StringTokenizer(includes, ";");
259     String returnList= "";
260     while (st.hasMoreTokens()) {
261 ajm 1.4 returnList = getIncludedFiles(st.nextToken(), readFiles) + ";" + returnList;
262 ajm 1.3 }
263 ajm 1.4
264 ajm 1.3 return returnList + currentFile;
265     }
266     }
267    
268     /**
269 ajm 1.4 * This simple method checks to see if a given
270     * file exists in the given list.
271     *
272     * @param file the file to check the list for
273     * @param fileList the list to check
274     *
275     * @return if the given file appeard in the list
276     */
277     private boolean hasDuplicate(String file, String fileList) {
278     StringTokenizer st = new StringTokenizer(fileList, ";");
279     while (st.hasMoreTokens()) {
280     if (file.equals(st.nextToken())) {
281     return true;
282     }
283     }
284     return false;
285     }
286    
287     /**
288 ajm 1.3 * Opens and loads the system configuration into the
289     * local reference _systemConfig
290     */
291     private void loadSystemConfig() {
292 ajm 1.6 _logger.write(this.toString(), Logger.SYSMSG, "reloading " + _systemConfigFile);
293 ajm 1.3 // get a reference to the system config and store it
294     try {
295     // create the properties for the configuration
296     File systemConfigFile = new File(_configPath, _systemConfigFile);
297 ajm 1.8 _systemConfigHolder = new Properties();
298     _systemConfigHolder.load(new FileInputStream(systemConfigFile));
299    
300 ajm 1.3 // create the servant
301 ajm 1.8 ConfigurationServant ref = new ConfigurationServant(_systemConfigHolder, _systemConfigFile, systemConfigFile.lastModified());
302 ajm 1.6 org.omg.CORBA.Object objRef = _refman.getRootPOA().servant_to_reference(ref);
303 ajm 1.3
304     // narrow it to a Configuration
305     _systemConfig = ConfigurationHelper.narrow(objRef);
306    
307     } catch (Exception e) {
308 ajm 1.6 _logger.write(toString(), Logger.FATAL, "ERROR: " + e.getMessage());
309 ajm 1.3 }
310     }
311    
312 ajm 1.8 /**
313     * Parses the system configuration file
314     * for group membership entries.
315     *
316     * It looks for all entries of group.<name>
317     * which contain the given source name
318     *
319     * @param source the source to find membership for
320     *
321     * @return the list of groups that this source is a member of
322     */
323     private LinkedList getGroupMembership(String source) {
324 tdb 1.20 _logger.write(toString(), Logger.DEBUG, "searching groups for - " + source);
325 ajm 1.8 LinkedList groupMembership = new LinkedList();
326     Iterator i = new TreeSet(_systemConfigHolder.keySet()).iterator();
327     while(i.hasNext()) {
328     String key = (String) i.next();
329 tdb 1.22 // look for a key that's a group entry
330 ajm 1.8 if (key.startsWith("group.")) {
331 tdb 1.22 // get the list of hosts in the group
332 ajm 1.8 String group = _systemConfig.getProperty(key);
333 tdb 1.22 if(groupMatch(source, group)) {
334 ajm 1.8 groupMembership.add(key.substring(6));
335 tdb 1.22 _logger.write(toString(), Logger.DEBUG, "group match found for - " + source + " in group - " + key);
336 ajm 1.8 }
337     }
338     }
339     return groupMembership;
340 tdb 1.22 }
341    
342     /**
343     * Checks that a given source is matched within the
344     * given list of hosts. For example:<br>
345     * <br>
346     * Given "stue5de.ukc.ac.uk"<br>
347     * And "raptor.ukc.ac.uk;stue*.ukc.ac.uk<br>
348     * <br>
349     * This method would return true as there is a match.
350     *
351     * This method will also match if the source is exactly
352     * matched within the group of hosts (ie. no wildcard).
353     *
354     * @param source the string to look for
355     * @param group the group to search for a match
356     *
357     * @return if there is a match
358     */
359     public static boolean groupMatch(String source, String group) {
360     StringTokenizer st = new StringTokenizer(group, ";");
361     // go through all the hosts in the group
362     while (st.hasMoreTokens()) {
363     String host = st.nextToken();
364     if(StringUtils.wildcardMatch(source, host)) {
365     return true;
366     }
367     }
368     // not had a match
369     return false;
370 ajm 1.15 }
371 ajm 1.8
372     /**
373     * Build the properties as a Configuration to be
374     * returned to the caller
375     *
376     * @param fileList the list of files to build the configuration from
377     *
378     * @return the built Configuration
379     */
380     private Configuration buildConfiguration(String fileList) {
381     Configuration config = null;
382    
383     // if there is an entry
384 ajm 1.10 if (!fileList.equals("")) {
385 ajm 1.8 try {
386    
387     // build the properites here from the filelist....
388     StringTokenizer st = new StringTokenizer(fileList, ";");
389    
390     // some holders for variables
391     File currentFile;
392 tdb 1.14 long lastModified = 0, newLastModified = 0;
393     Properties properties = null, prevProperties = null;
394 ajm 1.8
395     // the root of all configurations will be the system config
396     // so we need to open the properties of that
397     Properties defaultProperties = new Properties();
398    
399     // This loop then iterates over the file list
400     // creates the properties to be passed to the
401     // Configuration constructor
402 tdb 1.13 while (st.hasMoreTokens()) {
403 ajm 1.8 properties = new Properties(defaultProperties);
404     currentFile = new File(_configPath, st.nextToken());
405     newLastModified = currentFile.lastModified();
406     if (newLastModified > lastModified) {
407     lastModified = newLastModified;
408     }
409     properties.load(new FileInputStream(currentFile));
410     defaultProperties = properties;
411 tdb 1.13 }
412 ajm 1.8
413     // this creates the configuration, all nice, ready to be returned
414     ConfigurationServant ref = new ConfigurationServant(properties, fileList, lastModified);
415     org.omg.CORBA.Object objRef = _refman.getRootPOA().servant_to_reference(ref);
416     config = ConfigurationHelper.narrow(objRef);
417 tdb 1.13 _logger.write(toString(), Logger.DEBUG, "returning built configuration");
418 ajm 1.8 } catch (Exception e) {
419     // not sure what to do here
420     // so we just log the error
421 ajm 1.10 _logger.write(toString(), Logger.ERROR, "ERROR - " + e);
422 ajm 1.8 }
423    
424     // if there isn't an entry for the requested config
425     } else {
426     _logger.write(toString(), Logger.DEBUG, "no configured config, returning " + _systemConfigFile);
427     config = _systemConfig;
428     }
429     return config;
430     }
431    
432 ajm 1.3 //---ACCESSOR/MUTATOR METHODS---
433    
434     //---ATTRIBUTES---
435    
436     /**
437 ajm 1.6 * This is the friendly identifier of the
438     * component this class is running in.
439     * eg, a Filter may be called "filter1",
440     * If this class does not have an owning
441     * component, a name from the configuration
442     * can be placed here. This name could also
443     * be changed to null for utility classes.
444     */
445     private String _name = Core.NAME;
446    
447     /**
448     * This holds a reference to the
449     * system logger that is being used.
450 ajm 1.3 */
451 ajm 1.6 private Logger _logger = ReferenceManager.getInstance().getLogger();
452 ajm 1.3
453     /**
454 ajm 1.6 * A reference to the reference manager in use
455 ajm 1.3 */
456 ajm 1.6 private ReferenceManager _refman = ReferenceManager.getInstance();
457 ajm 1.3
458     /**
459     * The root path to all configurations
460     */
461     private String _configPath;
462    
463     /**
464     * The name of the file that contains the system configuration
465     */
466     private String _systemConfigFile;
467    
468     /**
469     * An instance of the system config
470     */
471     private Configuration _systemConfig;
472 ajm 1.8
473     /**
474     * The system config file represented by a
475     * properties object.
476     */
477     private Properties _systemConfigHolder;
478 ajm 1.3
479     //---STATIC ATTRIBUTES---
480    
481     }