AtNotes Übersicht Willkommen Gast. Bitte einloggen oder registrieren.
07.06.20 - 04:29:05
Übersicht Hilfe Regeln Glossar Suche Einloggen Registrieren
News:
Schnellsuche:
+  Das Notes Forum
|-+  Lotus Notes / Domino Sonstiges
| |-+  Java und .NET mit Notes/Domino (Moderatoren: Axel, m3)
| | |-+  Mit java eine SessionFactory für Notes implementieren
« vorheriges nächstes »
Seiten: [1] 2 Nach unten Drucken
Autor Thema: Mit java eine SessionFactory für Notes implementieren  (Gelesen 9709 mal)
sudsaat
Junior Mitglied
**
Offline Offline

Beiträge: 78


« am: 29.11.10 - 17:56:28 »

Hallo community,

für eine komponentenbasierte Entwicklung bin ich gerade dabei ein technisches Konzept zu erarbeiten. Mitunter ist eine Notes-Komponente, die den Zugriff auf Domino kapselt ein Thema.

Mein Ansatz (denke da liegt mein Fehler) ist folgender:

1. Konfiguration der Komponente über ein property-file

Code:
# WeberT: properties for the domino-access component.

# generally set the type of access. Following types are available
# IIOP - using CORBA to access domino-server.
# local - using locally installed notes-client to access domino-server
domino.access.type=IIOP oder local
domino.access.host=serverIP oder HostName
domino.access.user=vollständiger benutzer
domino.access.password=passwort

2. Eine "generische" Factory entscheidet, welche Factory (Corba oder local) die Komponente verwendet

Code:
import java.util.ResourceBundle;

import lotus.domino.Session;

public class GenericDominoFactory {

// WeberT: the name of the property-file
private static final String DOMINO_FACTORY_RESOURCE_NAME = "dominofactory";

// WeberT: the key to get access-type from property-file
private static final String DOMINO_ACCESS_TYPE_KEY = "domino.access.type";

// WeberT: this are the available access-types
private static final String DOMINO_ACCESS_IIOP = "IIOP";
private static final String DOMINO_ACCESS_LOCAL = "LOCAL";

private static DominoFactory factory;

private GenericDominoFactory() {

}

public static Session getDominoSession() {
if (factory==null) {
ResourceBundle resources = ResourceBundle.getBundle(DOMINO_FACTORY_RESOURCE_NAME);
String accessType = resources.getString(DOMINO_ACCESS_TYPE_KEY);
if (accessType.equalsIgnoreCase(DOMINO_ACCESS_IIOP)) {
factory = new RemoteCorbaDominoFactory();
} else if (accessType.equalsIgnoreCase(DOMINO_ACCESS_LOCAL)) {
factory = new LocalDominoFactory();
} else {
System.out.println("DOMINO: no valid access-type was given, please check " + DOMINO_FACTORY_RESOURCE_NAME + ".properties for key " + DOMINO_ACCESS_TYPE_KEY);
}
}
return factory!=null ? factory.getDominoSession() : null;
}

}

3. Die beiden konkreten Factories folgen dem Interface "DominoFactory"

Code:
import lotus.domino.Session;

public interface DominoFactory {

public abstract Session getDominoSession();
}

4a. Entweder übernimmt die Corba-Implementierung das Erzeugen einer Session

Code:
import java.util.ResourceBundle;

import lotus.domino.NotesException;
import lotus.domino.NotesFactory;
import lotus.domino.Session;

public class RemoteCorbaDominoFactory implements DominoFactory {

private static final String DOMINO_FACTORY_RESOURCE_NAME = "dominofactory";

private static final String DOMINO_HOST_KEY = "domino.access.host";
private static final String DOMINO_USER_KEY = "domino.access.user";
private static final String DOMINO_PASSWORD_KEY = "domino.access.password";

@Override
public Session getDominoSession() {
ResourceBundle resources = ResourceBundle.getBundle(DOMINO_FACTORY_RESOURCE_NAME);
Session session = null;

try {
session = NotesFactory.createSession( resources.getString(DOMINO_HOST_KEY),
resources.getString(DOMINO_USER_KEY),
resources.getString(DOMINO_PASSWORD_KEY));
} catch (NotesException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

return session;
}

}

..anschließend kann ich die session verwenden und muss nur an "recycle" aller erzeugten Objekte und der Session selbst kümmern.

4b. Oder die Local-Implementierung erzeugt die Session

Code:
import java.util.ResourceBundle;

import lotus.domino.NotesException;
import lotus.domino.NotesFactory;
import lotus.domino.NotesThread;
import lotus.domino.Session;

public class LocalDominoFactory implements DominoFactory {

@Override
public Session getDominoSession() {

NotesThread.sinitThread();
Session session = null;
try {
session = NotesFactory.createSession();
} catch (NotesException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// NotesThread.stermThread();

return session;
}

}

Neben dem Problem, dass ich eigentlich gerne die Session über die überladene static-Methode NotesFactory.createSession((String)null, user, pwd) erzeugen würde (da bekomme ich user is not a server?!? - dazu habe ich aber einen weiteren Thread hier eröffnet), stehe ich vor der Problematik, wie ich das mit dem stermThread() am besten handhabe.

Wenn ich das bereits in der Implementierung aufrufe, erhalte ich logischerweise später die Meldung:
Object has been removed or recycled

wenn ich es nicht aufrufe, besteht die Gefahr, dass Notes crashed.

Meine Vermutung ist, dass mein Ansatz für Notes nicht praktikabel ist?

Welche Ansätze gibt es, um eine solche Komponente zu entwickeln (einen globalen Thread der die Session aufrecht hält? Einen finally-Block? etc...).

Bin für jeglichen Input dankbar.

Grüße Thomas :-)
« Letzte Änderung: 30.11.10 - 01:16:01 von sudsaat » Gespeichert
Ralf_M_Petter
Gold Platin u.s.w. member:)
*****
Offline Offline

Geschlecht: Männlich
Beiträge: 1879


Jeder ist seines eigenen Glückes Schmied


WWW
« Antworten #1 am: 30.11.10 - 12:47:55 »

Hallo Thomas!

So wie du willst, wirst du das nicht hinbekommen. Das Notesthread.sinitThread und NotesThread.stermThread muss in jedem Thread extra gemacht werden. Das heisst, wenn du dein generiertes Session Objekt in einem anderen Thread verwenden willst, dann muss auch dieser Thread erst initialisiert werden und wieder deinitialisiert werden.

Ich verwende ein anderes Modell das einige Vorteile hat.

Ich habe einen Threadpool generiert, in dem x Threads automatisch für Domino initialisiert und eine Session erstellt werden. Wenn ich nun Code habe der Domino verwendet packe ich den in einen Runnableblock und übergebe in dem Threadpool. Zur Übergabe des RunnableObjekts gibt es eine Methode für Asynchrone Ausführung und auch Warten bis der Block abgeschlossen ist.

Der grosse Vorteil ist, dass in allen Thread die Session immer schon bereit steht und auch zuverlässig von dem Threadpool recycelt wird. Das heisst, wenn ich in einem Runnableblock mal auf das Recyceln vergesse, dann ist nichts verhaut, da die Session am Ende der Ausführung automatisch recycelt wird. Man kann den Threadpool natürlich auch so programmieren, dass er nicht nur das Session Objekt vorhält, sondern auch noch andere Objekte schon voraus generiert, wie Datenbanken oder View Objekte.

Wenn meine Anwendung beendet wird, ruft sie eine Methode des Threadpools auf, die alle Threads ordnungsgemäß beendet.

Grüße

Ralf
Gespeichert

Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.
sudsaat
Junior Mitglied
**
Offline Offline

Beiträge: 78


« Antworten #2 am: 30.11.10 - 13:34:55 »

Hallo Ralf,

das habe ich mir schon gedacht das ich irgendwie auf dem Holzweg bin.

Dein Ansatz klingt sehr gut, hast du da eventuell ein code-snippet auf dem ich aufbauen könnte parat? Gerade der Pool mit der asynchronen Ausführung würde mich interessieren.

Vielen Dank.

Grüße Thomas :-)
Gespeichert
Ralf_M_Petter
Gold Platin u.s.w. member:)
*****
Offline Offline

Geschlecht: Männlich
Beiträge: 1879


Jeder ist seines eigenen Glückes Schmied


WWW
« Antworten #3 am: 30.11.10 - 14:18:24 »

Kann leider keinen Code posten, da der Code für meinen Arbeitsgeber entwickelt wurde. Ist jetzt etwas zu viel Arbeit es hier nachzuprogrammieren. Ausserdem wenn ich es nocheinmal machen müsste würde ich es mit dem Concurrent Framework probieren, dass ja mittlerweile verfügbar ist.

Für einen ersten Einstieg in das Concurrent Framework von Java lies dir mal http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ThreadPoolExecutor.html#terminated%28%29 durch oder du kaufst dir gleich das Buch  über Concurrency in Java http://www.amazon.de/Java-Concurrency-Practice-Brian-Goetz/dp/0321349601/ref=sr_1_1?ie=UTF8&qid=1291122897&sr=8-1
 

Grüße

Ralf
Gespeichert

Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.
sudsaat
Junior Mitglied
**
Offline Offline

Beiträge: 78


« Antworten #4 am: 30.11.10 - 15:11:04 »

Hi Ralf,

das mit dem Code posten ist kein Problem - kann ich nachvollziehen :-)

Das mit dem Concurrent-Framework ist eine gute Idee - auf die bin ich noch gar nicht gekommen.

Werde mich mal daran versuchen, wobei meine Hürde eher Domino als Java ist ;-)

Vielen Dank für dein Feedback, hat sehr geholfen!

Grüße Thomas :-)
Gespeichert
flaite
Gold Platin u.s.w. member:)
*****
Offline Offline

Beiträge: 2966


WWW
« Antworten #5 am: 30.11.10 - 17:43:54 »

Zitat
gerne die Session über die überladene static-Methode NotesFactory.createSession((String)null, user, pwd) erzeugen würde (da bekomme ich user is not a server?!? - dazu habe ich aber einen weiteren Thread hier eröffnet)
Wenn ich mich recht erinnere kommt der Effekt, wenn du
a) Client und Server auf dem selben Rechner installiert hast.
UND
b) der Server im PATH des OS vor dem Client steht. Im PATH vom Betriebssystem muss der Client vor dem Server erwähnt werden.
Gespeichert

Ich stimm nicht mit allen überein, aber mit vielen und sowieso unterhaltsam -> https://www.youtube.com/channel/UCr9qCdqXLm2SU0BIs6d_68Q

---

Aquí no se respeta ni la ley de la selva.
(Hier respektiert man nicht einmal das Gesetz des Dschungels)

Nicanor Parra, San Fabian, Región del Bio Bio, República de Chile
sudsaat
Junior Mitglied
**
Offline Offline

Beiträge: 78


« Antworten #6 am: 01.12.10 - 15:50:13 »

Hallo zusammen,

ich brauche nochmal einen kleinen Gedankenanstoß für die Implementierung eines Thread-Pools.

Für das Java Concurrent-Framework habe ich mir einige Testklassen geschrieben, die soweit auch funktionieren:
- eine generische Pool-Factory die entscheidet ob Single-, Fixed- oder Cached-Pooling verwendet wird
- eine Test-Klasse MyNotesThread
- eine NotesThread-Factory für die initialisierung von MyNotesThread
- 2 Interfaces (MyNotesRunnable und MyNotesCallable für Rückmeldungen)

soweit so gut...

Wenn die Factory jetzt einen Thread erzeugt, kann ich dort beispielsweise die Session erzeugen und den Thread vorhalten bis ein "Worker" Arbeit liefert.

Das Concurrent-Framework übernimmt die Initialisieung und Wiederverwendbarkeit der Threads. Die Wiederverwendbarkeit der Threads ist gerade meine Denkblokade :-)

Folgender exemplarischer Code:
Code:
ExecutorService executor = Executors.newFixedThreadPool(2, new NotesThreadFactory());

List<Future<Boolean>> list = new ArrayList<Future<Boolean>>();

for (int i = 0; i < 6; i++) {
Future<Boolean> submit = executor.submit(new NotesCallable() {

private Random generator = new Random();

@Override
public Boolean call() throws Exception {
long sleepTime = generator.nextInt( 10000 );
System.out.println("sleeping for " + sleepTime + " milliseconds");
Thread.sleep(sleepTime);
return true;
}
});

list.add(submit);
}

erzeugt über die NotesThreadFactory initial 2 Threads der Klasse "MyNotesThread". Der Konstruktur der Klasse übernimmt hier exemplarisch die initialisierung:

Code:
public NotesThreadData(Runnable r) {
super(r);
try {
NotesThread.sinitThread();
session = NotesFactory.createSession();
System.out.println("Session initialized: " + session.hashCode());
} catch (NotesException e) {
e.printStackTrace();
}
}

und hält die session vor für die kommenden Worker.

Im obigen Beispiel werden 6 NotesCallable erzeugt, die parallel (immer 2 aktiv) abgearbeitet werden.

Wie schaffe ich es jetzt, dem Thread mitzuteilen nach jedem abgearbeiteten Worker die session zu recyclen, sTermTerm() aufzurufen und sich neu zu initialisieren?

Hab da gerade ne komplette Denkblockade und komme nicht weiter.

Freue mich auf eure Antworten.

PS: Wenn ich einen brauchbaren Stand habe, kann ich ihn auch gerne zum Test zur Verfügung stellen.

Grüße Thomas :-)

Noch was am Rande: Welche Funktionalität bietet die Klasse:
lotus.notes.addins.util.NotesThreadPool;

finde leider nichts brauchbares was diese Klasse betrifft?!?
« Letzte Änderung: 01.12.10 - 16:14:11 von sudsaat » Gespeichert
MadMetzger
Gold Platin u.s.w. member:)
*****
Offline Offline

Geschlecht: Männlich
Beiträge: 1052


f.k.a. Alexis Pyromanis


« Antworten #7 am: 01.12.10 - 16:13:50 »

Du könntest unter das Interface direkt eine Abstrakte Implemtierung hängen, die eine Templatemethode (Müsste eines der GoF-Patterns sein) enthält: (Ich glaube, dass es geschickter ist, die Inititialisierung vielleicht nicht im Konstruktor schon zu machen)

Code:
public void run() {
initSession()
doWork()
terminateSession()
}

public void initSession() {
// initialisiere NotesSession
}

public terminateSession() {
// terminate NotesSession usw.
}

public abstract doWork()

In der Methode doWork passiert dann die eigentliche Arbeit.

Das Ganze aus dem Bauch heraus, ohne deinen Code im Detail zu kennen.
Gespeichert

sudsaat
Junior Mitglied
**
Offline Offline

Beiträge: 78


« Antworten #8 am: 01.12.10 - 16:27:32 »

Hallo MadMetzger,

vielen Dank für die schnelle Antwort, aber ich glaube wir reden ein wenig aneinander vorbei :-)

Mein Ziel ist (vereinfacht):
- Einen ThreadPool der x-Threads parallel abarbeitet (mit Concurrent kein Thema)
- Jeder Thread solle zumindest eine session (später auch db, usw.) vorhalten (also bereits initialisiert)
- Somit der Programmcode eines Worker (Runnable oder Callable) direkt ausgeführt werden ohne auf die initialisierung der Notes-Objekte zu warten
- Nachdem der Thread die Arbeit eines Workers beendet hat, soll er die Objekte recyclen und gleich für den nächsten Worker wieder initialisieren

..wenn ich es mit einem GoF-Pattern löse, erfolgt (wie in deinem Beispiel) die Initialisierung erst, wenn ein Worker-Objekt eingeliefert wird, d.h. diese Variante spart zwar Schreibarbeit was die Initialisierung und Terminierung angeht, dauert aber länger, da jeder Worker auf die Initialisierung warten müsste.

Hoffe ich habe es verständlich erklärt.

Hast Du hierzu eine Idee?

Problemstellung kurz zusammengefasst: Wie kann ein wiederverwendbarer Thread für kommende Worker immer eine neue Objekte (z.B. session) vorhalten?

Freue mich auf Feedback.

Grüße Thomas :-)
Gespeichert
MadMetzger
Gold Platin u.s.w. member:)
*****
Offline Offline

Geschlecht: Männlich
Beiträge: 1052


f.k.a. Alexis Pyromanis


« Antworten #9 am: 01.12.10 - 16:36:36 »

100%ig ist mir dein Modell noch nicht klar, aber natürlich kannst du das recyclen und neu initialisieren auch in der Methode terminateSession() machen. Diese hieße dann vielleicht sinniger recycleAndInitializeNew(). Das Templatemuster ginge dann trotzdem noch, denke ich. Oder ich habe gerade eine falsche Vorstellung von deinem Code. Lösbar ist deine Anforderung sicherlich, muss auch nicht die Templatemethod sein, die kam mir nur reflexartig in den Sinn, weil Teile bei der Abarbeitung immer gleich sind.

Wie sehen denn Pool, Thread und Worker usw ungefähr aus?
Gespeichert

sudsaat
Junior Mitglied
**
Offline Offline

Beiträge: 78


« Antworten #10 am: 01.12.10 - 17:15:44 »

Ich versuche das ganze an einem "out-of-the-box" beispiel klarzumachen.

Ist stark vereinfact, hoffe es ist alles drin und wird deutlich:

NotesThreadData sieht folgendermaßen aus:
Code:
package out.of.the.box;

import lotus.domino.NotesException;
import lotus.domino.NotesFactory;
import lotus.domino.NotesThread;
import lotus.domino.Session;

public class NotesThreadData extends Thread {

private Session session = null;

public NotesThreadData(Runnable r) {
super(r);
try {
NotesThread.sinitThread();
session = NotesFactory.createSession();
System.out.println("Session initialized: " + session.hashCode());
} catch (NotesException e) {
e.printStackTrace();
}
}
}

Diese werden von dieser Factory erzeugt:

Code:
package out.of.the.box;

import java.util.concurrent.ThreadFactory;

public class NotesThreadFactory implements ThreadFactory {

public Thread newThread(Runnable r) {
return new NotesThreadData(r);
}
}

das ganze wird über einen ThreadPool gesteuert:

Code:
package out.of.the.box;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NotesThreadPool {

private static final int NTHREDS = 2;

private ExecutorService executorService = null;

public NotesThreadPool() {
executorService = Executors.newFixedThreadPool(NTHREDS, new NotesThreadFactory());
}

public void doSomeNotesWork(Runnable r) {
executorService.execute(r);
}

public void shutDown() {
// WeberT: make the executor accept no new threads and finish all existing threads in the queue
executorService.shutdown();

// WeberT: wait until all threads are finished
while (!executorService.isTerminated()) {}

System.out.println("Finished all threads");
}

}

Zum starten was passiert:
Code:
package out.of.the.box;

public class Main {

public static void main(String[] args) {

NotesThreadPool pool = new NotesThreadPool();

for (int i = 0; i < 10; i++) {

pool.doSomeNotesWork(new Runnable() {
@Override
public void run() {
System.out.println("Runnable run");
}
});
}
pool.shutDown();
}

}

Beim Start werden für beide Threads eine Session initialisiert. Ich möchte, dass dies nach jedem Worker passiert (In diesem Beispiel sind die Worker simple Runnables).

Hoffe es wird deutlich.

Danke für die Unterstützung und verschneite Grüße
Thomas :-)
Gespeichert
MadMetzger
Gold Platin u.s.w. member:)
*****
Offline Offline

Geschlecht: Männlich
Beiträge: 1052


f.k.a. Alexis Pyromanis


« Antworten #11 am: 01.12.10 - 17:26:51 »

Okay, jetzt wird es ein wenig klarer. Vermutlich macht es Sinn die Methode run(), von der ich meine, dass sie run() auf dem im Konstruktor übergebenen Runnable aufruft, zu überschreiben: (nur eine grobe Skizze/Idee ohne zu probieren)
Code:
@Override
public void run() {
    super.run();
    //session recycling and reinit
}
Gespeichert

sudsaat
Junior Mitglied
**
Offline Offline

Beiträge: 78


« Antworten #12 am: 01.12.10 - 17:50:27 »

Meinst du in etwa sowas:

Code:
package out.of.the.box;

import lotus.domino.NotesException;
import lotus.domino.NotesFactory;
import lotus.domino.NotesThread;
import lotus.domino.Session;

public class NotesThreadData extends Thread {

private Session session = null;

public NotesThreadData(Runnable r) {
super(r);
try {
NotesThread.sinitThread();
session = NotesFactory.createSession();
System.out.println("Session initialized: " + session.hashCode());
} catch (NotesException e) {
e.printStackTrace();
}
}

@Override
public synchronized void start() {
System.out.println("start was called with session: " + session.hashCode());
super.start();
}

@Override
public void run() {
System.out.println("run was called with session: " + session.hashCode());
super.run();
}
}

das Problem hierbei ist, dass die run() Methode ebenfalls nur einmal aufgerufen wird, output beim ausführen:

Session initialized: 16112134
start was called with session: 16112134
Session initialized: 18508170
start was called with session: 18508170
run was called with session: 18508170
Runnable run
Runnable run
Runnable run
Runnable run
Runnable run
Runnable run
Runnable run
Runnable run
Runnable run
run was called with session: 16112134
Runnable run
Finished all threads


ne idee?

vielleicht ein eigener ExecutorService implementieren, um die Threads dort zu initialisieren?

Danke und Grüße Thomas :-)

Edit: Ich ziehe mir gerade die Java-Sourcen und schaue mir die Implementierung des ExecutorService an - der könnte dann auch gleich zu beginn n-Threads initial erstellen bevor die ersten Worker vorbeischauen.
« Letzte Änderung: 01.12.10 - 18:12:18 von sudsaat » Gespeichert
Ralf_M_Petter
Gold Platin u.s.w. member:)
*****
Offline Offline

Geschlecht: Männlich
Beiträge: 1879


Jeder ist seines eigenen Glückes Schmied


WWW
« Antworten #13 am: 02.12.10 - 08:02:07 »

Mein Meinung nach musst du einen ThreadPoolExceutor http://download.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/ThreadPoolExecutor.html#terminated%28%29 verwenden und dort die Methoden initialize und terminate überschreiben. Diese sind doch für das einrichten und terminieren des Threads zuständig.

Grüße

Ralf
Gespeichert

Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.
MadMetzger
Gold Platin u.s.w. member:)
*****
Offline Offline

Geschlecht: Männlich
Beiträge: 1052


f.k.a. Alexis Pyromanis


« Antworten #14 am: 02.12.10 - 08:43:14 »

Ich wusste gar nicht, dass Java schon was in der Art mitbringt, man lernt nie aus. Vermutlich ist das sogar noch sinnvoller, als wenn du das komplett selbst schreibst. Wozu das Rad zweimal erfinden...
Gespeichert

Ralf_M_Petter
Gold Platin u.s.w. member:)
*****
Offline Offline

Geschlecht: Männlich
Beiträge: 1879


Jeder ist seines eigenen Glückes Schmied


WWW
« Antworten #15 am: 02.12.10 - 09:15:43 »

Das Concurrent Framework wurde erst mit 1.5 eingeführt. Ich habe selber auch eine eigene Lösung programmiert. Aber wie gesagt richtige nebenläufige Programmierung ist extrem schwierig und deshalb werde ich in Zukunft auch verstärkt auf das Fix und fertig Framework von java setzen.

Ralf
Gespeichert

Jede Menge Tipps und Tricks zu IT Themen findet Ihr auf meinem Blog  Everything about IT  Eine wahre Schatzkiste sind aber sicher die Beiträge zu meinem Lieblingsthema Tipps und Tricks zu IBM Notes/Domino Schaut doch einfach mal rein.
flaite
Gold Platin u.s.w. member:)
*****
Offline Offline

Beiträge: 2966


WWW
« Antworten #16 am: 02.12.10 - 14:39:57 »

Das mit dem Concurrent Framework zu machen wär vermutlich eine gute Idee. Fragt sich nur, wenn man sowas schreiben soll.

Thomas,

ich mag die Idee eigentlich nicht, solche Connection Objekte mit einer fertigen Session in den Pool zu legen. Dann eher Sessions nicht schliessen und die im Pool zwischenparken.
Das mag ich eigentlich auch nicht.
Ich versuche solche Ressourcen immer möglichst kurz zu halten.
Erst wenn es performance-mässig überhaupt nicht anders geht, würd ich über solche Park-Lösungen überhaupt erst nachdenken.

Eine NotesSession ist für mich sowas wie ein InputStream und den parkt man ja auch nicht initialisiert in irgendwelchen Objekten.

Gruß Axel
Gespeichert

Ich stimm nicht mit allen überein, aber mit vielen und sowieso unterhaltsam -> https://www.youtube.com/channel/UCr9qCdqXLm2SU0BIs6d_68Q

---

Aquí no se respeta ni la ley de la selva.
(Hier respektiert man nicht einmal das Gesetz des Dschungels)

Nicanor Parra, San Fabian, Región del Bio Bio, República de Chile
sudsaat
Junior Mitglied
**
Offline Offline

Beiträge: 78


« Antworten #17 am: 02.12.10 - 20:26:59 »

Hallo zusammen,

vielen Dank für euer Feedback.

Ich habe heute eine kleine Test-Suite über das Concurrent Framework entwickelt - wer es mal testen möchte, bitte an mich wenden (weiß nicht, ob ich das hier so einfach posten darf?)

@Ralf_M_Peter:
Der beiden Methoden verwendet ThreadPoolExecutor selbst für initialisierung und terminierung (also wenn der Pool gestartet und beendet wird).

@Pitiyankee:
Ich benötige das um einen schnellen Zugriff für synchrone Requests mit Rückmeldung an den "Verursacher" (beispielsweise einen Benutzer) zu gewährleisten. Das erstellen der Session kann u.U. schon mal 2-3 Sekunden benötigen, und die sind in dem vorgesehenen Kontext "sehr teuer". Ich entwickel viele Schnittstellenprogramme zwischen ERP-System, Workflow-Systemen, Archiv-Systemen etc. und dort versuche ich immer einen Pool mit Anmeldungen (was eine Session in Notes im Wesentlichen ja ist) vorzuhalten. Ich sehe also die Session nicht als InputStream sondern eher wie ein Verbindung in einem ConnectionPool für Datenbanken). Der Performance-Faktor ist immens und der Benutzer glücklich, wenn er anstatt ca. 10 Sekunden nur 0,2 Sekunden auf das Ergebnis wartet :-)

Ansonsten gebe ich dir recht, bei nicht zeitkritischen kleinen Anwendungn ergibt das wenig Sinn, da der Overhead (ist die "geparkte" session noch gültig oder serverseitig bereits geschlossen blabla ) alles wegfällt.

Ich bastel noch ein wenig weiter, nächstes Ziel ist die Session generisch über DIIOP, Internet, local etc. zu beziehen und den Thread-Pool über properties zu konifigurieren (großes Ziel ist eine Notes-Komponente für den direkten Einsatz für weitere Entwicklungen zu erstellen).

so long... Thomas :-)

PS: Sollte das in einen neuen Forums-Thread? Hat ja mit dem jetzigen nur noch bedingt zu tun.
« Letzte Änderung: 03.12.10 - 02:15:28 von sudsaat » Gespeichert
sudsaat
Junior Mitglied
**
Offline Offline

Beiträge: 78


« Antworten #18 am: 02.12.10 - 20:42:53 »

Update: Generische Factory ist fertig für IIOP und local - jetzt ist der Zeitpunkt mich mit meinem Problem "user is not a server" für internet-sessions zu befassen :-)

Grüße Thomas :-)

------------8<---------(snip)-------------------------------

Edit: den generischen teil werde ich noch ein wenig umstricken...

Kurz was anderes: Ich bekomme ab und an den Fehler:
Notes initialization failure - err 41728

ist bei IBM auch schon durch einen anderen Benutzer gemeldet. Kennt jemand diesen Fehler?

------------8<---------(snip)-------------------------------

Edit: Suche jemanden, der Bock hat, die kleine Komponente zu testen. Mich würde interessieren, ob der Fehler auch bei euch auftritt. JUnit-Testklassen für den Verbindungstest sind vorhanden für:

- GenericSessionFactory (über property konfigurierbar)
- LocalSessionFactory
- RemoteCorbaSessionFactory
- InternetSessionFactory

..eine Test-Suite für alle Tests gemeinsam.

Die InternetSessionFactory wirft aktuell leider den Fehler (user is not a server) bei mir (Notes 8.5.2). Wäre für einen Tester dankbar :-)

Weiter bekomme ich wie gesagt ab und an den Fehler:
Notes initialization failure - err 41728

Wäre auch interessant, wie sich das bei euch verhält?

Grüße Thomas :-)

------------8<---------(snip)-------------------------------

Update: Zwischenstand für potentielle Tester :-)

Die Komponenten ist bisher ein Geflecht aus 16 Klassen und bitet folgende Features:
- NotesThreadPooling über Concurrent-Framework
- 3 Zugriffsmodi (IIOP, http, local)
- Vorhalten einer neuen Session für jeden eintreffenden task
- Recycle der Session nach abgearbeitetem Task
- Konfiguration über property-file
- Junit-Tests (siehe oben)
- Testlauf mit zufälliger ABM :-)

Konfigurierbar sind bisher folgende Optionen:

Code:
# access type (IIOP, http, local)
domino.access.type=local

# connection-properties
domino.access.fullAccess=false
domino.access.host=172.30.41.115
domino.access.sslActive=false
domino.access.user=easyxbase easyxbase/comdms
domino.access.password=topS3cr3t
domino.access.inetPassword=topS3cr3t

# Thread-Pool config
#
# domino.threadpool.size - set maximal count of workers for incoming tasks
#
domino.threadpool.size=2

Aktuell in Arbeit:
- generische Rückmeldung von Tasks nach getaner Arbeit über "Callable" statt "Runnable"

ich halte euch auf dem laufenden.

Grüße Thomas :-)

------------8<---------(snip)-------------------------------

Update: callables sind nun auch möglich, bin mir aber noch nicht sicher, wie ich mit der Rückmeldung der Future-Objekte umgehe?

Habe mal testweise 10.000 Tasks über den Thread-Pool mit 50 Threads abarbeiten lassen - sieht soweit gut aus.

------------8<---------(snip)-------------------------------

Update: sessionAchieve hinzugefügt. Über properties kann bestimmt werden, ob die worker (threads) eine erstellte session beibehalten oder nach jedem Task recyclen und neu initialisieren.

Die Komponente deckt jetzt folgende Szenarien ab (exemplarisch):

Single-Threaded mit einer 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 mit einer session / thread für alle tasks:
domino.threadpool.size=50
domino.threadpool.sessionAchieve=true

Multi-Threaded mit jeweils neuer session / thread für alle tasks:
domino.threadpool.size=50
domino.threadpool.sessionAchieve=false


Muss mich jetzt anderen Themen widmen. Denke in der kommenden Woche werde ich folgende Themen angehen:
- Fehlerbehandlung über uncheckedExceptions
- Logging (evtl. über SLF4J)

Habe kein Feedback mehr erhalten, daher bin ich mir unsicher, ob das Thema von Interesse ist.

Falls nicht, bitte diesen Thread schließen.

Grüße Thomas :-)
« Letzte Änderung: 04.12.10 - 20:06:09 von sudsaat » Gespeichert
sudsaat
Junior Mitglied
**
Offline Offline

Beiträge: 78


« Antworten #19 am: 05.12.10 - 15:03:48 »

Die Komponenten verwendet jetzt SLF4J.

Im Paket wird aktuell Log4J als Logging-Framwework über SLF4J eingesetzt.

Grüße Thomas :-)
Gespeichert
Seiten: [1] 2 Nach oben Drucken 
« vorheriges nächstes »
Gehe zu:  


Einloggen mit Benutzername, Passwort und Sitzungslänge

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2006, Simple Machines Prüfe XHTML 1.0 Prüfe CSS
Impressum Atnotes.de - Powered by Syslords Solutions - Datenschutz | Partner: