mirror of
https://github.com/gnustep/libs-ec.git
synced 2025-02-15 16:11:01 +00:00
1015 lines
25 KiB
Objective-C
1015 lines
25 KiB
Objective-C
|
|
/** Enterprise Control Configuration and Logging
|
|
|
|
Copyright (C) 2012 Free Software Foundation, Inc.
|
|
|
|
Written by: Richard Frith-Macdonald <rfm@gnu.org>
|
|
Date: Febrary 2010
|
|
Originally developed from 1996 to 2012 by Brainstorm, and donated to
|
|
the FSF.
|
|
|
|
This file is part of the GNUstep project.
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
modify it under the terms of the GNU Lesser General Public
|
|
License as published by the Free Software Foundation; either
|
|
version 3 of the License, or (at your option) any later version.
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
Library General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
|
License along with this library; if not, write to the Free
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
Boston, MA 02111 USA.
|
|
|
|
*/
|
|
|
|
#import <Foundation/Foundation.h>
|
|
|
|
#import "EcProcess.h"
|
|
#import "EcAlarm.h"
|
|
#import "EcAlarmDestination.h"
|
|
|
|
|
|
@interface EcAlarmDestination (Private)
|
|
|
|
/* Make connection to destination host.
|
|
*/
|
|
- (id<EcAlarmDestination>) _connect;
|
|
|
|
/* Loss of connection ... clear destination.
|
|
*/
|
|
- (void) _connectionBecameInvalid: (id)connection;
|
|
|
|
/* Regular timer to handle alarms.
|
|
*/
|
|
- (void) _timeout: (NSTimer*)t;
|
|
|
|
/* Remove alll recdords for managed object
|
|
*/
|
|
- (void) _unmanage: (NSString*)m;
|
|
|
|
@end
|
|
|
|
@implementation EcAlarmDestination
|
|
|
|
- (void) activePut: (EcAlarm*)alarm
|
|
{
|
|
if (_monitor != self)
|
|
{
|
|
[_monitor activePut: alarm];
|
|
}
|
|
[_alarmLock lock];
|
|
[_alarmsActive addObject: alarm];
|
|
[_alarmLock unlock];
|
|
}
|
|
|
|
- (void) activeRemove: (EcAlarm*)alarm
|
|
{
|
|
if (_monitor != self)
|
|
{
|
|
[_monitor activeRemove: alarm];
|
|
}
|
|
[_alarmLock lock];
|
|
[_alarmsActive removeObject: alarm];
|
|
[_alarmLock unlock];
|
|
}
|
|
|
|
- (oneway void) alarm: (in bycopy EcAlarm*)event
|
|
{
|
|
if (NO == [event isKindOfClass: [EcAlarm class]])
|
|
{
|
|
NSLog(@"[%@-%@] invalid argument (%@)",
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
|
|
event);
|
|
}
|
|
else
|
|
{
|
|
EcAlarmSeverity severity = [event perceivedSeverity];
|
|
|
|
[_alarmLock lock];
|
|
if (YES == _coalesceOff)
|
|
{
|
|
[_alarmQueue addObject: event];
|
|
}
|
|
else if (EcAlarmSeverityCleared == severity)
|
|
{
|
|
NSUInteger index;
|
|
|
|
index = [_alarmQueue indexOfObject: event];
|
|
if (NSNotFound == index)
|
|
{
|
|
[_alarmQueue addObject: event];
|
|
}
|
|
else
|
|
{
|
|
EcAlarm *old = [_alarmQueue objectAtIndex: index];
|
|
EcAlarmSeverity oldSeverity = [old perceivedSeverity];
|
|
|
|
if (EcAlarmSeverityCleared == oldSeverity)
|
|
{
|
|
/* Repeated clears may be coalesced with later clears
|
|
* being ignored.
|
|
*/
|
|
if (YES == _debug)
|
|
{
|
|
NSLog(@"Coalesce %@ by dropping it (%@ exists)",
|
|
event, old);
|
|
}
|
|
[_alarmQueue addObject: event];
|
|
[_alarmQueue removeObjectAtIndex: index];
|
|
}
|
|
else if (nil == [_alarmsActive member: old])
|
|
{
|
|
/* An alarm which is not yet active may be cancelled-out
|
|
* by a following clear.
|
|
*/
|
|
if (YES == _debug)
|
|
{
|
|
NSLog(@"Coalesce %@ by removing %@ (old)",
|
|
event, old);
|
|
}
|
|
[_alarmQueue removeObjectAtIndex: index];
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NSUInteger index;
|
|
|
|
index = [_alarmQueue indexOfObject: event];
|
|
if (NSNotFound == index)
|
|
{
|
|
[_alarmQueue addObject: event];
|
|
}
|
|
else
|
|
{
|
|
EcAlarm *old = [_alarmQueue objectAtIndex: index];
|
|
EcAlarmSeverity oldSeverity = [old perceivedSeverity];
|
|
|
|
if (EcAlarmSeverityCleared == oldSeverity)
|
|
{
|
|
/* A clear can be replaced by a raised alarm.
|
|
*/
|
|
[_alarmQueue addObject: event];
|
|
if (YES == _debug)
|
|
{
|
|
NSLog(@"Coalesce %@ by removing %@ (old)",
|
|
event, old);
|
|
}
|
|
[_alarmQueue removeObjectAtIndex: index];
|
|
}
|
|
else if (severity < oldSeverity)
|
|
{
|
|
/* Lower numeric values are higher severity,
|
|
* so the new alarm supercedes the old one.
|
|
*/
|
|
[_alarmQueue addObject: event];
|
|
if (YES == _debug)
|
|
{
|
|
NSLog(@"Coalesce %@ by removing %@ (old)",
|
|
event, old);
|
|
}
|
|
[_alarmQueue removeObjectAtIndex: index];
|
|
}
|
|
else
|
|
{
|
|
if (YES == _debug)
|
|
{
|
|
NSLog(@"Coalesce %@ by dropping it (%@ exists)",
|
|
event, old);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
[_alarmLock unlock];
|
|
}
|
|
}
|
|
|
|
- (NSArray*) alarms
|
|
{
|
|
NSArray *a;
|
|
|
|
[_alarmLock lock];
|
|
a = [_alarmsActive allObjects];
|
|
[_alarmLock unlock];
|
|
return a;
|
|
}
|
|
|
|
- (NSArray*) backups
|
|
{
|
|
NSArray *a;
|
|
|
|
[_alarmLock lock];
|
|
a = [_backups retain];
|
|
[_alarmLock unlock];
|
|
return [a autorelease];
|
|
}
|
|
|
|
- (NSArray*) clears
|
|
{
|
|
NSArray *a;
|
|
|
|
[_alarmLock lock];
|
|
a = [_alarmsCleared allObjects];
|
|
[_alarmLock unlock];
|
|
return a;
|
|
}
|
|
|
|
- (void) clearsPut: (EcAlarm*)alarm
|
|
{
|
|
if (_monitor != self)
|
|
{
|
|
[_monitor clearsPut: alarm];
|
|
}
|
|
[_alarmLock lock];
|
|
[_alarmsCleared addObject: alarm];
|
|
[_alarmLock unlock];
|
|
}
|
|
|
|
- (void) clearsRemove: (EcAlarm*)alarm
|
|
{
|
|
if (_monitor != self)
|
|
{
|
|
[_monitor clearsRemove: alarm];
|
|
}
|
|
[_alarmLock lock];
|
|
[_alarmsCleared removeObject: alarm];
|
|
[_alarmLock unlock];
|
|
}
|
|
|
|
- (void) dealloc
|
|
{
|
|
[self shutdown];
|
|
DESTROY(_thread);
|
|
DESTROY(_backups);
|
|
DESTROY(_destination);
|
|
DESTROY(_monitor);
|
|
DESTROY(_alarmQueue);
|
|
DESTROY(_alarmsActive);
|
|
DESTROY(_alarmsCleared);
|
|
DESTROY(_managedObjects);
|
|
DESTROY(_alarmLock);
|
|
[super dealloc];
|
|
}
|
|
|
|
- (NSString*) description
|
|
{
|
|
NSString *desc;
|
|
|
|
[_alarmLock lock];
|
|
if (_isRunning)
|
|
{
|
|
desc = [NSString stringWithFormat: @"%@ host:%@ name:%@"
|
|
@" queue:%u active:%u cleared:%u managed:%u",
|
|
[super description], _host, _name, (unsigned)[_alarmQueue count],
|
|
(unsigned)[_alarmsActive count],
|
|
(unsigned)[_alarmsCleared count],
|
|
(unsigned)[_managedObjects count]];
|
|
}
|
|
else
|
|
{
|
|
desc = [NSString stringWithFormat: @"%@ host:%@ name:%@ Not Running",
|
|
[super description], _host, _name];
|
|
}
|
|
[_alarmLock unlock];
|
|
return desc;
|
|
}
|
|
|
|
- (id) initWithHost: (NSString*)host name: (NSString*)name
|
|
{
|
|
if (nil != (self = [super init]))
|
|
{
|
|
NSDate *begin;
|
|
|
|
_host = [host copy];
|
|
_name = [name copy];
|
|
_alarmLock = [NSRecursiveLock new];
|
|
_alarmQueue = [NSMutableArray new];
|
|
_alarmsActive = [NSMutableSet new];
|
|
_alarmsCleared = [NSMutableSet new];
|
|
_managedObjects = [NSMutableSet new];
|
|
|
|
_thread = [[NSThread alloc] initWithTarget: self
|
|
selector: @selector(run)
|
|
object: nil];
|
|
[_thread setName: @"alarmdest"];
|
|
[_thread start];
|
|
|
|
begin = [NSDate date];
|
|
while (NO == [self isRunning])
|
|
{
|
|
NSDate *when;
|
|
|
|
if ([begin timeIntervalSinceNow] < -5.0)
|
|
{
|
|
NSLog(@"alarm thread failed to start within 5 seconds");
|
|
[_alarmLock lock];
|
|
_shouldStop = YES; // If the thread starts ... shutdown
|
|
[_alarmLock unlock];
|
|
[self release];
|
|
return nil;
|
|
}
|
|
when = [[NSDate alloc] initWithTimeIntervalSinceNow: 0.1];
|
|
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
|
|
beforeDate: when];
|
|
[when release];
|
|
}
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (oneway void) domanage: (in bycopy NSString*)managedObject
|
|
{
|
|
if (nil == managedObject)
|
|
{
|
|
managedObject = EcMakeManagedObject(nil, nil, nil);
|
|
}
|
|
if (NO == [managedObject isKindOfClass: [NSString class]]
|
|
|| 4 != [[managedObject componentsSeparatedByString: @"_"] count])
|
|
{
|
|
NSLog(@"[%@-%@] invalid argument (%@)",
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
|
|
managedObject);
|
|
}
|
|
else
|
|
{
|
|
NSString *event;
|
|
|
|
event = [NSString stringWithFormat: @"domanage %@", managedObject];
|
|
[_alarmLock lock];
|
|
if (YES == _coalesceOff)
|
|
{
|
|
[_alarmQueue addObject: event];
|
|
}
|
|
else
|
|
{
|
|
NSUInteger index = [_alarmQueue indexOfObject: event];
|
|
|
|
[_alarmQueue addObject: event];
|
|
if (NSNotFound != index)
|
|
{
|
|
if (YES == _debug)
|
|
{
|
|
NSLog(@"Coalesce %@", event);
|
|
}
|
|
[_alarmQueue removeObjectAtIndex: index];
|
|
}
|
|
}
|
|
[_alarmLock unlock];
|
|
}
|
|
}
|
|
|
|
- (id) init
|
|
{
|
|
return [self initWithHost: nil name: nil];
|
|
}
|
|
|
|
- (BOOL) isRunning
|
|
{
|
|
BOOL result;
|
|
|
|
[_alarmLock lock];
|
|
result = _isRunning;
|
|
[_alarmLock unlock];
|
|
return result;
|
|
}
|
|
|
|
- (EcAlarm*) latest: (EcAlarm*)toFind
|
|
{
|
|
EcAlarm *found = nil;
|
|
NSUInteger index;
|
|
|
|
[_alarmLock lock];
|
|
/* First try to find the most recent match in the queue
|
|
*/
|
|
index = [_alarmQueue count];
|
|
while (index-- > 0)
|
|
{
|
|
EcAlarm *a = [_alarmQueue objectAtIndex: index];
|
|
|
|
if ([a isEqual: toFind])
|
|
{
|
|
found = RETAIN(a);
|
|
break;
|
|
}
|
|
}
|
|
if (nil == found)
|
|
{
|
|
/* Not in queue ... try active alarms or clears
|
|
*/
|
|
found = RETAIN([_alarmsActive member: toFind]);
|
|
if (nil == found)
|
|
{
|
|
found = RETAIN([_alarmsCleared member: toFind]);
|
|
}
|
|
}
|
|
[_alarmLock unlock];
|
|
return AUTORELEASE(found);
|
|
}
|
|
|
|
- (NSArray*) managed
|
|
{
|
|
NSArray *a;
|
|
|
|
[_alarmLock lock];
|
|
a = [_managedObjects allObjects];
|
|
[_alarmLock unlock];
|
|
return a;
|
|
}
|
|
|
|
- (void) managePut: (NSString*)name
|
|
{
|
|
if (_monitor != self)
|
|
{
|
|
[_monitor managePut: name];
|
|
}
|
|
[_alarmLock lock];
|
|
[_managedObjects addObject: name];
|
|
[_alarmLock unlock];
|
|
}
|
|
|
|
- (void) manageRemove: (NSString*)name
|
|
{
|
|
if (_monitor != self)
|
|
{
|
|
[_monitor manageRemove: name];
|
|
}
|
|
[_alarmLock lock];
|
|
[_managedObjects removeObject: name];
|
|
[_alarmLock unlock];
|
|
}
|
|
|
|
- (void) run
|
|
{
|
|
NSAutoreleasePool *pool = [NSAutoreleasePool new];
|
|
NSRunLoop *loop = [NSRunLoop currentRunLoop];
|
|
NSDate *future = [NSDate distantFuture];
|
|
|
|
_isRunning = YES;
|
|
_timer = [NSTimer scheduledTimerWithTimeInterval: 1.0
|
|
target: self
|
|
selector: @selector(_timeout:)
|
|
userInfo: nil
|
|
repeats: YES];
|
|
|
|
while (YES == _isRunning)
|
|
{
|
|
[loop runMode: NSDefaultRunLoopMode beforeDate: future];
|
|
}
|
|
[pool release];
|
|
}
|
|
|
|
- (void) setBackups: (NSArray*)backups
|
|
{
|
|
NSUInteger i;
|
|
|
|
if (nil != backups && NO == [backups isKindOfClass: [NSArray class]])
|
|
{
|
|
[NSException raise: NSInvalidArgumentException
|
|
format: @"[%@-%@] argument is not nil or an array",
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
|
}
|
|
i = [backups count];
|
|
if (0 == i)
|
|
{
|
|
backups = nil;
|
|
}
|
|
else
|
|
{
|
|
while (i-- > 0)
|
|
{
|
|
if (NO == [[backups objectAtIndex: i]
|
|
isKindOfClass: [EcAlarmDestination class]])
|
|
{
|
|
[NSException raise: NSInvalidArgumentException
|
|
format: @"[%@-%@] array contains bad destination",
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
|
}
|
|
}
|
|
}
|
|
[_alarmLock lock];
|
|
ASSIGNCOPY(_backups, backups);
|
|
[_alarmLock unlock];
|
|
}
|
|
|
|
- (BOOL) setCoalesce: (BOOL)coalesce
|
|
{
|
|
BOOL old;
|
|
|
|
[_alarmLock lock];
|
|
old = (NO == _coalesceOff) ? YES : NO;
|
|
_coalesceOff = (NO == coalesce) ? YES : NO;
|
|
[_alarmLock unlock];
|
|
return old;
|
|
}
|
|
|
|
/* Much software uses integer settings for debug levels, so to selector
|
|
* type conflicts we use the same convention even though we are using it
|
|
* as a boolean.
|
|
*/
|
|
- (int) setDebug: (int)debug
|
|
{
|
|
BOOL old;
|
|
|
|
[_alarmLock lock];
|
|
old = _debug;
|
|
_debug = debug ? YES : NO;
|
|
[_alarmLock unlock];
|
|
return (int)old;
|
|
}
|
|
|
|
- (id<EcAlarmDestination>) setDestination: (id<EcAlarmDestination>)destination
|
|
{
|
|
id old;
|
|
|
|
if (nil != (id)destination && NO == [(id)destination
|
|
conformsToProtocol: @protocol(EcAlarmDestination)])
|
|
{
|
|
[NSException raise: NSInvalidArgumentException
|
|
format: @"[%@-%@] arg does not conform to EcAlarmDestination protocol",
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
|
}
|
|
[_alarmLock lock];
|
|
old = (id)_destination;
|
|
_destination = RETAIN(destination);
|
|
[_alarmLock unlock];
|
|
return AUTORELEASE(old);
|
|
}
|
|
|
|
- (id<EcAlarmMonitor>) setMonitor: (id<EcAlarmMonitor>)monitor
|
|
{
|
|
id old;
|
|
|
|
if (nil != (id)monitor && NO == [(id)monitor
|
|
conformsToProtocol: @protocol(EcAlarmMonitor)])
|
|
{
|
|
[NSException raise: NSInvalidArgumentException
|
|
format: @"[%@-%@] arg does not conform to EcAlarmMonitor protocol",
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
|
}
|
|
[_alarmLock lock];
|
|
old = (id)_monitor;
|
|
_monitor = RETAIN(monitor);
|
|
[_alarmLock unlock];
|
|
return AUTORELEASE(old);
|
|
}
|
|
|
|
- (void) shutdown
|
|
{
|
|
BOOL wasShuttingDown;
|
|
|
|
[_alarmLock lock];
|
|
wasShuttingDown = _shouldStop;
|
|
_shouldStop = YES;
|
|
[_host release];
|
|
_host = nil;
|
|
[_name release];
|
|
_name = nil;
|
|
[_alarmLock unlock];
|
|
if (NO == wasShuttingDown && [_thread isExecuting])
|
|
{
|
|
NSDate *begin;
|
|
|
|
[self performSelector: @selector(_timeout:)
|
|
onThread: _thread
|
|
withObject: nil
|
|
waitUntilDone: NO];
|
|
|
|
/* Unless we are called recursively, lets wait for a while for
|
|
* the alarm thread to terminate.
|
|
*/
|
|
begin = [NSDate date];
|
|
while (YES == [self isRunning])
|
|
{
|
|
NSDate *when;
|
|
|
|
if ([begin timeIntervalSinceNow] < -5.0)
|
|
{
|
|
NSLog(@"alarm thread failed to stop within 5 seconds");
|
|
return;
|
|
}
|
|
when = [[NSDate alloc] initWithTimeIntervalSinceNow: 0.1];
|
|
[[NSRunLoop currentRunLoop] runMode: NSDefaultRunLoopMode
|
|
beforeDate: when];
|
|
[when release];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (oneway void) unmanage: (in bycopy NSString*)managedObject
|
|
{
|
|
if (nil == managedObject)
|
|
{
|
|
managedObject = EcMakeManagedObject(nil, nil, nil);
|
|
}
|
|
if (NO == [managedObject isKindOfClass: [NSString class]]
|
|
|| 4 != [[managedObject componentsSeparatedByString: @"_"] count])
|
|
{
|
|
NSLog(@"[%@-%@] invalid argument (%@)",
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd),
|
|
managedObject);
|
|
}
|
|
else
|
|
{
|
|
NSString *event;
|
|
|
|
event = [NSString stringWithFormat: @"unmanage %@", managedObject];
|
|
[_alarmLock lock];
|
|
if (YES == _coalesceOff)
|
|
{
|
|
[_alarmQueue addObject: event];
|
|
}
|
|
else
|
|
{
|
|
NSUInteger index = [_alarmQueue indexOfObject: event];
|
|
|
|
[_alarmQueue addObject: event];
|
|
if (NSNotFound != index)
|
|
{
|
|
if (YES == _debug)
|
|
{
|
|
NSLog(@"Coalesce %@", event);
|
|
}
|
|
[_alarmQueue removeObjectAtIndex: index];
|
|
}
|
|
}
|
|
[_alarmLock unlock];
|
|
}
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation EcAlarmDestination (Private)
|
|
|
|
- (id<EcAlarmDestination>) _connect
|
|
{
|
|
id<EcAlarmDestination> d = nil;
|
|
|
|
[_alarmLock lock];
|
|
NS_DURING
|
|
if (nil == (id)_destination)
|
|
{
|
|
if (nil != _name)
|
|
{
|
|
id proxy;
|
|
|
|
if (nil == _host)
|
|
{
|
|
proxy = [NSConnection
|
|
rootProxyForConnectionWithRegisteredName: _name
|
|
host: _host
|
|
usingNameServer:
|
|
[NSMessagePortNameServer sharedInstance]];
|
|
}
|
|
else
|
|
{
|
|
proxy = [NSConnection
|
|
rootProxyForConnectionWithRegisteredName: _name
|
|
host: _host
|
|
usingNameServer:
|
|
[NSSocketPortNameServer sharedInstance]];
|
|
}
|
|
|
|
if (proxy != nil)
|
|
{
|
|
id connection = [proxy connectionForProxy];
|
|
|
|
[connection setDelegate: self];
|
|
[[NSNotificationCenter defaultCenter]
|
|
addObserver: self
|
|
selector: @selector(_connectionBecameInvalid:)
|
|
name: NSConnectionDidDieNotification
|
|
object: connection];
|
|
[self setDestination: (id<EcAlarmDestination>)proxy];
|
|
}
|
|
}
|
|
}
|
|
d = [(id)_destination retain];
|
|
NS_HANDLER
|
|
NSLog(@"Problem connecting to destination ... %@", localException);
|
|
NS_ENDHANDLER
|
|
[_alarmLock unlock];
|
|
return [(id)d autorelease];
|
|
}
|
|
|
|
- (void) _connectionBecameInvalid: (id)connection
|
|
{
|
|
[self setDestination: nil];
|
|
}
|
|
|
|
- (void) _timeout: (NSTimer*)t
|
|
{
|
|
/* We hold a lock while modifying the internal data structures,
|
|
* but must release it while forwarding things to their eventual
|
|
* destination (in case the forwarding is done in another thread
|
|
* which needs to grab the lock or where a DO message causes an
|
|
* attempt to grab the lock).
|
|
*/
|
|
[_alarmLock lock];
|
|
if (NO == _inTimeout && YES == _isRunning)
|
|
{
|
|
_inTimeout = YES;
|
|
NS_DURING
|
|
{
|
|
if ([_alarmQueue count] > 0)
|
|
{
|
|
NSTimeInterval now = [NSDate timeIntervalSinceReferenceDate];
|
|
NSUInteger index = 0;
|
|
|
|
// Do stuff here
|
|
|
|
while (index < [_alarmQueue count])
|
|
{
|
|
id o = [_alarmQueue objectAtIndex: index];
|
|
|
|
if (NO == [o isKindOfClass: [EcAlarm class]])
|
|
{
|
|
NSString *s = RETAIN([o description]);
|
|
|
|
[_alarmQueue removeObjectAtIndex: index];
|
|
|
|
if (YES == [s hasPrefix: @"domanage "])
|
|
{
|
|
NSString *m = [s substringFromIndex: 9];
|
|
|
|
if (nil == [_managedObjects member: m])
|
|
{
|
|
[self managePut: m];
|
|
[_alarmLock unlock];
|
|
[self domanageFwd: m];
|
|
[_alarmLock lock];
|
|
}
|
|
}
|
|
else if (YES == [s hasPrefix: @"unmanage "])
|
|
{
|
|
NSString *m = [s substringFromIndex: 9];
|
|
|
|
if (nil != [_managedObjects member: m])
|
|
{
|
|
[_alarmLock unlock];
|
|
[self _unmanage: m];
|
|
[self unmanageFwd: m];
|
|
[_alarmLock lock];
|
|
}
|
|
|
|
/* When we unmanage an object, we also
|
|
* implicitly unmanage objects which
|
|
* are components of that object.
|
|
*/
|
|
if (YES == [m hasSuffix: @"_"])
|
|
{
|
|
NSEnumerator *e;
|
|
NSString *c;
|
|
|
|
e = [[_managedObjects allObjects]
|
|
objectEnumerator];
|
|
while (nil != (c = [e nextObject]))
|
|
{
|
|
if (YES == [c hasPrefix: m])
|
|
{
|
|
[_alarmLock unlock];
|
|
[self unmanageFwd: c];
|
|
[_alarmLock lock];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
NSLog(@"ERROR ... unexpected command '%@'", s);
|
|
}
|
|
RELEASE(s);
|
|
}
|
|
else if (NO == [(EcAlarm*)o delayed: now])
|
|
{
|
|
EcAlarm *next = (EcAlarm*)AUTORELEASE(RETAIN(o));
|
|
EcAlarm *prev = [_alarmsActive member: next];
|
|
NSString *m = [next managedObject];
|
|
BOOL shouldForward = NO;
|
|
|
|
[_alarmQueue removeObjectAtIndex: index];
|
|
|
|
if (nil == prev)
|
|
{
|
|
[next setFirstEventDate: [next eventDate]];
|
|
}
|
|
else
|
|
{
|
|
[next setFirstEventDate: [prev firstEventDate]];
|
|
}
|
|
|
|
if ([next perceivedSeverity] == EcAlarmSeverityCleared)
|
|
{
|
|
if (nil != prev)
|
|
{
|
|
/* Alarm previously active ...
|
|
* remove old copy and forward clear.
|
|
*/
|
|
[self activeRemove: prev];
|
|
shouldForward = YES;
|
|
}
|
|
if (nil == [_alarmsCleared member: next])
|
|
{
|
|
/* Alarm not previously cleared ...
|
|
* add to cleared set and forward clear.
|
|
*/
|
|
[self clearsPut: next];
|
|
shouldForward = YES;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* If there was a previous version of the alarm
|
|
* cleared, remove that so it's re-raised.
|
|
*/
|
|
[self clearsRemove: next];
|
|
|
|
/* If the alarm is new or of changed severity,
|
|
* update the records and pass it on.
|
|
*/
|
|
if (nil == prev || [next perceivedSeverity]
|
|
!= [prev perceivedSeverity])
|
|
{
|
|
[self activePut: next];
|
|
shouldForward = YES;
|
|
}
|
|
}
|
|
|
|
if (YES == shouldForward)
|
|
{
|
|
/* If the managed object is not registered,
|
|
* register before sending an alarm for it.
|
|
*/
|
|
if (nil == [_managedObjects member: m])
|
|
{
|
|
[self managePut: m];
|
|
}
|
|
else
|
|
{
|
|
m = nil;
|
|
}
|
|
|
|
[_alarmLock unlock];
|
|
if (nil != m)
|
|
{
|
|
[self domanageFwd: m];
|
|
}
|
|
[self alarmFwd: next];
|
|
[_alarmLock lock];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* This alarm is delayed, skip past to process the
|
|
* next one.
|
|
*/
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
_inTimeout = NO;
|
|
if (YES == _shouldStop)
|
|
{
|
|
_isRunning = NO;
|
|
}
|
|
[_alarmLock unlock];
|
|
}
|
|
NS_HANDLER
|
|
{
|
|
_inTimeout = NO;
|
|
if (YES == _shouldStop)
|
|
{
|
|
_isRunning = NO;
|
|
}
|
|
[_alarmLock unlock];
|
|
NSLog(@"%@ %@", NSStringFromClass([self class]), localException);
|
|
}
|
|
NS_ENDHANDLER
|
|
}
|
|
else
|
|
{
|
|
[_alarmLock unlock];
|
|
}
|
|
}
|
|
|
|
- (void) _unmanage: (NSString*)m
|
|
{
|
|
if (nil != [_managedObjects member: m])
|
|
{
|
|
NSEnumerator *e;
|
|
EcAlarm *a;
|
|
|
|
e = [[_alarmsActive allObjects] objectEnumerator];
|
|
while (nil != (a = [e nextObject]))
|
|
{
|
|
if ([[a managedObject] isEqual: m])
|
|
{
|
|
[self activeRemove: a];
|
|
}
|
|
}
|
|
e = [[_alarmsCleared allObjects] objectEnumerator];
|
|
while (nil != (a = [e nextObject]))
|
|
{
|
|
if ([[a managedObject] isEqual: m])
|
|
{
|
|
[self clearsRemove: a];
|
|
}
|
|
}
|
|
[self manageRemove: m];
|
|
}
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation EcAlarmDestination (Forwarding)
|
|
|
|
- (void) alarmFwd: (EcAlarm*)event
|
|
{
|
|
if (NO == [NSThread isMainThread])
|
|
{
|
|
[self performSelectorOnMainThread: _cmd
|
|
withObject: event
|
|
waitUntilDone: NO];
|
|
return;
|
|
}
|
|
NS_DURING
|
|
[[self _connect] alarm: event];
|
|
if (YES == _debug)
|
|
{
|
|
NSLog(@"%@ %@", NSStringFromSelector(_cmd), event);
|
|
}
|
|
NS_DURING
|
|
[[self backups] makeObjectsPerformSelector: @selector(alarm:)
|
|
withObject: event];
|
|
NS_HANDLER
|
|
[self setBackups: nil];
|
|
NSLog(@"Problem sending alarm to backups ... %@", localException);
|
|
NS_ENDHANDLER
|
|
NS_HANDLER
|
|
[self setDestination: nil];
|
|
NSLog(@"Problem sending alarm to destination ... %@", localException);
|
|
NS_ENDHANDLER
|
|
}
|
|
|
|
- (void) domanageFwd: (NSString*)managedObject
|
|
{
|
|
if (NO == [NSThread isMainThread])
|
|
{
|
|
[self performSelectorOnMainThread: _cmd
|
|
withObject: managedObject
|
|
waitUntilDone: NO];
|
|
return;
|
|
}
|
|
NS_DURING
|
|
[[self _connect] domanage: managedObject];
|
|
if (YES == _debug)
|
|
{
|
|
NSLog(@"%@ %@", NSStringFromSelector(_cmd), managedObject);
|
|
}
|
|
NS_DURING
|
|
[[self backups] makeObjectsPerformSelector: @selector(domanage:)
|
|
withObject: managedObject];
|
|
NS_HANDLER
|
|
[self setBackups: nil];
|
|
NSLog(@"Problem with domanage to backups ... %@", localException);
|
|
NS_ENDHANDLER
|
|
NS_HANDLER
|
|
[self setDestination: nil];
|
|
NSLog(@"Problem with domanage to destination ... %@", localException);
|
|
NS_ENDHANDLER
|
|
}
|
|
|
|
- (void) unmanageFwd: (NSString*)managedObject
|
|
{
|
|
if (NO == [NSThread isMainThread])
|
|
{
|
|
[self performSelectorOnMainThread: _cmd
|
|
withObject: managedObject
|
|
waitUntilDone: NO];
|
|
return;
|
|
}
|
|
NS_DURING
|
|
[[self _connect] unmanage: managedObject];
|
|
if (YES == _debug)
|
|
{
|
|
NSLog(@"%@ %@", NSStringFromSelector(_cmd), managedObject);
|
|
}
|
|
NS_DURING
|
|
[[self backups] makeObjectsPerformSelector: @selector(unmanage:)
|
|
withObject: managedObject];
|
|
NS_HANDLER
|
|
[self setBackups: nil];
|
|
NSLog(@"Problem with unmanage to backups ... %@", localException);
|
|
NS_ENDHANDLER
|
|
NS_HANDLER
|
|
[self setDestination: nil];
|
|
NSLog(@"Problem with unmanage to destination ... %@", localException);
|
|
NS_ENDHANDLER
|
|
}
|
|
|
|
@end
|
|
|