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

# Content
1 /*
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 //---PACKAGE DECLARATION---
21 package uk.org.iscream.cms.server.core;
22
23 //---IMPORTS---
24 import uk.org.iscream.cms.server.util.*;
25 import uk.org.iscream.cms.server.componentmanager.*;
26 import java.net.InetAddress;
27 import java.net.UnknownHostException;
28 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 * @author $Author: tdb $
43 * @version $Id: ConfigurationManagerServant.java,v 1.22 2001/12/11 17:52:35 tdb Exp $
44 */
45 class ConfigurationManagerServant extends ConfigurationManagerPOA {
46
47 //---FINAL ATTRIBUTES---
48
49 /**
50 * The current CVS revision of this class
51 */
52 public final String REVISION = "$Revision: 1.22 $";
53
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 ConfigurationManagerServant() {
63 // assign some local variables
64 _configPath = System.getProperty("uk.org.iscream.cms.server.ConfigurationLocation");
65 _systemConfigFile = System.getProperty("uk.org.iscream.cms.server.SystemConfigurationFile");
66
67 // load the system config
68 loadSystemConfig();
69
70 // log our status
71 _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 }
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 _logger.write(toString(), Logger.SYSMSG, "got request for " + source);
99
100
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 _logger.write(toString(), Logger.SYSMSG, "system config changed");
105 loadSystemConfig();
106 }
107
108 // search config for group membership
109 // 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
114 // this list will be used to compile the groupings
115 LinkedList groups = new LinkedList();
116
117 // 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 LinkedList ipGroups = null;
121 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 ipGroups = getGroupMembership(ip);
127 ipGroups.addFirst(ip);
128 // add to our list of groups
129 groups.addAll(ipGroups);
130 } catch (UnknownHostException e) {
131 _logger.write(toString(), Logger.ERROR, "could not resolve hostname - " + hostname);
132 }
133 }
134
135 // add the rest of the groups to the end
136 groups.addAll(nameGroups);
137
138 Iterator i = groups.iterator();
139 String fileList = "";
140 while (i.hasNext()) {
141 String groupName = (String) i.next();
142 _logger.write(toString(), Logger.DEBUG, "looking for config entry for - " + groupName);
143 // we look for this entry in the systemConfig
144 String configFile = _systemConfig.getProperty("config." + groupName);
145 // 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 }
164 }
165 // add the system config as the final check
166 fileList = _systemConfigFile + ";" + fileList;
167 _logger.write(toString(), Logger.DEBUG, "config tree - " + fileList);
168
169 // build the configuration
170 Configuration config = buildConfiguration(fileList);
171
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
202 /**
203 * Overrides the {@link java.lang.Object#toString() Object.toString()}
204 * method to provide clean logging (every class should have this).
205 *
206 * This uses the uk.org.iscream.cms.server.util.FormatName class
207 * to format the toString()
208 *
209 * @return the name of this class and its CVS revision
210 */
211 public String toString() {
212 return FormatName.getName(
213 _name,
214 getClass().getName(),
215 REVISION);
216 }
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 * @param readFiles used for recursion purposes only, these are the files it has read so far
228 *
229 * @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 * @throws CircularIncludeException this is if a circular include is detected
234 */
235 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 Properties properties = new Properties();
247 properties.load(new FileInputStream(new File(_configPath, currentFile)));
248
249 // get the include property
250 String includes = properties.getProperty("include");
251
252 // if we're the last file with no includes, return our name
253 if (includes == null) {
254 return currentFile;
255
256 // otherwise, recurse over our includes
257 } else {
258 StringTokenizer st = new StringTokenizer(includes, ";");
259 String returnList= "";
260 while (st.hasMoreTokens()) {
261 returnList = getIncludedFiles(st.nextToken(), readFiles) + ";" + returnList;
262 }
263
264 return returnList + currentFile;
265 }
266 }
267
268 /**
269 * 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 * Opens and loads the system configuration into the
289 * local reference _systemConfig
290 */
291 private void loadSystemConfig() {
292 _logger.write(this.toString(), Logger.SYSMSG, "reloading " + _systemConfigFile);
293 // 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 _systemConfigHolder = new Properties();
298 _systemConfigHolder.load(new FileInputStream(systemConfigFile));
299
300 // create the servant
301 ConfigurationServant ref = new ConfigurationServant(_systemConfigHolder, _systemConfigFile, systemConfigFile.lastModified());
302 org.omg.CORBA.Object objRef = _refman.getRootPOA().servant_to_reference(ref);
303
304 // narrow it to a Configuration
305 _systemConfig = ConfigurationHelper.narrow(objRef);
306
307 } catch (Exception e) {
308 _logger.write(toString(), Logger.FATAL, "ERROR: " + e.getMessage());
309 }
310 }
311
312 /**
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 _logger.write(toString(), Logger.DEBUG, "searching groups for - " + source);
325 LinkedList groupMembership = new LinkedList();
326 Iterator i = new TreeSet(_systemConfigHolder.keySet()).iterator();
327 while(i.hasNext()) {
328 String key = (String) i.next();
329 // look for a key that's a group entry
330 if (key.startsWith("group.")) {
331 // get the list of hosts in the group
332 String group = _systemConfig.getProperty(key);
333 if(groupMatch(source, group)) {
334 groupMembership.add(key.substring(6));
335 _logger.write(toString(), Logger.DEBUG, "group match found for - " + source + " in group - " + key);
336 }
337 }
338 }
339 return groupMembership;
340 }
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 }
371
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 if (!fileList.equals("")) {
385 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 long lastModified = 0, newLastModified = 0;
393 Properties properties = null, prevProperties = null;
394
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 while (st.hasMoreTokens()) {
403 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 }
412
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 _logger.write(toString(), Logger.DEBUG, "returning built configuration");
418 } catch (Exception e) {
419 // not sure what to do here
420 // so we just log the error
421 _logger.write(toString(), Logger.ERROR, "ERROR - " + e);
422 }
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 //---ACCESSOR/MUTATOR METHODS---
433
434 //---ATTRIBUTES---
435
436 /**
437 * 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 */
451 private Logger _logger = ReferenceManager.getInstance().getLogger();
452
453 /**
454 * A reference to the reference manager in use
455 */
456 private ReferenceManager _refman = ReferenceManager.getInstance();
457
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
473 /**
474 * The system config file represented by a
475 * properties object.
476 */
477 private Properties _systemConfigHolder;
478
479 //---STATIC ATTRIBUTES---
480
481 }