Da das Plugin für CronJobs in NetBeans relativ schnell gewachsen ist, sammele ich hier mal ein paar Feature und gebe Tipps, wie man das Tool einsetzen kann.
Die grundsätzliche Überlegung ist natürlich: Braucht man sowas?
Natürlich gibt es 100 andere Lösungswege, wenn man zeit- und aktionsgesteuert Ant-Targets auslösen möchte. Aber es macht Sinn innerhalb der IDE von NetBeans, direkt das Build-System ansprechen zu können. Und auch die Aktionen Projekt öffnen, Projekt schließen, IDE starten und IDE beenden gehören einfach zur IDE. Darum das Plugin.
Warum Ant Targets?
Wenn man bei fast allen Projekt Typen in NetBeans Ant basierte Build Systeme hat (ausgenommen mal C/C++ und PHP), macht es schon Sinn auf dieser Ebene das (in der IDE) frei verfügbare "Scripting"-Framework zu verwenden. Allerdings möchte ich für die Zukunft nicht ausschließen, andere Aktionen (als Ant-Targets) zu starten. Deswegen muss man schon jetzt immer bei den Aktionsdefinitionen das Schlüsselwort "ANT" verwenden.
Und auch bei Nicht-Ant-Projekte kann man natürlich eigene Ant Scripte angeben und ausführen lassen.
Warum die CronJob Syntax?
Die Syntax ist zwar auf den ersten Blick nicht sofort verständlich aber universell. Man bekommt in allen Ecken des Internets Doku und Hilfestellung. Außerdem erschien mir die Cron4j Implementation sehr sauber und stabil. Schlussendlich kam ich erstmal um ein eigenes Scheduler Framework plus GUI drumherum. Damit konnte die erste Version innerhalb von drei Mannstunden zum laufen gebracht werden. Ich will aber nicht ausschließen, dass ein Assistent zum Einplanen von CronJobs folgen wird.
Man darf aber auch den Nachteil nicht vergessen. Exakt alle (möglichen) Zeitpunkte für einen Job kann man nicht definieren. Auch sind CronJobs wiederkehrend. Einen Job für nur ein Datum kann man nicht einrichten (der längste Wiederholungszeitraum ist jährlich). Wenn gewünscht könnte man die Syntax erweitern, um den CronJob nach erster Ausführung zu deaktivieren...
Außerdem sind CronJobs exakt an Minuten ausgerichtet. Deswegen kann man keine CronJobs 10 Sekunden nach IDE Start ausführen (ich erzeuge nämlich aus der relativen Angabe von z.B. 3m einen CronJob zu einem Zeitpunkt exakt 3 Minuten nach IDE Start). Es wäre aber möglich diese Einschränkung in Zukunft fallen zu lassen.
Unterschiede der Job-Einplanungen
Globale Jobs
Man kann Global (in den Optionen der NetBeans IDE) Jobs einplanen. Einmal für wiederkehrende Zeiten und außerdem für den NetBeans Start und für das NetBeans Beenden. Jobs für den NetBeans Start müssen mit einer Duration-Angabe versehen werden (z.B 2m für zwei Minuten nach IDE Start oder 1h für eine Stunde). Jobs für das Beenden der IDE werden unmittelbar ausgeführt (eine Angabe einer Zeit ist da nicht möglich). Die Jobs beim Beenden verhindern natürlich erstmal den Shutdown der IDE. Es erscheint der bekannte Progress Dialog, dass noch Tasks am laufen sind.
Projektbezogene Jobs
Die projektbezogenen Jobs beziehen sich direkt auf das Projekt, dem sie zugeordnet sind. Dafür erhalten fast alle Projekttypen (JavaSe, -ME, EE, PHP, Web, Groovy, NetBeans-Modules, usw) einen neuen Anzeige-Knoten in der Projektansicht. Unter dieser CronJob Konfiguration verbergen sich zur Zeit drei Punkte zum konfigurieren von Jobs. Projekt-CronJobs, Beim Öffnen ausführen und Beim Schließen ausführen. Bei all diesen Jobs wird das Ant-Script aus dem Projekt ermittelt (also gibt man es bei der Definition nicht mit an). "Beim Öffnen" bedeutet nicht nur das Öffnen eines Projektes während der Arbeit mit der IDE, sondern auch bei IDE Start (wenn das Projekt schon vormals geöffnet war). "Beim Schließen" triggert auch beim Beenden der IDE.
Nicht immer will man (oder kann man, siehe PHP-Projekte) das Script des Projektes verwenden. In dem Konfigurationsdialog kann man dann ein individuelles Script angeben.
Erste Schritte
Ein Testtarget
Als ein sehr nützliches Ant Target hat sich dieses Beispiel bewährt:
<target name="scheduletest">
<tstamp>
<format property="start" pattern="yyyy MMMM dd HH:mm:ss" locale="en"/>
</tstamp>
<echo message="Target started at ${start}"/>
<sleep seconds="15"/>
<echo message="Target finished. Thank you for the audience."/>
</target>
Es zeigt die Startzeit an, wartet 15 Sekunden und verabschiedet sich höflich.
Wann immer man am Anfang mit dem Plugin rumspielt sollte man diese Target parat haben und es in die eigenen Ant-Scripte einfügen. Ein komplettes Ant-Script (jetzt ohne Target) sollte so aussehen:
<?xml version="1.0" encoding="UTF-8"?>
<project name="somename" basedir=".">
</project>
Das Target kann man zwischen <project> (hier) </project> einfügen. Gerade für Globale Jobs muss man ein eigenes Script anlegen.
Ein globaler CronJob
Das obige Script einfach mal (komplett) in das Home-Verzeichnis in den Unterordner jobs ablegen. Das Script als text.xml benennen.
Nun in der IDE Extras->Optionen (Tools->Options) öffnen. Unter Verschiedenes (Miscellaneous) den Tab "CronJob" auswählen. Unter Globale CronJobs nun diese Zeile einfügen:
*/2 * * * * ANT "{user.home}/jobs/test.xml" scheduletest
Die ersten fünf Angaben der Zeile sind echte CronJob-Syntax und bedeuten, dass der nachfolgende Befehl alle 2 Minuten ausgeführt werden soll (*/2 bedeutet: Nimm die Minuten der aktuellen Zeit, führe die Operation "aktuelle_minute modular 2" aus und prüfe das Ergebnis auf 0, dann führe den Befehl aus - also */5 würde alle 5 Minuten ausgeführt. */30 würde um :00 und :30, also jede halbe Stunde, und nun die Preisfrage: */31?).
Die Angabe ANT ist einfach ein eigenes Schlüsselwort (im Moment das einzige). Für globale Jobs muss (nach ANT) immer ein individuelles Script angegeben werden. Am besten in Anführungsstriche, besonders dann, wenn man Properties mit angibt. In diesem Fall wäre das {user.home} und wird mit dem Home-Pfad des Betriebsystems-Anwenders substituiert. Und da so ein Pfad Leerzeichen enthalten kann, brauchen wir die Anführungsstriche...
Als Properties sind alle System.properties der Java VM möglich (aber nicht unbedingt sinnvoll). Der letzte Parameter ist das Target in dem ANT Script. Man darf auch mehrere mit Komma getrennt (aber ohne Leerzeichen) angeben. Die werden dann in der vorgegebenen Reihenfolge abgearbeitet (z.B. clean,compile).
Damit das obige Beispiel nun läuft, muss man die Jobs generell aktivieren. Entweder auf die Uhr (obere rechte Ecke) klicken (so dass diese farbig wird), oder die Checkbox unten links anhaken.
Den kompletten Optionsdialog mit [Ok] bestätigen. Dann ist alles scharf geschaltet.
Sofort sollte sich das Ausgabe Fenster öffnen und folgendes anzeigen:
Try to start scheduler
Initializing 1 cronjob tasks for the scheduler...
Scheduler started.
Das ist das CronJob Fenster (ein extra Ausgabe Fenster nur für Job-Einplanungen)
Nach zwei Minuten (+ x Sekunden < 60) erscheint ein weiteres Fenster (Titel ist test(scheduletest)) mit folgender Ausgabe:
scheduletest:
Target started at 2009 August 06 10:36:00
Target finished. Thank you for the audience.
ERSTELLEN ERFOLGREICH (Gesamtzeit: 0 Minuten 15 Sekunden)
Nun exakte zwei Minuten später die Aktualisierung:
scheduletest:
Target started at 2009 August 06 10:38:00
Target finished. Thank you for the audience.
ERSTELLEN ERFOLGREICH (Gesamtzeit: 0 Minuten 15 Sekunden)
Das war es auch schon. Der Test für die ersten Schritte war erfolgreich. Am besten wird der CronJob nun wieder in den Optionen deaktiviert...
Ein Job beim IDE Start
Wenn man das selbe Script auch beim Hochfahren der IDE starten will, muss man dieses in den Optionen im zweiten Eingabefeld eintragen. Allerdings verlassen wir damit die reguläre CronJob-Syntax. Die erste Angabe ist ausschließlich eine Duration Angabe:
2m ANT "{user.home}/jobs/test.xml" scheduletest
Damit uns der erste Test nicht reinpfuscht, kommentieren wir im darüber liegenden Feld (für die CronJobs) die Testzeile mit einem # aus.
Nicht die angehakte Checkbox vergessen, mit [Ok] bestätigen und mal in das CronJob Ausgabefenster schauen. Folgende Zeilen sind hinzugekommen:
Starting ANT {user.home}/jobs/test.xml scheduletest
Starting succeeded ANT {user.home}/jobs/test.xml scheduletest
Starting ANT {user.home}/jobs/test.xml scheduletest
Starting succeeded ANT {user.home}/jobs/test.xml scheduletest
Starting ANT {user.home}/jobs/test.xml scheduletest
Starting succeeded ANT {user.home}/jobs/test.xml scheduletest
Stopping tasks for the schedulerScheduler stopped.
Try to start scheduler
Die Starting-Zeilen sind noch vom letzten Test. Die letzte Zeile verwundert erst. Es fehlt eine Angabe von neuen Taskeinplanungen. Aber tatsächlich ist das nicht falsch. Denn für den Neustart eingerichtete Jobs werden erst bei dem Start der IDE aktiviert. Im Moment läuft die IDE ja schon eine Weile.
Also die IDE beenden und neu starten.
...
Wieder da? Gut.
Unmittelbar sieht man nun im CronJob-Ausgabefenster dies hier:
Try to start scheduler
Initializing 1 startup tasks for the scheduler...
Scheduler started.
Na also, ein Startup-Task wurde eingerichtet. Und zwei Minuten später die bekannte Testausgabe:
scheduletest:
Target started at 2009 August 06 10:51:00
Target finished. Thank you for the audience.
ERSTELLEN ERFOLGREICH (Gesamtzeit: 0 Minuten 15 Sekunden)
Damit funktionieren auch die Startup-Jobs.
Ein Job beim IDE beenden
Jobs, die beim Beenden aktiviert werden, benötigen gar keine Zeitangabe mehr. Wer will schon länger auf den Feierabend warten, als es nötig ist?
Wieder in den CronJob-Optionen kommt in das letzte Feld diese Zeile:
ANT "{user.home}/jobs/test.xml" scheduletest
Nun mal die IDE schließen. Unmittelbar erscheint ein Dialog "IDE beenden", in dem sind zwei Prozesse aufgelistet:
Prozess - Run 1 shutdown task(s)
test (scheduletest)
[IDE beenden] [Abbrechen]
Wenn man nun geduldig wartet ist die IDE 15 Sekunden später weg vom Fenster. Ungeduldigerweise könnte man auf [IDE beenden] klicken. Der aktuelle Ant-Task (und alle weiteren) würden abgebrochen werden. Mit [Abbrechen] beendet sich die IDE nicht. Aber es würden trotzdem alle Shutdown-Jobs weiter eingeplant laufen (das kann zu dem Zeitpunkt nicht mehr verhindert werden)!
Soweit erstmal die wichtigsten Tipps zum neuen CronJob-Plugin. In einem zweiten Teil gehe ich auf die projektbezogenen Ant Jobs ein.
*) Zur Preisfrage: Nur einmal jede Stunde in der 31. Minute, nicht um :31 und :01! Wenn man zur ersten und 31. Minute den Job haben will, muss man den ersten Parameter so schreiben 1,31 (ohne Leerzeichen)