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) { |
| |
| } |
| }); |
1b: Beispiel Callable:
| NotesThreadPool.getInstance().doSomeNotesWork(new NotesCallableTask(i) { |
| |
| @Override |
| public Object runNotesAndCallback(Session session) { |
| |
| 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) { |
| |
| } |
| |
| 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