Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
Ich möchte gerne eine Timer Bean machen, die ab dem Deployment alle x Minuten was tut.
Jetzt finde ich im Netz (und in meinem schlauen Buch) nur Beispiele, wo der Timer durch einen Client gestartet wird.
Wie lässt sich das denn bewerkstelligen, dass der Timer direkt beim Deployment losgeht?
In der Regel gibt es vorher schon AS spezifische Implementierungen.. z.B. die heißen gerne was mit "Scheduler Service" oder so... oder "Timer Service" ... eine Implementierung z.B. ist von Quartz, die findet im JBoss Verwendung.
Es wird mehrfach aufgerufen, weil das einem Scheduler entspricht und weil du es so haben wolltest.
Wenn du glaubst, dass das mehrfach aufgerufen wird, weil du für einen Zeitpunkt mehrere Logeinträgt hast, dann hast du dein Logging falsch konfiguriert.
Mit mehrfach meine ich natürlich nicht jede Minute Sondern jede Minute (wie eingestellt) dreifach direkt nacheinander.
Wenn du glaubst, dass das mehrfach aufgerufen wird, weil du für einen Zeitpunkt mehrere Logeinträgt hast, dann hast du dein Logging falsch konfiguriert.
Hmm... Wenn ich debugge und an Zeile 9 nen Breakpoint setze, komme ich pro Durchlauf (Sprich jede Minute) dreimal an die Stelle. Ich glaube also nicht, dass es an falsch konfiguriertem Logging liegt...
In den ersten Versuchen hatte ich kein persistent=false drin. Könnten das noch Fragmente davon sein? Bin noch nicht so ganz schlau geworden, wie man einen einmal als persistent=true definierten Scheduler wieder los wird...
Wenn ich den jboss runterfahre und z.B. nach zehn Minuten wieder hochfahre, bekomme ich diese Ausgaben 10 mal sprich der Timer wird wiederholt für jedes mal wo er beim runtergefahrenen Server versäumt wurde. Hatte gedacht das würde durch persistent=false verhindert.
Und wie kriegt man die wieder weg?
clearTimers() in der MBean nützt leider nichts.
Lösche ich die vorher mit @Schedule annotierte Methode, gibts ne Exception beim Starten, dass die Methode nicht gefunden werden kann.
Nur wenn ich die komplette Klasse lösche kommt keine Exception mehr. Sobald ich wieder eine Klasse habe, die gleich heißt, kommt sie wieder.
(Aber das kann ja nicht die Lösung sein)...
Ich suche jetzt schon seit Stunden bei Google aber die Keywords "Timer Remove Persistent EJB" geben alle möglichen Ergebnisse nur nicht die, die helfen.
Ich benötige auch einen Timer, ABER ich muss in der Funktion auf Files zugreifen, da laut Spezifikation kein file.io in einer EJB erlaubt ist, habe ich dies in meiner Web-Bean (Managed Bean) gemacht (Datenbankzugriff etc. läuft über eine EJB).
Dort ist nun eine Funktion, welche Prozeduren vom SQL Server lädt, in Files schreibt und zipt und gewissen Leuten zu mailed, funktioniert alles wunderbar (ist als Backup gedacht).
Aber wie schaffe ich es nun, dass diese Funktion z.B. jeden Freitag (oder alle x Stunden) ausgeführt wird?
java.io ist meines Wissens in der Spec nicht erlaubt, um dem Container Resource-Management (gleichzeitiger Aufruf, max. Anzahl von Channels, Transaktionen, ...) zu ermöglichen. Wenn das in einem sehr kontrollierten Rahmen passiert (wo du z.B. genau weißt, dass die Methode nur einmal vom Scheduler aufgerufen werden kann), würde ich mich jetzt fast aus dem Fenster lehnen und sagen, dass du auch (wenn du keinen Resource Adapter schreiben willst) die java.io Zugriffe benutzen kannst. Musst halt so stabil programmieren dass in allen Fällen (auch in allen Fehlerfällen) die Streams geschlossen u. Altdaten aufgeräumt werden.
Die Web-Bean aufrufen... Schwierig.. Wenn du von hinten durch die Brust willst, könnte man drüber nachdenken, per EJB Timer die entsprechende HTTP-URL aufzurufen wodurch die Methode dieser Web-Bean ausgelöst wird...
Aber wie gesagt (die alten Hasen dürfen mich gerne verbessern) würde ich jetzt sagen - am Ende schenkts sich nichts ob per Web-Bean oder EJB die java.io Aufrufe getätigt werden. Gibt in beiden Fällen kein Resource-Management.
Danke für die Antwort.
Dummerweise habe ich extra alles umgeschrieben, so dass in der EJB kein IO-Zugriffe entstehen.
Wäre nun aufwendig erneut alles umzuschreiben.
Die Lösung
Java:
import java.util.Timer;
public class TimerTaskDemo {
public void go() {
Timer timer = new Timer();
timer.schedule(new WebClass(), 1000, 10000);
}
}
Und in der Webclass:
Java:
@Override
public void run() {
System.out.println("Los gehts!!");
generateBackupMail(); // verschickt die Emails
}
führt logischerweise zu diesem Fehler:
Code:
16:20:51,234 INFO [STDOUT] Los gehts!!
16:20:51,234 ERROR [STDERR] Exception in thread "Timer-1"
16:20:51,234 ERROR [STDERR] java.lang.NullPointerException
16:20:51,234 ERROR [STDERR] at de.procBackup.webapp.WebClass.getallDataBases(WebClass.java:162)
16:20:51,234 ERROR [STDERR] at de.procBackup.webapp.WebClass.getallProcedures(WebClass.java:169)
16:20:51,234 ERROR [STDERR] at de.procBackup.webapp.WebClass.startBackup(WebClass.java:45)
16:20:51,234 ERROR [STDERR] at de.procBackup.webapp.WebClass.generateBackupMail(WebClass.java:81)
16:20:51,234 ERROR [STDERR] at de.procBackup.webapp.WebClass.run(WebClass.java:300)
16:20:51,250 ERROR [STDERR] at java.util.TimerThread.mainLoop(Unknown Source)
16:20:51,250 ERROR [STDERR] at java.util.TimerThread.run(Unknown Source)
Da man ja nicht einfach eine neue Instanz anlegen kann, wie man die bestehende übergehen könnte, bin ich leider auch überfragt.
Also ich erzeuge erstmal eine TimerTask Klasse, z.B. so :
Java:
import java.util.Timer;
public class TimerTaskDemo {
public void go(WebClass beanReference) {
Timer timer = new Timer();
timer.schedule(beanReference, 1000, 10800000);
}
}
Wie man sehen kann, übergebe ich dieser eine beanReference, dies wäre die aktuelle Instanz der "WebKlasse", von der man ja keine neue Instanz erzeugen kann. (siehe obigen Beitrag).
In meiner Webclasse habe ich für den Timer die benötigte Funktion run() eingebaut:
Java:
@Override
public void run() {
System.out.println("Los gehts!!");
generateBackupMail(); // verschickt die Emails
}
Diese wird ausgeführt, sobald der Timer bzw die TimerTaskDemo Klasse den jeweiligen Funktionsaufruf "bekommt".
Nun kommt der "Trick"
Eine Funktion, die einmal bei Start der Applikation oder durch drücken eines CommandButtons ausgeführt wird, übergibt die aktuelle WebKlassen-Instanz an den Timer.
Dies macht man über ExternalContext usw:
Java:
public void letsgo() {
System.out.println("Starte Timer");
ExternalContext ec = FacesContext.getCurrentInstance().getExternalContext();
HttpSession session = (HttpSession) ec.getSession(true);
WebClass beanReference = (WebClass) session.getAttribute("webClass");
TimerTaskDemo td = new TimerTaskDemo();
// starte den Timer, welcher in der Webklasse die Funktion run() ausführt.
td.go(beanReference);
}
Eure Webklasse muss die TimerTask-Klasse vererbt bekommen.
Java:
public class WebClass extends TimerTask
webClass (session.getAttribute("webClass") ist der Name der managed bean in der face-config.xml .
So funktioniert der Java Timer auch wunderbar mit Webclassen bzw. managed beans.