Cleanup configuration update handling and fix problem clearing alarms

git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/ec/trunk@35816 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
Richard Frith-MacDonald 2012-11-23 12:45:09 +00:00
parent d5a58f6b45
commit 84f3276514
4 changed files with 242 additions and 259 deletions

View file

@ -467,19 +467,38 @@ EcMakeManagedObject(NSString *host, NSString *process, NSString *component)
{
Class c = [self class];
return [NSString stringWithFormat:
@"Alarm %-8d %@ %@ %@ %@ %@ at %@(%@) %@ %@ %@",
_notificationID,
_managedObject,
[c stringFromEventType: _eventType],
[c stringFromProbableCause: _probableCause],
[c stringFromSeverity: _perceivedSeverity],
[c stringFromTrend: _trendIndicator],
_eventDate,
_firstEventDate,
_specificProblem,
_proposedRepairAction,
_additionalText];
if (0 == _notificationID)
{
return [NSString stringWithFormat:
@"Alarm addr: %-16" PRIx64 " %@ %@ %@ %@ %@ at %@(%@) %@ %@ %@",
(uint64_t)(uintptr_t)self,
_managedObject,
[c stringFromEventType: _eventType],
[c stringFromProbableCause: _probableCause],
[c stringFromSeverity: _perceivedSeverity],
[c stringFromTrend: _trendIndicator],
_eventDate,
_firstEventDate,
_specificProblem,
_proposedRepairAction,
_additionalText];
}
else
{
return [NSString stringWithFormat:
@"Alarm notification: %-8d %@ %@ %@ %@ %@ at %@(%@) %@ %@ %@",
_notificationID,
_managedObject,
[c stringFromEventType: _eventType],
[c stringFromProbableCause: _probableCause],
[c stringFromSeverity: _perceivedSeverity],
[c stringFromTrend: _trendIndicator],
_eventDate,
_firstEventDate,
_specificProblem,
_proposedRepairAction,
_additionalText];
}
}
- (void) encodeWithCoder: (NSCoder*)aCoder

View file

@ -82,7 +82,12 @@ static NSArray *modes;
logger->interval = 10;
logger->size = 8 * 1024;
logger->message = [[NSMutableString alloc] initWithCapacity: 2048];
[EcProc setCmdUpdate: logger withMethod: @selector(update)];
[[NSNotificationCenter defaultCenter]
addObserver: self
selector: @selector(update)
name: NSUserDefaultsDidChangeNotification
object: [EcProc cmdDefaults]];
[logger update];
[loggers addObject: logger];
RELEASE(logger);
@ -133,6 +138,7 @@ static NSArray *modes;
{
[self flush];
[timer invalidate];
[[NSNotificationCenter defaultCenter] removeObserver: self];
RELEASE(key);
RELEASE(flushKey);
RELEASE(serverKey);
@ -479,13 +485,22 @@ static NSArray *modes;
[self _flush];
}
/* Should only be called on main thread.
/* Should only execute on main thread.
*/
- (void) update
{
NSUserDefaults *defs = [NSUserDefaults standardUserDefaults];
NSUserDefaults *defs;
NSString *str;
if (NO == [NSThread isMainThread])
{
[self performSelectorOnMainThread: @selector(update)
withObject: nil
waitUntilDone: NO
modes: modes];
return;
}
defs = [EcProc cmdDefaults];
/*
* If there is a server specified for this debug logger, we want it
* registered so we can use it - otherwise we will default to using

View file

@ -181,12 +181,16 @@ typedef enum {
from: (NSString*)c;
/** Shut down the Command server and all its clients */
- (oneway void) terminate;
/** An exceptional method and can be used without registering first
* (ie, can be used by anyone, not only clients of the Command server).
* It's meant to be used remotely by java servlets, and all sort of
/** This is an exceptional method which may be used without registering
* your process with a Command server first (ie, it can be used by anyone,
* not only clients of the Command server).<br />
* It's meant to be used remotely by Java servlets, and all sort of
* software running on the machine and which is *not* a full Command
* client (ie, a subclass of EcProcess) but which still wants to retrieve
* configuration from a central location (the Control/Command servers).
* configuration from a central location (the Control/Command servers).<br />
* The returned value is a a serialized property list ... you need to
* deserialize using the standard GNUstep property list APIs.<br />
* NB: The configuration might change later on, so you must not cache
* the configuration after asking for it, but rather ask for it each
* time your software needs it.
@ -391,7 +395,8 @@ extern NSString* cmdVersion(NSString *ver);
*/
- (void) cmdAlert: (NSString*)fmt arguments: (va_list)args;
/** Send a SEVERE error message to the server.
/** Send a SEVERE error message to the server by calling the
* -cmdAlert:arguments: method.
*/
- (void) cmdAlert: (NSString*)fmt, ...;
@ -406,7 +411,7 @@ extern NSString* cmdVersion(NSString *ver);
*/
- (void) cmdAudit: (NSString*)fmt arguments: (va_list)args;
/** Send a log message to the server.
/** Send a log message to the server by calling the -cmdAudit:arguments: method.
*/
- (void) cmdAudit: (NSString*)fmt, ...;
@ -425,22 +430,29 @@ extern NSString* cmdVersion(NSString *ver);
- (void) cmdDbg: (NSString*)type msg: (NSString*)fmt arguments: (va_list)args;
/** Send a debug message - as long as the debug mode specified as 'type'
* is currently set.
* is currently set. Operates by calling the -cmdDbg:msg:arguments: method.
*/
- (void) cmdDbg: (NSString*)type msg: (NSString*)fmt, ...;
/** Send a debug message with debug mode 'defaultMode'.
/** Send a debug message with debug mode 'defaultMode'.<br />
* Calls the -cmdDbg:msg:arguments: method.
*/
- (void) cmdDebug: (NSString*)fmt arguments: (va_list)args;
/** Send a debug message with debug mode 'defaultMode'.
/** Send a debug message with debug mode 'defaultMode'.<br />
* Operates by calling the -cmdDebug:arguments: method.
*/
- (void) cmdDebug: (NSString*)fmt, ...;
/** Called whenever the user defaults are updated due to a central
* configuration change (or another defaults system change).<br />
* This is also called by -cmdUpdate: even if no configuration
* actually changed ... in which case the notification argument
* is nil.<br />
* If you override this to handle configuration changes, don't forget
* to call the superclass implementation.
* to call the superclass implementation.<br />
* This method is provided to allow subclasses to control the order
* in which defaults changes are handled by them and their superclasses.
*/
- (void) cmdDefaultsChanged: (NSNotification*)n;
@ -448,11 +460,12 @@ extern NSString* cmdVersion(NSString *ver);
*/
- (void) cmdError: (NSString*)fmt arguments: (va_list)args;
/** Send an error message to the server.
/** Send an error message to the server by calling the
* -cmdError:arguments: method.
*/
- (void) cmdError: (NSString*)fmt, ...;
/** Flush logging information
/** Flush logging information.
*/
- (void) cmdFlushLogs;
@ -465,12 +478,13 @@ extern NSString* cmdVersion(NSString *ver);
*/
- (BOOL) cmdIsClient;
/** Returns a fag indicating whether this process is currently connected
/** Returns a flag indicating whether this process is currently connected
* it its Command server.
*/
- (BOOL) cmdIsConnected;
/** Returns YES is the process is running in test mode, NO otherwise.
/** Returns YES is the process is running in test mode, NO otherwise.<br />
* Test mode is defined by the EcTesting user default.
*/
- (BOOL) cmdIsTesting;
@ -505,10 +519,10 @@ extern NSString* cmdVersion(NSString *ver);
* array).<br />
* There are two special cases ... when the operator types 'help XXX' your
* method will be called with 'help'as the first element of the array and
* you should respond with some useful hep text, and when the operator
* you should respond with some useful help text, and when the operator
* simply wants a short description of what the command does, the array
* argument will be nil (and your method should respond with a short
* description of the cmmand).
* description of the command).
*/
- (NSString*) cmdMesg: (NSArray*)msg;
@ -525,7 +539,9 @@ extern NSString* cmdVersion(NSString *ver);
*/
- (NSMutableDictionary*)cmdOperator: (NSString*)name password: (NSString*)pass;
/** Used to tell your application to quit.
/** Used to tell your application to quit.<br />
* Subclasses should override this method to perform any pre-shutdown cleanup
* before they call the superclass implementation.
*/
- (void) cmdQuit: (NSInteger)status;
@ -533,11 +549,32 @@ extern NSString* cmdVersion(NSString *ver);
*/
- (int) cmdSignalled;
/** Used to tell your application about configuration changes.
/** Used to tell your application about configuration changes.<br />
* This is called before the NSUserDefaults system is updated with the
* changes, so you may use it to update internal state in the knowledge
* that code watching for user defaults change notifications will not
* have updated yet.<br />
* The base class implementation is responsible for updating the user
* defaults system ... so be sure that your implementation calls the
* superclass implementation (unless you wish to suppress the configuration
* update).<br />
* You may alter the info dictionary prior to passign it to the superclass
* implementation if you wish to adjust the new configuration before it
* takes effect.
*/
- (void) cmdUpdate: (NSMutableDictionary*)info;
/** Used to tell your application about configuration changes.<br />
* This is called after the NSUserDefaults system is updated with the
* changes, so you may use it to update internal state in the knowledge
* that code watching for user defaults change notifications will have
* updated already.<br />
* NB. This method will be called even if your implementation of
* -cmdUpdate: suppresses the actual update. In this situation this
* method will find the configuration unchanged since the previous
* time that it was called.
*/
- (void) cmdUpdated;
- (void) log: (NSString*)message type: (EcLogType)t;
@ -572,25 +609,13 @@ extern NSString* cmdVersion(NSString *ver);
*/
- (void) setCmdTimeout: (SEL)sel;
/** Specify an object 'obj' to be sent a message 'sel' when the
* network configuration information for this process has been changed.
* If 'sel' is a nul selector, then the specified object is removed
* from the list of objects to be notified. The EcProces class will
* retain the object given.
*/
- (void) setCmdUpdate: (id)obj withMethod: (SEL)sel;
/*
* Trigger a timeout to go off as soon as possible ... subsequent timeouts
* go off at the normal interval after that one.
*/
- (void) triggerCmdTimeout;
/** Obtains the configuration value for the specified key from the
* NSUserDefaults system (as modified by the Command server).<br />
* If you need more than one value, or if you want a typed values,
* you should call -cmdDefaults to get the defaults object, and then
* call methods of that object directly.
/** Deprecated ... use -cmdDefaults instead.
*/
- (id) cmdConfig: (NSString*)key;

View file

@ -433,7 +433,7 @@ static EcLogger *warningLogger = nil;
static NSMutableSet *cmdActions = nil;
static id cmdServer = nil;
static id cmdPTimer = nil;
static NSMutableDictionary *cmdConf = nil;
static NSDictionary *cmdConf = nil;
static NSDictionary *cmdOperators = nil;
static NSDate *cmdFirst = nil;
static NSDate *cmdLast = nil;
@ -446,8 +446,6 @@ static NSTimeInterval cmdTimInterval = 60.0;
static NSMutableArray *noNetConfig = nil;
static NSMutableArray *updateHandlers = nil;
static NSMutableDictionary *servers = nil;
static NSString *hostName = nil;
@ -536,47 +534,6 @@ ecCommandName()
}
@interface UpdateHandler: NSObject
{
id obj;
SEL sel;
}
- (id) initWithObj: (id)o andSel: (SEL)s;
- (id) obj;
- (SEL) sel;
- (void) setSel: (SEL)s;
@end
@implementation UpdateHandler
- (void) dealloc
{
RELEASE(obj);
[super dealloc];
}
- (id) initWithObj: (id)o andSel: (SEL)s;
{
self = [super init];
if (self != nil)
{
obj = RETAIN(o);
sel = s;
}
return self;
}
- (id) obj
{
return obj;
}
- (SEL) sel
{
return sel;
}
- (void) setSel: (SEL)s
{
sel = s;
}
@end
NSString *cmdDefaultDbg = @"defaultMode";
NSString *cmdConnectDbg = @"connectMode";
NSString *cmdDetailDbg = @"detailMode";
@ -980,6 +937,7 @@ findMode(NSDictionary* d, NSString* s)
- (void) cmdMesgtesting: (NSArray*)msg;
- (NSString*) _moveLog: (NSString*)name to: (NSString*)sub;
- (void) _timedOut: (NSTimer*)timer;
- (void) _update: (NSMutableDictionary*)info;
@end
@implementation EcProcess
@ -1088,10 +1046,12 @@ static NSString *noFiles = @"No log files to archive";
- (void) cmdDefaultsChanged: (NSNotification*)n
{
NSEnumerator *enumerator = [cmdDebugKnown keyEnumerator];
NSEnumerator *enumerator;
NSDictionary *dict;
NSString *mode;
NSString *str;
enumerator = [cmdDebugKnown keyEnumerator];
while (nil != (mode = [enumerator nextObject]))
{
NSString *key = [@"Debug-" stringByAppendingString: mode];
@ -1118,6 +1078,34 @@ static NSString *noFiles = @"No log files to archive";
GSDebugAllocationActive([cmdDefs boolForKey: @"Memory"]);
[NSObject enableDoubleReleaseCheck: [cmdDefs boolForKey: @"Release"]];
cmdFlagTesting = [cmdDefs boolForKey: @"Testing"];
if ((str = [cmdDefs stringForKey: @"CmdInterval"]) != nil)
{
[self setCmdInterval: [str floatValue]];
}
str = [cmdDefs stringForKey: @"MemAllowed"];
if (nil != str)
{
memAllowed = [str intValue];
if (memAllowed <= 0)
{
memAllowed = DEFMEMALLOWED; // Fifty megabytes default
}
}
if (servers != nil)
{
NSEnumerator *e;
RemoteServer *server;
e = [servers objectEnumerator];
while ((server = [e nextObject]))
{
[server update];
}
}
}
- (NSString*) cmdDebugPath
@ -1791,7 +1779,7 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
selector: @selector(cmdConnectionBecameInvalid:)
name: NSConnectionDidDieNotification
object: connection];
[self cmdUpdate: r];
[self _update: r];
}
}
}
@ -2046,46 +2034,6 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
[self triggerCmdTimeout];
}
- (void) setCmdUpdate: (id)obj withMethod: (SEL)sel
{
UpdateHandler *u;
unsigned count = [updateHandlers count];
unsigned i;
if (updateHandlers == nil)
{
updateHandlers = [[NSMutableArray alloc] initWithCapacity: 1];
}
for (i = 0; i < count; i++)
{
u = [updateHandlers objectAtIndex: i];
if ([u obj] == obj)
{
break;
}
}
if (i == count)
{
if (sel != 0)
{
u = [[UpdateHandler alloc] initWithObj: obj andSel: sel];
[updateHandlers addObject: u];
RELEASE(u);
}
}
else
{
if (sel == 0)
{
[updateHandlers removeObjectAtIndex: i];
}
else
{
[u setSel: sel];
}
}
}
- (void) triggerCmdTimeout
{
if (cmdPTimer != nil)
@ -2341,8 +2289,8 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
{
[self cmdPrintf: @"\nThe clear command is used to clear the"];
[self cmdPrintf: @" alarms currently active for this process.\n"];
[self cmdPrintf: @"You may use the ord 'all' or a space separated"];
[self cmdPrintf: @" list of alarm notification IDs.\n"];
[self cmdPrintf: @"You may use the word 'all' or a space separated"];
[self cmdPrintf: @" list of alarm addreesses.\n"];
}
else
{
@ -2362,6 +2310,7 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
for (index = 1; index < count; index++)
{
uint64_t addr;
NSString *arg = [msg objectAtIndex: index];
if ([arg caseInsensitiveCompare: _(@"all")]
@ -2377,16 +2326,15 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
[alarmDestination alarm: alarm];
}
}
else
else if (1 == sscanf([arg UTF8String], "%" PRIx64, &addr))
{
int n = [arg intValue];
NSUInteger i;
alarm = nil;
for (i = 0; i < alarmCount; i++)
{
alarm = [a objectAtIndex: i];
if ([alarm notificationID] == n)
if ((uint64_t)(uintptr_t)alarm == addr)
{
break;
}
@ -2395,7 +2343,7 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
if (nil == alarm)
{
[self cmdPrintf:
@"No alarm found with the notificationID '%@'\n",
@"No alarm found with the address '%@'\n",
arg];
}
else
@ -2405,6 +2353,11 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
[alarmDestination alarm: alarm];
}
}
else
{
[self cmdPrintf: @"Not a hexadecimal address: '%@'\n",
arg];
}
}
}
}
@ -2900,135 +2853,31 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
- (void) cmdUpdate: (NSMutableDictionary*)info
{
NSMutableDictionary *newConfig;
NSDictionary *dict;
NSEnumerator *enumerator;
NSString *key;
BOOL update = NO;
BOOL defaultsChanged;
if (info == nil)
if (nil == info)
{
update = YES;
defaultsChanged = NO;
}
else
{
newConfig = [NSMutableDictionary dictionaryWithCapacity: 32];
/*
* Put all values for this application in the cmdConf dictionary.
*/
dict = [info objectForKey: cmdLogName()];
if (dict != nil)
{
enumerator = [dict keyEnumerator];
while ((key = [enumerator nextObject]) != nil)
{
id obj;
if ([noNetConfig containsObject: key])
{
[self cmdWarn: @"Bad key '%@' in net config.", key];
continue;
}
obj = [dict objectForKey: key];
[newConfig setObject: obj forKey: key];
}
}
/*
* Add any default values to the cmdConf
* dictionary where we don't have application
* specific values.
*/
dict = [info objectForKey: @"*"];
if (dict)
{
enumerator = [dict keyEnumerator];
while ((key = [enumerator nextObject]) != nil)
{
if ([newConfig objectForKey: key] == nil)
{
id obj;
if ([noNetConfig containsObject: key])
{
[self cmdWarn: @"Bad key '%@' in net config.", key];
continue;
}
obj = [dict objectForKey: key];
[newConfig setObject: obj forKey: key];
}
}
}
dict = [info objectForKey: @"Operators"];
if (dict != nil && dict != cmdOperators)
{
ASSIGNCOPY(cmdOperators, dict);
}
if (cmdConf == nil || [cmdConf isEqual: newConfig] == NO)
{
ASSIGN(cmdConf, newConfig);
update = [cmdDefs setConfiguration: newConfig];
}
ASSIGNCOPY(cmdConf, info);
defaultsChanged = [cmdDefs setConfiguration: cmdConf];
}
/*
* Now we update any settings which may be changed on the fly.
/* If the defaults did not actually change,
* trigger an update anyway.
*/
if (update == YES)
if (NO == defaultsChanged)
{
NSString *str;
if ((str = [self cmdConfig: @"CmdInterval"]) != nil)
{
[self setCmdInterval: [str floatValue]];
}
str = [self cmdConfig: @"MemAllowed"];
if (nil != str)
{
memAllowed = [str intValue];
if (memAllowed <= 0)
{
memAllowed = DEFMEMALLOWED; // Fifty megabytes default
}
}
/*
* Notify all interested parties of update.
*/
if (updateHandlers != nil)
{
NSArray *a = [NSArray arrayWithArray: updateHandlers];
unsigned count = [a count];
unsigned i;
for (i = 0; i < count; i++)
{
UpdateHandler *u = [a objectAtIndex: i];
if ([updateHandlers indexOfObjectIdenticalTo: u] != NSNotFound)
{
[[u obj] performSelector: [u sel]];
}
}
}
}
if (servers != nil)
{
NSEnumerator *e;
RemoteServer *server;
e = [servers objectEnumerator];
while ((server = [e nextObject]))
{
[server update];
}
[self cmdDefaultsChanged: nil];
}
}
- (void) cmdUpdated
{
return;
}
- (void) dealloc
{
@ -3602,7 +3451,7 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
if (nil != plist)
{
[self cmdUpdate: plist];
[self _update: plist];
}
}
@ -3950,5 +3799,80 @@ NSLog(@"Ignored attempt to set timer interval to %g ... using 10.0", interval);
}
}
- (void) _update: (NSMutableDictionary*)info
{
NSMutableDictionary *newConfig;
NSDictionary *dict;
NSEnumerator *enumerator;
NSString *key;
newConfig = [NSMutableDictionary dictionaryWithCapacity: 32];
/*
* Put all values for this application in the cmdConf dictionary.
*/
dict = [info objectForKey: cmdLogName()];
if (dict != nil)
{
enumerator = [dict keyEnumerator];
while ((key = [enumerator nextObject]) != nil)
{
id obj;
if ([noNetConfig containsObject: key])
{
[self cmdWarn: @"Bad key '%@' in net config.", key];
continue;
}
obj = [dict objectForKey: key];
[newConfig setObject: obj forKey: key];
}
}
/*
* Add any default values to the cmdConf
* dictionary where we don't have application
* specific values.
*/
dict = [info objectForKey: @"*"];
if (dict)
{
enumerator = [dict keyEnumerator];
while ((key = [enumerator nextObject]) != nil)
{
if ([newConfig objectForKey: key] == nil)
{
id obj;
if ([noNetConfig containsObject: key])
{
[self cmdWarn: @"Bad key '%@' in net config.", key];
continue;
}
obj = [dict objectForKey: key];
[newConfig setObject: obj forKey: key];
}
}
}
dict = [info objectForKey: @"Operators"];
if (dict != nil && dict != cmdOperators)
{
ASSIGNCOPY(cmdOperators, dict);
}
if (nil == cmdConf || [cmdConf isEqual: newConfig] == NO)
{
NS_DURING
[self cmdUpdate: newConfig];
NS_HANDLER
[self cmdError: @"Problem before updating config: %@", localException];
NS_ENDHANDLER
NS_DURING
[self cmdUpdated];
NS_HANDLER
[self cmdError: @"Problem after updating config: %@", localException];
NS_ENDHANDLER
}
}
@end