# WatchDog Thread und Listener



## serjoscha (20. Aug 2010)

Hallo zusammen

Ich habe mir für ein aktuelles Programm eine WatchDog Klasse geschrieben, welche in einem Thread für
die Dauer ihrer Laufzeit eine Datei auf Änderungen überwacht.

Ich habe mir damals schonmal sowas geschrieben und habe einen PropertyChangeListener verwendet
um die Controller Klasse mitbekommen zu lassen, dass der WatchDog eine Änderung an der Datei
festgestellt hat, jedoch finde ich das mit dem PropertyChangeListener nicht sonderlich elegant und
versuche jetzt schon mehrere Stunden eine "schöne" Lösung zu finden um den Controller vom
WatchDog Thread aus benachrichtigen zu können.

Kann mir da jemand eine Lösung zu nennen ? 

Ich möchte wirklich nur ungern dass die WatchDog Klasse selber die entsprechenden Aktionen ausführt.
Sie soll wirklich nur bei Änderungen benachrichtigen und nicht auch noch irgendwas machen (außer 
benachrichtigen) wenn was passiert.


Danke!


----------



## tuxedo (20. Aug 2010)

Was hält dich davon ab ein eigenes Listener-Interface zu definieren? Der Watchdog-Thread kann dann Listener-Implementierungen entgegen nehmen und diese entsprechend "benachrichtigen".


----------



## serjoscha (20. Aug 2010)

hm, um ganze ehrlich zu sein weiß ich nicht wie das funktioniert. Mir hat sich auch immernochnicht
die Funktion von Interfaces eröffnet, da Interfaces ja garkeine ausprogrammierte Funktionalität haben
sondern nur beschreiben wie eine Klasse die davon erbt auszusehen hat.

Das hieße ich habe:

Controller Klasse
WatchDog Klasse
WatchDogEventListener

[..]

Controller Klasse implements WatchDogEventListener
Watchdog implements/extends (?!) WatchDogEventListener?

Hmmm, "problem" ist hier dass die WatchDog Klasse schon Thread extendet, wobei sich das ja zur Not
sogar noch mit implements runnable lösen ließe

hmm...


----------



## tuxedo (20. Aug 2010)

Der Watchdog muss nix implementieren.

Er muss nur Methoden haben wie:


```
addListener(WatchdogEventListener listener) { ... }
removeListener(WatchdogEventListener listener) { ... }
```

Das Listener interface könnte so aussehen:

```
public interface WatchdogEventListener {

public void eventOccured(File f);

}
```

Die "listener" die du da bekommst, steckst du in eine Liste. Tritt ein Event auf, so nimmst du die Liste her, holst dir jeden einzelnen Listeneintrag (also den Listener) her, und rufst da drauf 


```
listener.eventOccured(theFileThatHasBeenChanged);
```

auf.

Dein Controller implementiert dieses Interface. D.h. du musst die Methode "eventOccured" dort implementieren.

Und um sich für ein Event anzumelden, rufst du dann


```
myWatchdog.addListener(myController);
```

auf. Fertig.


----------



## serjoscha (20. Aug 2010)

Danke für die tolle darlegung!

Folgendes versteh ich aber nicht:


> Die "listener" die du da bekommst, steckst du in eine Liste. Tritt ein Event auf, so nimmst du die Liste her, holst dir jeden einzelnen Listeneintrag (also den Listener) her, und rufst da drauf
> 
> 
> ```
> ...



Ich habe das grade mal versucht umzusetzen: irgendwie wir nun direkt beim initialisieren des Programms
die EventOccured methode aufgerufen. Wie kann ich definieren, was dieses event triggert?! Das geht mir
nicht in den Sinn.

Ich habe praktisch jetzt gemacht was du mir beschrieben hast:

Meine WatchDog Klasse hat nun eine add-Methode um über den Controller den Listener hinzufügen zu können,
ich habe ein Interface mit dem Occured Event und ich habe meinen Controller, welcher das Interface
implementiert und im Moment einfach nur eine kleine Nachricht ausgibt...

Bitte um Aufklärung meiner Verwirrung ???:L

Danke!


----------



## tuxedo (20. Aug 2010)

Die addListener() Methode fügt den Listener nur in die Liste mit Listenern hinzu. Da wird noch kein "eventOccured" aufgerufen.

So. Dein Watchdog bekommt ja irgendwie mit wenn sich die zu überwachende Datei geändert hat. Hat er so eine Situation entdeckt, dann iteriert der Watchdog über die Liste mit listenern, und ruft auf jedem einzelnen Listener in der Liste "eventOccured" auf. 

Ergo: Deine aktuelle kleine testnachricht wird nur dann ausgegeben, wenn sich die zu überwachende Datei geändert hat.

- Alex


----------



## serjoscha (20. Aug 2010)

wunderbar, es hat funktioniert!!

ganz großes danke!!!

super gute Erklärung!!

Eine kleine Sache verstehe ich noch nicht ganz, wieso brauche ich eine Liste von Listenern,
wenn ich nur einen einzelnen Listener habe? Lässt sich das der Verständlichkeit des Quellcodes
halbes auch anders lösen? Also ohne Liste?

Ich habe dafür nun eine Array Liste vom Typen Meines ListenerInterfaces genommen, ist das so auch
gängig / sauber?

Danke!!!!!!!


----------



## tuxedo (20. Aug 2010)

Naja, i.d.R. gibts mehrere die sich für so ein Event interessieren könnten.

Wenn du ausschließen kannst dass sich mehrere dafür interessieren, dann kannst du dir die Liste sparen.

Bei verwendung der Liste musst du halt auch drauf achten, dass du das hinzufügen und entfernen und das "drüber iterieren" synchronisierst. Ohne Liste sparst du dir das natürlich ebenfalls.

Ein "Array" benutze ich hier eigentlich nicht. Denn ich weiß ja nicht wieviele Listener kommen. Umkopieren ist auch unschön. Verwende eigentlich ausschließlich so was:


```
List<MyListenerInterface> listeners = new ArrayList<MyListenerInterface>();
```

Das ist quasi das "bessere Array" in dem Fall.


----------



## serjoscha (20. Aug 2010)

super! vielen Dank, Problem 100% gelöst


----------



## diggaa1984 (20. Aug 2010)

nun mal die Frage .. was ist der Unterschied zur Nutzung vom PropertychangeSupport .. auch dazu musst du listener anmelden, allerdings sparst du dir das selbstständige benachrichtigen der listener, und du musst keine Liste extra verwalten, das macht der Supporter für dich.

das einzige was mich stören würde wäre, diesen Supporter zweckzuentfremden, wenn man keine Properties im eigentlichen Sinne hätte ... aber Listener-Geschichten kann man damit doch einfach umsetzen


----------



## serjoscha (21. Aug 2010)

naja wie du schon sagtest: das zweckentfremden stört mich. Außerdem die Tatsache, dass ich 
mir extra dafür eine Variable hätte anlegen müssen. Da ist es so doch wirklich schon ne Nummer sauberer.
Und ganz davon ab: Listener selber schreiben zu können ist wohl eine sache die recht wichtig ist.


----------

