Hallo zusammen,
wie der Titel bereits sagt, bin ich dabei, eine Komponente für Domino-Thread-Pooling zu entwickeln.
Was bietet die Komponente:- NotesThreadPooling über Concurrent-Framework
- Vorhalten von Session-Objekten für jeden eintreffenden task
- 3 Zugriffsmodi (IIOP, http, local)
- Recycle der Session nach abgearbeitetem Task
- Konfiguration über property-file
- Logging über SLF4J -> Log4J (leicht zu ändern)
- Tasks können Runnable oder Callable sein
- Junit-Tests (siehe oben)
- Ant-Tasks zum Bauen der komponent.jar
- viel debugging-output um das Verhalten von Concurrent nachzuvollziehen
- ShowCase mit zufälliger ABM :-)
Was bietet die Komponente noch nicht:- Vorhalten weiterer Objekte (db, view, etc.)
- Verarbeitung der Future-Objekte falls Callables verwendet werden
- Exception-Handling (da hoffe ich auf Feedback von euch, um gleich den richtigen Weg einzuschlagen :-)
Warum diese Komponente?- schnelles Abarbeiten synchroner Requests
- schnellen Zugriff für hochfrequentierte Anwendungen
Voraussetzungen- mind. Java 5 wegen Concurrent-Framework
- Zugriff auf einen Domino-Server oder -Client (je nach Zugriffsart)
Ich habe aus der Komponente ein Archiv gebaut und eine readme.pdf als Leitfaden zum Einrichten in Eclipse erstellt.
Die Konfiguration der Komponente erfolgt über das property-file "src/java/domino.properties
Die möglichen Konfigurationen sind dort dokumentiert.
Um die Komponente in Projekten zu verwenden, kann ein .jar über ant erstellt werden. Die Property-Dateien sind bewusst nicht bestandteil des .jars und müssen in jeder Entwicklung selbst angelegt werden.
Eine vorgebaute Version befindet sich im /dist Verzeichnis (erstellt mit java 6)
Wie ist die Komponente zu verwenden?1. Möglichkeit: direkte Implementierung der abstrakten Klassen
1a: Beispiel Runnable:
NotesThreadPool.getInstance().doSomeNotesWork(new NotesRunnableTask(i) {
@Override
public void runNotes(Session session) {
// use session to do some work
}
});
1b: Beispiel Callable:
NotesThreadPool.getInstance().doSomeNotesWork(new NotesCallableTask(i) {
@Override
public Object runNotesAndCallback(Session session) {
// use session to do some work
return "call back";
}
});
Diese beiden Beispiele sind im ShowCase.java ersichtlich. Der Parameter "i" ist ein Zähler für den ShowCase und wird später entfernt.
2. Möglichkeit: Ableiten der abstrakten Klasse (notwendig, falls weitere Objekte benötigt werden.
Hier ein kleines Beispiel das ich aktuell in einem Workflow teste:
public class CreateInvoice extends NotesRunnableTask {
private Invoice invoice;
public CreateInvoice(Long workingnumber) {
super(workingnumber);
}
@Override
public void runNotes(Session session) {
// do some work with invoice
}
public void createInvoice(Invoice invoice) {
this.invoice = invoice;
NotesThreadPool.getInstance().doSomeNotesWork(this);
}
}
Der Parameter workingNumber dient nur für den ShowCase und wird langfristig entfernt. Zum Test kann einfach irgendein Long-Wert (z.B. 0L) übergeben werden.
Der komplette Pool kann über folgendes snippet beendet werden:
NotesThreadPool.getInstance().shutDown();
Da ich keinen Domino-Server lokal installiert habe, konnte ich den Zugriff via http noch nicht testen.
Ich freue mich euer Feedback und Vorschläge zur Verbesserung der Komponente :-)
Grüße Thomas :-)
PS: Download befindet sich im Fuß dieses Threads.
Update: Beispielkonfigurationen:
Single-Threaded über eine Session:domino.threadpool.size=1
domino.threadpool.sessionAchieve=true
Single-Threaded mit jeweils neuer Session:domino.threadpool.size=1
domino.threadpool.sessionAchieve=false
Multi-Threaded über eine session pro thread für alle tasks:domino.threadpool.size=50
domino.threadpool.sessionAchieve=true
Multi-Threaded mit jeweils neuer session pro thread für alle tasks:domino.threadpool.size=50
domino.threadpool.sessionAchieve=false