Jedes Plugin in Notes/Eclipse kann Einstellungen haben, die bestimmte Funktionalitäten des Plugins steuern.
Diese Einstellungen werden in dem Pfad "workspace\.metadata\.plugins\org.eclipse.core.runtime\.settings" abgelegt. Für jedes Plugin, dass Einstellungen (Preferences) verwendet, wird ein eigenes Prefs File erstellt. Diese PrefsFiles können mit einem Texteditor problemlos editiert werden und sind als Schlüsselwort Wert Paare aufgebaut. Normalerweise ist es so, dass wenn man die Prefsdatei löscht, wird das File beim nächsten Laden des Plugins wieder mit Defaulteinstellungen erstellt. Das kann auch helfen, wenn in Lotus Notes irgendwas nicht so funktioniert wie es soll. Statt des Löschen des gesamten workspace Ordner kann man zielgerichtet einzelne Einstellung rauslöschen.
A blog about information technology. I am especially interested in Java, Eclipse RCP, IBM Notes Domino, Db2 and IBM i
Tuesday, May 22, 2012
Monday, May 21, 2012
Performanceverbesserungen durch Indexonly Access beim Zugriff auf die DB/2
Sehr oft braucht man bei relationalen Zugriffen nicht den ganzen Datensatz sondern nur ein Feld. Ein typisches Beispiel ist der Kundenstamm. Meistens braucht man in Selects für die Anzeige nur den Kundennamen nicht aber den Rest der Informationen. In einer Auftragsanzeige könnte z.B. die Auftragsnummer, Kundennummer ,Kundenname, Artikelnummer angezeigt werden.
Das SQL Statement dafür wäre:
select auftraege.auftragsnummer, auftraege.kundennummer, kunden.kundenname, auftraege.artikelnummer from auftraege, kunden where auftraege.kundennummer=kunden.kundennummer
Um die Verarbeitung zu beschleunigen wurde ein Index über die Kundentabelle mit der kundennummer als Unique Key erstellt. Damit wird bei der Verarbeitung folgender Zugriffsplan verwendet:
Die Auftragsdatei wird mittels Tablescan komplett durchgelesen. Für jeden Auftrag wird ein Index Zugriff durchgeführt und mit den Auftragen zusammengejoint. Dann muss aber noch für jeden Kunden ein extra Zugriff auf den Satz in der Kunden Tabelle erfolgen, um den Namen zu lesen. In unserer Beispieldatenbank sind weil wir 14.941 Aufträge haben dafür genau so viele Zugriffe notwendig.
Wenn diese Abfrage in der Anwendung sehr oft verwendet wird, entsteht natürlich ein relativ großer Overhead. Dies kann man durch einen besseren Index, der die Verwendung von Index only Access erlaubt verbessert werden.
Wir ergänzen daher unseren Index und fügen hinter der kundennummer noch das Feld kundenname an.
Wenn wir nun die selbe SQL Anweisung wie oben ausführen, bekommen wir einen schnelleren Zugriffsplan:
Die aufwendige Verarbeitung des Tableprobes ist komplett weggefallen. In den Erläuterungen zu dem Zugriffsplan steht auch, dass die Indexonly Methode für den Zugriff verwendet wurde.
Bei meinen Tests konnte ich eine 25% Performanceverbesserung des Query mit dem verbesserten Index gegenüber der ursprünglichen Variante feststellen.
Der Indexonly Zugriff beschleunigt nicht nur Joins sondern auch normale Zugriffe.
Das SQL:
select kundenname from kunden where kundennummer=4711
wird wenn der um kundenname erweiterte Index vorhanden ist mit einem optimierten Zugriffsplan ausgeführt.
statt dem schlechteren Zugriffsplan wenn nur die kundenNummer im Index vorhanden ist.
Die Tests wurden auf einen i/5 V6R1 durchgeführt. Sollten sich aber auf anderen Systemen ebenfalls nachvollziehen lassen. Einfach einmal ausprobieren.
Das SQL Statement dafür wäre:
select auftraege.auftragsnummer, auftraege.kundennummer, kunden.kundenname, auftraege.artikelnummer from auftraege, kunden where auftraege.kundennummer=kunden.kundennummer
Um die Verarbeitung zu beschleunigen wurde ein Index über die Kundentabelle mit der kundennummer als Unique Key erstellt. Damit wird bei der Verarbeitung folgender Zugriffsplan verwendet:
Die Auftragsdatei wird mittels Tablescan komplett durchgelesen. Für jeden Auftrag wird ein Index Zugriff durchgeführt und mit den Auftragen zusammengejoint. Dann muss aber noch für jeden Kunden ein extra Zugriff auf den Satz in der Kunden Tabelle erfolgen, um den Namen zu lesen. In unserer Beispieldatenbank sind weil wir 14.941 Aufträge haben dafür genau so viele Zugriffe notwendig.
Wenn diese Abfrage in der Anwendung sehr oft verwendet wird, entsteht natürlich ein relativ großer Overhead. Dies kann man durch einen besseren Index, der die Verwendung von Index only Access erlaubt verbessert werden.
Wir ergänzen daher unseren Index und fügen hinter der kundennummer noch das Feld kundenname an.
Wenn wir nun die selbe SQL Anweisung wie oben ausführen, bekommen wir einen schnelleren Zugriffsplan:
Die aufwendige Verarbeitung des Tableprobes ist komplett weggefallen. In den Erläuterungen zu dem Zugriffsplan steht auch, dass die Indexonly Methode für den Zugriff verwendet wurde.
Bei meinen Tests konnte ich eine 25% Performanceverbesserung des Query mit dem verbesserten Index gegenüber der ursprünglichen Variante feststellen.
Der Indexonly Zugriff beschleunigt nicht nur Joins sondern auch normale Zugriffe.
Das SQL:
select kundenname from kunden where kundennummer=4711
wird wenn der um kundenname erweiterte Index vorhanden ist mit einem optimierten Zugriffsplan ausgeführt.
Die Tests wurden auf einen i/5 V6R1 durchgeführt. Sollten sich aber auf anderen Systemen ebenfalls nachvollziehen lassen. Einfach einmal ausprobieren.
Sunday, May 20, 2012
Adresse mit Hilfe der Formelsprache auf Google Maps Karte zeigen.
Ich bin ja nicht gerade ein Fan der Formelsprache von Lotus Notes, aber manche Dinge lassen sich damit sehr elegant und einfach lösen. z.B. wenn man die Anforderung hat eine Adresse mittels Google maps nachzuschlagen, dann kann man folgende einfache Formel verwenden.:
@URLOpen("http://www.google.com/maps?f=q&hl=de&q="
+ @URLEncode("Platform" ; Strasse)
+ "+"
+ @URLEncode("Platform" ; Ort)+
"+"+
@URLEncode("Platform" ; Land))
Wen das aktuelle Dokument die Felder Strasse, Ort und Land (falls im Dokument nur das Länderkürzel steht muss hier noch mit einem kleinen DBLookup nachgeholfen werden) wird bei der Durchführung der Formel z.B. in einer Aktion im Defaultbrowser eine Googlemaps Karte mit einem Pin auf der gewünschten Adresse aufgemacht. Die Urlencode Formel ist wichtig, damit Sonderzeichen oder Umlaute richtig in die URL übersetzt werden. Natürlich kann man auf diese Art beliebige Urls zusammenbauen. Ich verwende das z.B. in einer Literaturdatenbank zum Anzeigen des Buches auf Amazon.
@URLOpen("http://www.google.com/maps?f=q&hl=de&q="
+ @URLEncode("Platform" ; Strasse)
+ "+"
+ @URLEncode("Platform" ; Ort)+
"+"+
@URLEncode("Platform" ; Land))
Wen das aktuelle Dokument die Felder Strasse, Ort und Land (falls im Dokument nur das Länderkürzel steht muss hier noch mit einem kleinen DBLookup nachgeholfen werden) wird bei der Durchführung der Formel z.B. in einer Aktion im Defaultbrowser eine Googlemaps Karte mit einem Pin auf der gewünschten Adresse aufgemacht. Die Urlencode Formel ist wichtig, damit Sonderzeichen oder Umlaute richtig in die URL übersetzt werden. Natürlich kann man auf diese Art beliebige Urls zusammenbauen. Ich verwende das z.B. in einer Literaturdatenbank zum Anzeigen des Buches auf Amazon.
Labels:
Formel Sprache,
Notes,
Tipp
Thursday, May 3, 2012
Lösung für Probleme mit belegten Zeiten in der busytime.nsf
Ab und zu kann es in einer Dominoumgebung passieren, dass die belegten Zeiten einer Ressource oder Person nicht mehr stimmen. z.B. das ein Besprechungsraum zu einer bestimmten Zeit als belegt gekennzeichnet ist, obwohl gar keine Reservierung in der Ressource.nsf vorliegt. Ich habe zwar den Grund dafür noch nicht gefunden, dass Problem lässt sich aber mit folgenden Befehl auf der Serverkonsole beheben:
tell rnrmgr check Testroom/TestOrganisation
Testroom ist natürlich der hierachische Name des Raums oder der Person bei der es Probleme mit der belegten Zeit gibt.
In den Version <8.0 muss der Begriff rnrmgr durch "sched" ersetzen.
Für Details siehe die IBM Knowledgebase
tell rnrmgr check Testroom/TestOrganisation
Testroom ist natürlich der hierachische Name des Raums oder der Person bei der es Probleme mit der belegten Zeit gibt.
In den Version <8.0 muss der Begriff rnrmgr durch "sched" ersetzen.
Für Details siehe die IBM Knowledgebase
Parameter an Hintergrundthread übergeben mit finalen Variablen
Ein oft übersehenes Feature in Java ist die Verwendung des Schlüsselwortes final bei der Definition einer Variablen. Prinzipiell weist die Verwendung von final den Java Compiler an, dass es sich bei der Variable um eine Konstante handelt, die nicht mehr geändert werden kann.
z.B.
Dieser Code erzeugt beim Compilieren einen Fehler, dass test nicht geändert werden darf.
Das ist sicher schon einmal ein Vorteil, da es Fehler vermeiden hilft, aber der ganz große Vorteil ist, dass wenn eine Variable final ist diese vom Compiler anders behandelt werden kann. Dies kann man sich beim Übergeben von Variablen an einen Hintergrundthread zu nutze machen.
Wir wollen eine Methode schreiben, die einen beliebigen Text beliebig oft an die Standardausgabe ausgibt und dies soll in einen Hintergrundthread passieren. Dies könnte man ungeführ wie unten codieren.
z.B.
final String test="Test"; test="test2";
Dieser Code erzeugt beim Compilieren einen Fehler, dass test nicht geändert werden darf.
Das ist sicher schon einmal ein Vorteil, da es Fehler vermeiden hilft, aber der ganz große Vorteil ist, dass wenn eine Variable final ist diese vom Compiler anders behandelt werden kann. Dies kann man sich beim Übergeben von Variablen an einen Hintergrundthread zu nutze machen.
Wir wollen eine Methode schreiben, die einen beliebigen Text beliebig oft an die Standardausgabe ausgibt und dies soll in einen Hintergrundthread passieren. Dies könnte man ungeführ wie unten codieren.
/**
* Druckt einen String mehrmals in einem Backgroundthread
*
* @param string
* @param count
* @return
*/
public static void printHelloWorld(String string, int count) {
Thread thread = new Thread() {
public void run() {
for (int i = 0; i < count; i++) { //Compilerfehler, da count nicht sichtbar.
System.out.println(string); //Compilerfehler, da string nicht sichtbar.
}
}
};
thread.start();
}
Hier wird der Compiler aber sofort anmerken, dass die Variablen "string" und "count" innerhalb des Threads nicht sichtbar sind. Wenn man die Variablen aber final definiert, dann weiß der Compiler, dass die Variablen nicht mehr geändert werden können und kann diese auch im Hintergrundthread verwenden.
/**
* Druckt einen String mehrmals in einem Backgroundthread
*
* @param string
* @param count
* @return
*/
public static void printHelloWorld(final String string, final int count) {
Thread thread = new Thread() {
public void run() {
for (int i = 0; i < count; i++) { //Jetzt ist count sichtbar, da eine finale Variable
System.out.println(string); //Jetzt ist string sichtbar, da eine finale Variable
}
}
};
thread.start();
}
Wednesday, April 25, 2012
Bilder von iPhone als Anhang im Lotus Notes Client
Seit einem Notes Update (8.5.3) hatten wir das Problem, dass Bilder die per mail von iPhones gesendet wurden nicht mehr als Dateianhang angezeigt wurden, sondern inline angezeigt wurden. Dies ist auch vom Notesclient soweit korrekt, da das iPhone die Bilder wirklich als inline schickt. Im Notes sind aber inline Bilder eher unpraktisch, da man diese nicht öffnen oder speichern kann, ausser über den Umweg der Zwischenablage.
Man kann das Anzeigen von Bildern als Inline Image in Notes aber einfach über die Einstellung
verhindern. Das bewirkt auch soweit ich bis jetzt gesehen habe keine anderen Seiteneffekte, da Bilder in HTML e-mails nach wie vor inline angezeigt werden. Der Haken im UI setzt die Notes.ini Variable ShowMIMEImagesAsAttachments=1. Man kann diese Variable natürlich auch über eine Desktop Policy auf allen Clients ausrollen.
Diese kleine Änderung kann die Userakzeptanz des Notes Client stark verbessern.
Man kann das Anzeigen von Bildern als Inline Image in Notes aber einfach über die Einstellung
verhindern. Das bewirkt auch soweit ich bis jetzt gesehen habe keine anderen Seiteneffekte, da Bilder in HTML e-mails nach wie vor inline angezeigt werden. Der Haken im UI setzt die Notes.ini Variable ShowMIMEImagesAsAttachments=1. Man kann diese Variable natürlich auch über eine Desktop Policy auf allen Clients ausrollen.
Diese kleine Änderung kann die Userakzeptanz des Notes Client stark verbessern.
Tuesday, April 24, 2012
"Recycle" ein Versuch einer Erklärung 2. Teil
Im Teil 1 haben wir geklärt, warum man Notes Objekte überhaupt recyceln muß und wie man die Session am Ende eines Programms ordentlich beendet. Bei ganz kleinen Programmen würde das auch toll funktionieren, aber sobald Programme mehr Daten verarbeiten und seien Sie sich sicher, auch wenn die Datenmenge derzeit noch überschaubar ist, irgendwann wird sie so groß, dass die verfügbaren handles oder der Speicherplatz ausgehen.
Deshalb gilt folgender Merksatz: Jedes Notesobjekt soll so rasch als möglich wieder recycelt werden. Spätestens jedoch bevor es derefenziert wird.
Ein Beispiel:
Die Variable doc ist nur innerhalb des ifs gültig und muss deshalb noch innerhalb des if's recycelt werden.
Es gibt beim Recycle jedoch eine Erleichterung, die einem einige Arbeit spart. Das recyceln von übergeordneten Objekten recycelt alle abgeleiteten Objekte mit.
Auf unser Beispiel übertragen:
Man sollte dieses implizite Recycle aber nur dann verwenden, wenn man wie in unseren Beispiel gewährleisten kann, dass nur sehr wenige Objekte erzeugt werden und diese auch nicht mit der Datenmenge mehr werden.
Fatal wäre folgender Code:
Dieser Code wird spätestens, bei ein paar Hundert Dokumenten in der View crashen.
Man muß also doc bei jedem Schleifendurchlauf recyceln. Das ist jedoch nicht ganz einfach, da doc ja nach getNextDocument nicht mehr da ist und vorher darf ich es nicht recyclen, da sonst getNextDocument() nicht mehr funktioniert, wenn das aktuelle Dokument recycelt wird. Folgendes Pattern hat sich bewährt:
Aufpassen muß man natürlich auch darauf, dass man nicht Objekte implizit bereinigt die man noch gerne verwenden möchte:
Ich hoffe etwas Licht in die Sache gebracht zu haben. Würde mich auch über Kommentare zu spezifischen Problemen freuen, die ich dann im 3. Teil behandeln werde.
Deshalb gilt folgender Merksatz: Jedes Notesobjekt soll so rasch als möglich wieder recycelt werden. Spätestens jedoch bevor es derefenziert wird.
Ein Beispiel:
if(flag)
Document doc=view.getFirstDocument();
System.out.println(doc.getItemValueString("Test");
}
Die Variable doc ist nur innerhalb des ifs gültig und muss deshalb noch innerhalb des if's recycelt werden.
if(flag){
Document doc=view.getFirstDocument();
System.out.println(doc.getItemValueString("Test");
doc.recycle();
}
Es gibt beim Recycle jedoch eine Erleichterung, die einem einige Arbeit spart. Das recyceln von übergeordneten Objekten recycelt alle abgeleiteten Objekte mit.
Auf unser Beispiel übertragen:
View view=cdb.getView("Test");
if(flag){
Document doc=view.getFirstDocument();
System.out.println(doc.getItemValueString("Test");
// doc.recycle(); kann man sich sparen, da das Dokument beim Recyclen der View mitrecycelt wird
}
else{
Document doc=view.getLastDocument();
System.out.println(doc.getItemValueString("Test");
// doc.recycle(); kann man sich sparen, da das Dokument beim Recyclen der View mitrecycelt wird
}
view.recycle();
Man sollte dieses implizite Recycle aber nur dann verwenden, wenn man wie in unseren Beispiel gewährleisten kann, dass nur sehr wenige Objekte erzeugt werden und diese auch nicht mit der Datenmenge mehr werden.
Fatal wäre folgender Code:
View view=cdb.getView("Test");
Document doc=view.getFirstDocument();
while(doc!=null){
//Mach was mit doc
doc=view.getNextDocument();
}
view.recycle();
Dieser Code wird spätestens, bei ein paar Hundert Dokumenten in der View crashen.
Man muß also doc bei jedem Schleifendurchlauf recyceln. Das ist jedoch nicht ganz einfach, da doc ja nach getNextDocument nicht mehr da ist und vorher darf ich es nicht recyclen, da sonst getNextDocument() nicht mehr funktioniert, wenn das aktuelle Dokument recycelt wird. Folgendes Pattern hat sich bewährt:
View view=cdb.getView("Test");
Document doc=view.getFirstDocument();
while(doc!=null){
//Mach was mit doc
Document tempdoc=doc;
doc=view.getNextDocument();
tempdoc.recycle();
}
view.recycle();
Aufpassen muß man natürlich auch darauf, dass man nicht Objekte implizit bereinigt die man noch gerne verwenden möchte:
View view=cdb.getView("Test");
Document doc=view.getFirstDocument();
view.recycle(); //Hier wird doc implizit mitrecycelt. Man darf doc nicht mehr verwenden.
System.out.println(doc.getItemValueString("form")); //Hier wird das Programm crashen.
Ich hoffe etwas Licht in die Sache gebracht zu haben. Würde mich auch über Kommentare zu spezifischen Problemen freuen, die ich dann im 3. Teil behandeln werde.
Thursday, April 19, 2012
Stacküberlauf beim Debuggen von Notesplugins
Wenn man Lotus Notes aus Eclipse zum Debuggen von selbsterstellten Plugins aufruft, wird das UI von Lotus Notes nicht richtig angezeigt und man bekommt einen sehr langen Stacktrace der mit
at java.util.regex.Pattern$Curly.match1(Pattern.java:3808)
at java.util.regex.Pattern$Curly.match(Pattern.java:3757)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4179)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4179)
at java.util.regex.Pattern$Curly.match0(Pattern.java:3800)
at java.util.regex.Pattern$Curly.match(Pattern.java:3755)
at java.util.regex.Pattern$Begin.match(Pattern.java:3131)
at java.util.regex.Matcher.search(Matcher.java:1116)
at java.util.regex.Matcher.find(Matcher.java:546)
at com.ibm.css.parser.CSSParserImpl.parse(CSSParserImpl.java:106)
at com.ibm.css.parser.CSSParserImpl.parse(CSSParserImpl.java:59)
at com.ibm.rcp.ui.css.StyleManager.handleRules(StyleManager.java:269)
at com.ibm.rcp.ui.css.StyleManager.handleRules(StyleManager.java:275)
at com.ibm.rcp.ui.css.StyleManager.parse(StyleManager.java:218)
at com.ibm.rcp.ui.internal.themes.ThemeManager.setCurrentTheme(ThemeManager.java:303)
at com.ibm.rcp.ui.internal.themes.ThemeManager.<init>(ThemeManager.java:187)
at com.ibm.rcp.ui.internal.themes.ThemeManager.getInstance(ThemeManager.java:216)
at com.ibm.rcp.ui.internal.themes.ThemeServiceFactory.getService(ThemeServiceFactory.java:30)
at org.eclipse.osgi.framework.internal.core.ServiceUse$1.run(ServiceUse.java:117)
at java.security.AccessController.doPrivileged(AccessController.java:202)
at org.eclipse.osgi.framework.internal.core.ServiceUse.getService(ServiceUse.java:115)
.. 51 more
endet.
Der Grund dafür ist, dass im DebugMode der Speicher auf dem Stack ausgeht. Dieses Problem kann man einfach umgehen in dem man in der Launch Configuration von Lotus Notes in Eclipse den JVM Parameter Xss1m setzt.
Folgende Schritte sind für die Änderung durchzuführen:
Den Debug Configurations Dialog über das Menü aufrufen
In der Launchconfiguration von Lotus Notes auf dem zweiten Tab "Arguments" den zusätzlichen Paramter Xss1m setzen.
Dann auf Apply drücken und die Debug Configuration starten. Dann sollte Notes ohne UI Probleme auch im Debug Mode laufen.
at java.util.regex.Pattern$Curly.match1(Pattern.java:3808)
at java.util.regex.Pattern$Curly.match(Pattern.java:3757)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4179)
at java.util.regex.Pattern$GroupHead.match(Pattern.java:4179)
at java.util.regex.Pattern$Curly.match0(Pattern.java:3800)
at java.util.regex.Pattern$Curly.match(Pattern.java:3755)
at java.util.regex.Pattern$Begin.match(Pattern.java:3131)
at java.util.regex.Matcher.search(Matcher.java:1116)
at java.util.regex.Matcher.find(Matcher.java:546)
at com.ibm.css.parser.CSSParserImpl.parse(CSSParserImpl.java:106)
at com.ibm.css.parser.CSSParserImpl.parse(CSSParserImpl.java:59)
at com.ibm.rcp.ui.css.StyleManager.handleRules(StyleManager.java:269)
at com.ibm.rcp.ui.css.StyleManager.handleRules(StyleManager.java:275)
at com.ibm.rcp.ui.css.StyleManager.parse(StyleManager.java:218)
at com.ibm.rcp.ui.internal.themes.ThemeManager.setCurrentTheme(ThemeManager.java:303)
at com.ibm.rcp.ui.internal.themes.ThemeManager.<init>(ThemeManager.java:187)
at com.ibm.rcp.ui.internal.themes.ThemeManager.getInstance(ThemeManager.java:216)
at com.ibm.rcp.ui.internal.themes.ThemeServiceFactory.getService(ThemeServiceFactory.java:30)
at org.eclipse.osgi.framework.internal.core.ServiceUse$1.run(ServiceUse.java:117)
at java.security.AccessController.doPrivileged(AccessController.java:202)
at org.eclipse.osgi.framework.internal.core.ServiceUse.getService(ServiceUse.java:115)
.. 51 more
endet.
Der Grund dafür ist, dass im DebugMode der Speicher auf dem Stack ausgeht. Dieses Problem kann man einfach umgehen in dem man in der Launch Configuration von Lotus Notes in Eclipse den JVM Parameter Xss1m setzt.
Folgende Schritte sind für die Änderung durchzuführen:
Den Debug Configurations Dialog über das Menü aufrufen
In der Launchconfiguration von Lotus Notes auf dem zweiten Tab "Arguments" den zusätzlichen Paramter Xss1m setzen.
Dann auf Apply drücken und die Debug Configuration starten. Dann sollte Notes ohne UI Probleme auch im Debug Mode laufen.
Subscribe to:
Posts (Atom)
ad







