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.16
Committed: Wed Mar 14 23:25:29 2001 UTC (23 years, 2 months ago) by tdb
Branch: MAIN
Changes since 1.15: +9 -9 lines
Log Message:
The whole server package structure has been changed.
Old Package: uk.ac.ukc.iscream.*
New Package: uk.org.iscream.*

File Contents

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