A change watcher, how to make?

Weyert's Avatar

Weyert

10 May, 2011 10:31 AM

I am currently working on cleaning up some existing code and give it some Robotlegs love. Only I am curious what the best approach is to implement it. The problem is that I need to detect to changes to files on the computer every n seconds and then inform the responsible classes that this file has changed. For example, a file which contains whether the device is logged in or not into the corporate network plus the ip address etc.

My current idea is to make three service classes with the following functionality:

  • Timer service which just dispatches TICK events every n seconds (TimerEvent(TICK, 'dataChecker') Each time this event gets dispatched the appropriate command
  • After each TICK the method checkForChanges gets called in the FileWatcherService if a file has changed content this will dispatch an event with the name of the changed file FileItemChanged(CHANGED,'systemState.xml') after this event a command gets triggered which will call
  • The process(filename) method which is responsible actually processing the data in the changed file systemState.xml which finally will cause the model to be changed.

Now my question is this is a good approach or over-engineered? Could it be simplified when I am using signals instead of events? Also if I am using events can I also somehow set a contract CommandA only should be called when event.type=TICK and event.timerName='dateChecker'?

Thanks for your insight!

  1. 1 Posted by Jos Yule on 10 May, 2011 02:18 PM

    Jos Yule's Avatar

    My only thing would be to wire the TICK event to a CheckForChanges Command. The command would have the FileWatcherService injected into it, and then call the appropriate method on that. Continue on as you had in your description - the Service firing another event, which triggers another Command to handle the changed file.

    Peace
    jos

  2. Support Staff 2 Posted by Stray on 11 May, 2011 08:19 AM

    Stray's Avatar

    I'd bind the command to a further customised event instead of TimerEvent.TICK and then you can control the 'only when timerName = x' part yourself inside the service, or a service wrapper.

    Stray

  3. 3 Posted by Weyert on 11 May, 2011 10:22 AM

    Weyert's Avatar

    Thanks for the suggestions. I am currently worked on it and seems to be working nicely. I am only not sure what you mean Stray.

    Currently I am having code like in my CheckForChanges command:

        [Inject]
        public var payload: TimerTickEvent;
    
        [Inject]
        public var fileWatcherService: IFileWatcherService;
    
        /**
         * @inheritDoc
         */
        override public function execute(): void {
            if ( payload.name != 'filewatcher' ) return;
            trace(this, 'check for changes', payload);
            fileWatcherService.checkForChanges();
        }
    

    Only this gets a big long when you have multiple tickets going on via the TimerService-class.

  4. Support Staff 4 Posted by Stray on 11 May, 2011 10:44 AM

    Stray's Avatar

    That's what I mean - rather than having them all bound to one 'tick' event, wouldn't you be better having the timer service wrapped in a timer gateway that handles this logic by dispatching specific events?

    So - imagine we have a TimerGateway - this TimerGateway has injected an instance of TimerService. TimerService no longer extends Actor, and instead of dispatching its events to the framework, it just dispatches them locally.

    We have a dictionary of payload names to specific events - let's say we also get rid of those flimsy magic strings and put those as constants in an object called TimerPayloadReference.

    So - we map the payload references to specific events, and so TimerGateway looks like:

    public class TimerGateway extends Actor implements ITimerGateway
    {
        [Inject]
        public var timerService:ITimerService;
    
        protected var _timerPayloadEventLookup:Dictionary;
    
        public function TimerGateway()
        {
            buildReference();
        }                                                 
    
        public function startMonitoring():void
        {
            eventMap.mapListener(timerService, TimerTickEvent.TICK, processTimerTick);
        }
    
        protected function buildReference():void
        {
            _timerPayloadEventLookup = new Dictionary();
            _timerPayloadEventLookup[TimerPayloadReference.FILE_WATCHER] =
                     TimedActionEvent.FILE_WATCHER_TICK;
            _timerPayloadEventLookup[TimerPayloadReference.SOMETHING] = 
                    TimedActionEvent.SOMETHING_TICK;
        }                                                                                                         
    
        protected function processTimerTick(e:TimerTickEvent):void
        {
            var specificEventType:String = _timerPayloadEventLookup[e.name];
            dispatch( new TimedActionEvent(specificEventType));
        } 
    
    }
    

    Now all our control flow logic is nicely captured in this bubble. In your context (or bootstrap command) you can bind specific commands to these specific TimedActionEvent events.

    You would also need to get timerService to use the TimerPayloadReference constants rather than just plain-old strings.

    Does that make sense?

    Stray

  5. 5 Posted by Weyert on 11 May, 2011 11:34 AM

    Weyert's Avatar

    Love it! Thanks.

  6. 6 Posted by Weyert on 11 May, 2011 12:38 PM

    Weyert's Avatar

    Thanks, this seems to be working really nicely.
    I have implemented a similar approach for dealing with the actual changed files event so that it will call ProcessXXXFileCommand when that file is updated.

    In this command you just do fileWatcherService.getContents( FileWatcherPayloadReference.SYSTEM_STATE ). I am not sure if I should send the actual contents along or not.

  7. 7 Posted by Weyert on 11 May, 2011 01:12 PM

    Weyert's Avatar

    I have decided to send a VO along with the file name and its contents:

            var itemContents: * = _cache[ name ];
            var cacheItem: CacheItemVO = new CacheItemVO(file, itemContents);
            dispatchEvent( new CacheItemEvent( CacheItemEvent.CHANGED, name, cacheItem ) );
    
  8. 8 Posted by Stray on 11 May, 2011 01:46 PM

    Stray's Avatar

    Much better :)

  9. Stray closed this discussion on 11 May, 2011 03:49 PM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac