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.24
Committed: Tue May 21 16:47:17 2002 UTC (22 years ago) by tdb
Branch: MAIN
Changes since 1.23: +3 -2 lines
Log Message:
Added URL to GPL headers.

File Contents

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