Timer Bean

peez

Bekanntes Mitglied
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?
 

FArt

Top Contributor
Ab EJB 3.1 gibt es da was fertiges: New Features in EJB 3.1 - Part 2

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.
 

peez

Bekanntes Mitglied
Super, Danke! Ist ja ganz einfach :)

Warum wird das jetzt immer mehrfach aufgerufen?

Hier mein erster Versuch:
Java:
@Stateless
public class DataInterfaceHousekeeperTimerBean {

	private final static Logger log = LoggerFactory.getLogger( DataInterfaceHousekeeperTimerBean.class );

	@Schedule( hour = "*", minute = "*", second = "1", persistent = false )
	private void doHousekeeping() {

		log.info( "********************************** HOUSEKEEPER *************************" );		
	}
}
 

FArt

Top Contributor
Super, Danke! Ist ja ganz einfach :)

Warum wird das jetzt immer mehrfach aufgerufen?

Hier mein erster Versuch:
Java:
@Stateless
public class DataInterfaceHousekeeperTimerBean {

	private final static Logger log = LoggerFactory.getLogger( DataInterfaceHousekeeperTimerBean.class );

	@Schedule( hour = "*", minute = "*", second = "1", persistent = false )
	private void doHousekeeping() {

		log.info( "********************************** HOUSEKEEPER *************************" );		
	}
}

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.
 

peez

Bekanntes Mitglied
Es wird mehrfach aufgerufen, weil das einem Scheduler entspricht und weil du es so haben wolltest.
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.
 

peez

Bekanntes Mitglied
Wenn bereits Tasks mit persisten=true liefen, dann kommen die natürlich nach einem Serverstart wieder zum Zuge.
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.
 

peez

Bekanntes Mitglied
Keine Idee mehr?
Habe mittlerweile das Scheduler-Zeugs aufgegeben und rausbekommen wie ich nen normalen Timer automatisch erstellen kann:

Java:
@Singleton
@Startup
public class DataInterfaceTimerBean implements TimedObject {
	public final static String TIMER_NAME = "TestTimer";
	private final static Logger log = LoggerFactory.getLogger( DataInterfaceTimerBean.class );

	@Resource
	TimerService timerService;

	@Override
	public void ejbTimeout( Timer timer ) {
		log.info( "***************** ejbTimeout() *************" );
	}

	@PostConstruct
	public void installTimer() {
		log.info( "##Creating Timer for DataInterface##" );
		Timer timer = timerService.createTimer( 10000, 10000, TIMER_NAME );
	}
}
 
R

RaiausderDose

Gast
Hallo,

Sorry, dass ich den alten Thread ausgrabe...

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?

https://rz-static.uni-hohenheim.de/...el_09_012.htm#Rxx365java09012040002D91F04A100

Diese Variante kann ich wohl kaum nutzen, da dies ja eine run()-Funktion benötigt, die ich in der Managed Bean ja nicht zur Verfügung habe.

Irgendwelche Ideen / Ratschläge?

Vielen Dank für die Hilfe!
 

peez

Bekanntes Mitglied
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.
 
R

RaiausderDose

Gast
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.
 
R

RaiausderDose

Gast
Ich hab eine Lösung gefunden, hurra :)

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.

Vielen Dank nochmal.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
I EJB 3.1 Timer @Schedule wird nicht ausgeführt?! Application Tier 2
V javax.ejb.Timer schlägt beim Start fehl Application Tier 4
K Parallele Timer Application Tier 13
K EJB Session Bean Application Tier 2
V EJB: Eine Remote Bean soll eine Local Bean ansprechen und dem Client übergeben Application Tier 2
B Spring context:component-scan: No such bean definition Application Tier 2
M EJB Stateless Bean ist immer null im REST WebService Application Tier 3
T ERROR: Bean name must not be empty! Application Tier 3
B Message-Driven Bean reagiert nicht Application Tier 3
A Stateful Session Bean will nicht "stateful" sein Application Tier 18
S Statefull Session Bean für UserLogin Application Tier 4
O javax.naming.NoInitialContextException - Remote Session Bean Application Tier 2
O Anfängerproblem mit Session Bean Application Tier 3
N Kummunikation Application Client - Session Bean Application Tier 8
J Session-Bean aufräumen bei Timeout bei Seam/EJB Application Tier 6
F Time-out Zeit für Session-Bean Application Tier 4
F Property-Datei in Stateless-Bean laden Application Tier 8
M Entity Bean wird nicht in stateless Session Bean injeziert Application Tier 3
V Stateless-Bean soll Info aus Stateful-Bean holen Application Tier 3
byte [Spring] Referenced Bean not found Application Tier 2

Ähnliche Java Themen

Neue Themen


Oben