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.17
Committed: Mon Mar 19 19:12:29 2001 UTC (23 years, 2 months ago) by tdb
Branch: MAIN
CVS Tags: PROJECT_COMPLETION
Changes since 1.16: +17 -9 lines
Log Message:
IP groups now have a lower priority than name groups.

File Contents

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