The whole Internet is full of more or less useful tips for performance tuning on windows server. Many tips to change some mystery registry settings are not only not useful, but the can cause serious problems on your servers. Some popular performance tricks in the Internet make only sense in older releases and are obsolete in newer versions of Windows Server. You should really carefully evaluate every tip before you implement it on your production servers.
But why trust on tips from the Internet when there are very good performance tuning guidelines from the creators of Windows Server like the
Performance Tuning Guidelines for Windows Server (Windows 2008, 2008 R2, 2012)
Performance Tuning Guidelines for Windows Server 2012 R2
This guides are packed with useful tips&tricks and detailed explanations how Windows server work and which settings should be applied in different scenarios like File, Application or Web servers. My recommendation is to not change any settings on your windows server before you have read and understood the above documents!
A blog about information technology. I am especially interested in Java, Eclipse RCP, IBM Notes Domino, Db2 and IBM i
Showing posts with label Tipp. Show all posts
Showing posts with label Tipp. Show all posts
Tuesday, May 20, 2014
Tuesday, August 20, 2013
Tips for new Nokia Lumia users
I was a long time user of Nokia symbian smartphones, but after Nokia gave up Symbian i have switched to android. But now since the arrival of windows phone 8 devices Nokia has very attractive new smartphones in there portfolio again. If you are new to the Lumia world as i am, then for sure you will find the Top tips for new Lumia owners part 1 and Top tips part 2 on Nokia Conversations very interesting.
Wednesday, August 14, 2013
Show pictures in emails from iPhones as attachments and not as inline images
It is very annoying, that the iPhone send pictures in email not as attachments but as inline images. This is especially a problem when you use a client to view such a mail, because it is a little bit difficult to save inline images to your file system.
Fortunately the notes client have the setting "Show in-line MIME images as attachments" which you can find in the Preferences Dialog in the "Basic Notes Client Configuration".
When you set the above described option all pictures in e-mails from iPhone user, will be shown as attachments, which you can open in your favorite photo editor, or save to the file system. This setting will not only change the behavior for new mails, but also for old ones. So you can always uncheck the "Show inline MIME images as attachments" option and will get the old behavior back. But i am pretty sure, you will not want it back if you have tried out this setting. An example for the email with the option set:
The option in the ui sets the variable "ShowMIMEImagesAsAttachments=1" in your Notes.ini. So when you want do deploy this useful option to all your notes users, you can set the "ShowMIMEImagesAsAttachments=1" variable in the notes.ini section of your Desktop policy.
Fortunately the notes client have the setting "Show in-line MIME images as attachments" which you can find in the Preferences Dialog in the "Basic Notes Client Configuration".
When you set the above described option all pictures in e-mails from iPhone user, will be shown as attachments, which you can open in your favorite photo editor, or save to the file system. This setting will not only change the behavior for new mails, but also for old ones. So you can always uncheck the "Show inline MIME images as attachments" option and will get the old behavior back. But i am pretty sure, you will not want it back if you have tried out this setting. An example for the email with the option set:
The option in the ui sets the variable "ShowMIMEImagesAsAttachments=1" in your Notes.ini. So when you want do deploy this useful option to all your notes users, you can set the "ShowMIMEImagesAsAttachments=1" variable in the notes.ini section of your Desktop policy.
Tuesday, June 25, 2013
Trace DHCP traffic with wireshark
The best tool to analyze weird problems in DHCP Systems is the network analysator Wireshark. But the network traces of wireshark can be very big and confusing. So you have to use filters to select only the traffic you really need to solve your problem. To see only DHCP traffic on your network interface you have to apply "bootp.option.type==53" in Wireshark.
Saturday, June 8, 2013
Visual Explain explained
Visual Explain in Db2 is a great tool which shows you how the query optimizer actually processes your sql statements. It gives you every information that you need to improve your sql statements or gives you hints which indexes you should create to get a better performance. Here is an example of the output of visual explain:
Every little icon represents one process step in your query. Some of the icons are pretty clear. Everyone knows what a table scan or and index probe means. But what about the others? The online help of Visual explain is not really helpfull, because there are only very short descriptions of every icon. But fortunatly there is a detailed description with examples of every access method the query optimizer can choose to process your sql statements in the IBM i information center. If you prefer to read this informations on paper you can download a PDF from http://pic.dhe.ibm.com/infocenter/iseries/v7r1m0/topic/rzajq/rzajq.pdf
Saturday, May 25, 2013
Howto make regular expressions caseinsensitive
Regular expression are very useful for string operations, but one annoying thing is that regular expressions are normally case sensitive. But with a simple option you can change this default behavior. You only have to add the "(?i)" clause to your regular expression. Here is an example:
But be aware, that the "(?i)" clause does only work for ASCII strings. If you have international characters in your regular expressions you have to add the "u" flag to your regex.
String test = "The lazy brown fox jumps over the quick Dog"; // The following command will not replace Dog, because the regex is not // case insensitive. System.out.println(test.replaceAll("dog", "cat")); // With (?i) added the regex will ignore case and Dog will be replaced // by cat. System.out.println(test.replaceAll("(?i)dog", "cat"));
But be aware, that the "(?i)" clause does only work for ASCII strings. If you have international characters in your regular expressions you have to add the "u" flag to your regex.
String test = "Äpfel und Birnen"; // The following command will not replace Äpfel, because the regex is // not unicode aware. System.out.println(test.replaceAll("(?i)äpfel", "Zitronen")); // With (?iu) added the regex is unicode aware and Äpfel will be // replaced by Zitronen. System.out.println(test.replaceAll("(?iu)äpfel", "Zitronen"));
Sunday, April 14, 2013
Improve your Domino Server Performance on the System i
On Windows it is pretty clear that Domino Servers only perform well, when the admin regulary defragment the file system where the Domino data is stored. Unfortunatly many System i admins do not know that fragmentation of Domino databases is a problem on their system too. So they do not get the best performance possible and with every year of using the server the problem of framgentation gets bigger and bigger.
The defragmentation of the disks in a System i Server can be done with the command STRDSKRGZ.
So login into your System i with a 5250 Terminal client and execute the STRDSKRGZ command:
The defragmentation of the disks in a System i Server can be done with the command STRDSKRGZ.
So login into your System i with a 5250 Terminal client and execute the STRDSKRGZ command:
Labels:
Admin,
Domino,
Notes,
Performance,
Tipp
Thursday, April 11, 2013
Howto split a String with a delimiter in SQL
Today i want to show how to split a String with a delimiter in SQL for example in a table with modelnumbers which consists of two parts sperated by a slash.
model
A1/44
CX3/2
C/140
To get the first and second part of the modelnumber you can use
select LEFT( trim(model),LENGTH(trim(model))-ABS(LOCATE('/',trim(model))-1)) model1, RIGHT( trim(model), LENGTH(trim(model))-LOCATE('/',trim(model))) model2 from modeltable
to get the result:
model1 model2
A1 44
CX3 2
C 140
model
A1/44
CX3/2
C/140
To get the first and second part of the modelnumber you can use
select LEFT( trim(model),LENGTH(trim(model))-ABS(LOCATE('/',trim(model))-1)) model1, RIGHT( trim(model), LENGTH(trim(model))-LOCATE('/',trim(model))) model2 from modeltable
to get the result:
model1 model2
A1 44
CX3 2
C 140
Thursday, April 4, 2013
Cool tool to analyze TCP Port activity
Windows has a command line tool to monitor which ports are used by which process called "netstat". But this tool is not very easy to use and on some operations very slow. But fortunatetly the genius guys from Sysinternals provide the great tool TCPView for this task. With this tool you see a overview of all used tcp ports and their status. So for example you can easily find out which process listens on which ports. You can even kill processes to free the ports in this tool.
Tuesday, April 2, 2013
IBM website does not render properly in Firefox with Hardware Acceleration enabled
Newer Firefox (e.g. the newest ESR) versions can not render the IBM support website correctly. Many parts of the website are invisible and will show only sporadic on scrolling.
I can reproduce this problem on different workstations with different hardware and even on the newest non ESR Version of Firefox. But it is not reproducable in virtual machines. This is a serious problem, because it is impossible to work without the IBM support site. Our first workaround for this was to use Internetexplorer :-((. But now our PC support team has found out, that the problem is related to the hardware acceleration of Firefox. When you disable the hardware acceleration then the IBM site is working as expected again.
I can reproduce this problem on different workstations with different hardware and even on the newest non ESR Version of Firefox. But it is not reproducable in virtual machines. This is a serious problem, because it is impossible to work without the IBM support site. Our first workaround for this was to use Internetexplorer :-((. But now our PC support team has found out, that the problem is related to the hardware acceleration of Firefox. When you disable the hardware acceleration then the IBM site is working as expected again.
Saturday, February 16, 2013
Lotusscript Code aus Java plugin aufrufen
In bestehenden Notesanwendungen steckt jede Menge Lotusscript Code der über viele Jahre aufwendig entwickelt wurde, deshalb möchte man bei der Entwicklung von Plugins nicht das Rad neu erfinden, sondern bestehenden Code auch aus Eclipse plugins aufrufen. Wie dies geht möchte ich heute gerne zeigen:
Als erstes muss man die Notes API (com.ibm.notes.java.api und com.ibm.java.ui) dem Plugin als Abhängigkeit hinzufügen.
Als Beispiel habe ich eine scriptlibrary mit einer Funktion getUmsatz mit den Parametern Kundennummer und Jahr hergenommen. In der Funktion der Scriptlibrary werden aufwendige Datenbankzugriffe und Berechnungen durchgeführt, die wir in java nicht nachprogrammieren wollen.
Da man von Java nicht direkt auf die Library zugreifen kann, braucht man als erstes einen kleinen Agent der als Brücke zwischen dem Plugin und der Scriptlibrary fungiert.
Der Agent macht nichts anderes, als dass er ein in Memory Dokument über den Dokumentcontext holt. Die Aufrufparameter für die getUmsatz Funktion ausliest und das Ergebnis der Funktion in der Variable Umsatz speichert. Natürlich konnte man den Agent auch dahingehend erweitern, dass in dem in Memory Dokument auch ein Parameter für die auzurufende Funktion mitgegeben wird und er dann die richtige Funktion aus der Scriptlibrary aufruft.
Wichtig bei dem Agent ist, dass man das Ziel auf "None" setzt. Sonst funktioniert der Zugriff auf das übergebene Dokument nicht zuverlässig.
Der Javateil ist etwas aufwendiger:
Als erstes muss man die Notes API (com.ibm.notes.java.api und com.ibm.java.ui) dem Plugin als Abhängigkeit hinzufügen.
Als Beispiel habe ich eine scriptlibrary mit einer Funktion getUmsatz mit den Parametern Kundennummer und Jahr hergenommen. In der Funktion der Scriptlibrary werden aufwendige Datenbankzugriffe und Berechnungen durchgeführt, die wir in java nicht nachprogrammieren wollen.
Da man von Java nicht direkt auf die Library zugreifen kann, braucht man als erstes einen kleinen Agent der als Brücke zwischen dem Plugin und der Scriptlibrary fungiert.
Option Public Option Declare Use "UmsatzScriptLibrary" Sub Initialize Dim ses As New NotesSession Dim context As NotesDocument Set context=ses.Documentcontext Call context.Replaceitemvalue("umsatz", getUmsatz(context.Getitemvalue("kundenNummer")(0), context.getItemValue("jahr")(0))) Print context.Getitemvalue("umsatz")(0) context.save True,false End Sub
Der Agent macht nichts anderes, als dass er ein in Memory Dokument über den Dokumentcontext holt. Die Aufrufparameter für die getUmsatz Funktion ausliest und das Ergebnis der Funktion in der Variable Umsatz speichert. Natürlich konnte man den Agent auch dahingehend erweitern, dass in dem in Memory Dokument auch ein Parameter für die auzurufende Funktion mitgegeben wird und er dann die richtige Funktion aus der Scriptlibrary aufruft.
Wichtig bei dem Agent ist, dass man das Ziel auf "None" setzt. Sonst funktioniert der Zugriff auf das übergebene Dokument nicht zuverlässig.
Der Javateil ist etwas aufwendiger:
public static void berechneKundenUmsatz(String kundenNummer, int jahr) { try { // Starte den Zugriff auf den Workspace und erstelle ein // NotesAgentDataobjekt mit unserem Brückenagent. NotesUIWorkspace ws = new NotesUIWorkspace(); NotesAgentData data = new NotesAgentData(new NotesDatabaseData("", "test.nsf"), "agent"); // Füge die Aufrufparameter für die Scriptlibrary dem data Objekt // hinzu. Diese werden später im documentcontext als Items // verfügbar. data.addItem("kundenNummer", kundenNummer); data.addItem("jahr", new Integer(jahr).toString()); // Erstelle ein Callback Objekt. die Methode done dieses Objekts // wird nach Ausführung des Brücken Agent aufgerufen. NotesDocumentDataCallback callBack = new NotesDocumentDataCallback() { @Override public void done(final NotesDocumentDataEvent event) { // Erstelle einen Notessessionjob in dem wir auf das // zurückgegebene Dokument zugreifen können. NotesSessionJob job = new NotesSessionJob( "verarbeite Ergebnis") { @Override protected IStatus runInNotesThread(Session session, IProgressMonitor arg1) throws NotesException { // Lade das Dokument, dass der Agent mit dem // Ergebnis befüllt hat. Document doc = event.getDocumentData() .open(session); // Speichere das Resultat in einer Finalen Variable, // dass wir es im UIThread weiterverwenden können. final double result = doc .getItemValueDouble("umsatz"); // Mache irgendetwas im UI mit dem Resultat. In // unserem Beispiel eine Dialogbox anzeigen. Display.getDefault().asyncExec(new Runnable() { @Override public void run() { MessageBox box = new MessageBox(PlatformUI .getWorkbench() .getActiveWorkbenchWindow() .getShell()); box.setMessage("Das Ergebnis ist: " + result); box.open(); } }); return Status.OK_STATUS; } }; // starte den Notesjob job.schedule(); } }; // Führe den Agent mit dem data und callback Objekt aus. Der letzte // Parameter bedeutet, das der UIContext keine Rolle spielt. Das // heißt es ist egal auf welches Dokument im UI derzeit geöffnet // ist. ws.runAgent(data, callBack, false); } catch (NotesException e) { e.printStackTrace(); } }Das ist jetzt natürlich nur ein kleines Beispiel, bei dem der Aufwand vielleicht nicht dafür steht, aber in dem Lotusscript agent kann auch auf das UI zugegriffen werden. Das heißt der Agent kann Dialoge anzeigen und er kann auch mehrere Werte oder eine ganze Liste als Ergebnis zurückliefern. Damit kann man auch bei der Entwicklung von Plugins sehr leicht bestehenden Code wieder verwenden.
Wednesday, February 6, 2013
Experience Webseite der IBM wurde für Version 9 aktualisiert
Die IBM hat eine sehr schöne Webseite über die neuen Funktionen und die Vorteile von Notes 9 gegenüber anderen e-mail Systemen zusammengestellt.
Für weitere Infos zur neuen Version schauen Sie auch auf meine Übersicht über alle Postings zum Thema Notes/Domino 9
Für weitere Infos zur neuen Version schauen Sie auch auf meine Übersicht über alle Postings zum Thema Notes/Domino 9
Monday, February 4, 2013
Lösen von Notes Performanceproblemen mit dem NRPC Parser
Der Notes Client besitzt eine eingebaute Tracefunktion um die NRPC (Notes Remote Procedure Call) Kommunikation zwischen einem Client und dem Server zu tracen. Leider ist das Log, dass diese Tracefunktionalität zur Verfügung stellt, etwas unübersichtlich und kryptisch. Jedoch gibt es auf OpenNTF eine Datenbank mit der man die Analyse vereinfachen kann.
Hier die Schritte um eine Performanceanalyse mit der Datenbank durchzuführen:
Downloaden Sie den NRPC Parser von OpenNTF und signieren Sie die Datenbank mit einer Developer id, damit Sie keine Probleme mit der ECL haben.
Öffnen Sie die Parserdatenbank und klicken Sie auf die
Schaltfläche. Damit werden in Ihrer notes.ini die Einträge
Jetzt muss der Notesclient neu gestart werden und man kann die Funktion in Notes durchführen mit der man ein Performanceproblem hat. z.B. eine Datenbank öffnen, oder ein Dokument aufmachen.
Danach sollte man die Notes.ini Einträge mit
wieder deaktivieren und den Notesclient neu starten.
Danach kann man mit der Schaltfläche
die erstellte Datei analysieren lassen und bekommt dann für jeden Aufruf einer Funktion auf dem Server eine Zeile in der genau steht was gemacht wurde, wie lange dieser Aufruf gedauert hat und wieviele Daten vom Server gesendet und empfangen wurden.
Aufwendige Operationen sind rot markiert. Die Spalte Sent gibt die Datenmenge in Bytes an die der Server gesendet hat. Die Spalte Rec'd gibt an, wieviel Daten der Server vom Client empfangen hat.
Update 11.11.2013 Wie in den Kommentaren angeführt hat Andrew Magerman eine neue Version des NRPC Parser veröffentlicht, die jetzt auch mit aktuellen Version von Notes korrekt funktioniert. Die Angabe von Debug_ThreadID=0 die man in älteren Versionen des NRPC Parsers benötigte ist daher nicht mehr notwendig. Vielen Dank für dieses Update und das fantastische Tool.
Hier die Schritte um eine Performanceanalyse mit der Datenbank durchzuführen:
Downloaden Sie den NRPC Parser von OpenNTF und signieren Sie die Datenbank mit einer Developer id, damit Sie keine Probleme mit der ECL haben.
Öffnen Sie die Parserdatenbank und klicken Sie auf die
Schaltfläche. Damit werden in Ihrer notes.ini die Einträge
- Client_Clock=1
- Debug_Console=1
- Debug_Outfile=c:\Program Files (x86)\IBM\Lotus\Notes\Data\RPC.txt
- CONSOLE_LOG_ENABLED=1
Jetzt muss der Notesclient neu gestart werden und man kann die Funktion in Notes durchführen mit der man ein Performanceproblem hat. z.B. eine Datenbank öffnen, oder ein Dokument aufmachen.
Danach sollte man die Notes.ini Einträge mit
wieder deaktivieren und den Notesclient neu starten.
Danach kann man mit der Schaltfläche
die erstellte Datei analysieren lassen und bekommt dann für jeden Aufruf einer Funktion auf dem Server eine Zeile in der genau steht was gemacht wurde, wie lange dieser Aufruf gedauert hat und wieviele Daten vom Server gesendet und empfangen wurden.
Aufwendige Operationen sind rot markiert. Die Spalte Sent gibt die Datenmenge in Bytes an die der Server gesendet hat. Die Spalte Rec'd gibt an, wieviel Daten der Server vom Client empfangen hat.
Update 11.11.2013 Wie in den Kommentaren angeführt hat Andrew Magerman eine neue Version des NRPC Parser veröffentlicht, die jetzt auch mit aktuellen Version von Notes korrekt funktioniert. Die Angabe von Debug_ThreadID=0 die man in älteren Versionen des NRPC Parsers benötigte ist daher nicht mehr notwendig. Vielen Dank für dieses Update und das fantastische Tool.
Monday, January 14, 2013
Notes 9 Verbesserung beim e-mail typeahead
Das Typeahead bei e-mail Adressfeldern ist eine sehr praktische Sache, aber seit Einführung dieser Funktion stört mich die Tatsache, dass immer zuerst die lokalen Adressbücher vor den Serveradressbüchern durchsucht werden, obwohl davon auszugehen ist, dass die Serveradressbücher im Normalfall die viel akuraten Informationen enthalten. Mit Notes 9 wurde nun eine neue notes.ini Variable (TypeaheadShowServerFirst=1) eingeführt mit der man dieses Verhalten umkehren kann.
Ohne TypeaheadShowServerFirst=1
Mit TypeaheadShowServerFirst=1
Die Notes.ini Variable kann natürlich auch über eine Desktoppolicy gesetzt werden. Leider gibt es jedoch keine Benutzerschnittstelle für diese meiner Meinung nach extrem wichtige Einstellung.
Laut Doku in der Version 9 soll diese Variable auch in 8.5.3 funktionieren. In meinem 8.5.3 FP1 Client hat die Variable jedoch keine Funktion.
Für weitere Infos zur neuen Version schauen Sie auch auf meine Übersicht über alle Postings zum Thema Notes/Domino 9
Ohne TypeaheadShowServerFirst=1
Mit TypeaheadShowServerFirst=1
Laut Doku in der Version 9 soll diese Variable auch in 8.5.3 funktionieren. In meinem 8.5.3 FP1 Client hat die Variable jedoch keine Funktion.
Für weitere Infos zur neuen Version schauen Sie auch auf meine Übersicht über alle Postings zum Thema Notes/Domino 9
Thursday, January 10, 2013
Zugriff auf die Hard und Softwarekonfiguration über WMI mittels Lotus Script
Unter Windows gibt es mit dem Windows Management Instrumentation ein sehr mächtiges Werkzeug mit dem man auf diverse Hardware und Software Informationen in Windows zugreifen, bzw mit dem man auch administrative Dinge erledigen kann. Normalerweise verwendet man WMI aus einem vb oder aus einem Powershell script.
Heute möchte ich aber zeigen, dass man den selben Mechanismus auch bequem von Lotus script für die Beschaffung von diversen Infos verwenden kann. Als Beispiel möchte ich einen Agenten anführen, der z.B. die derzeitige Bildschirmauflösung ausliest. Eventuell will man ja in einem Notesscript je nach verwendeter Bildschirmauflösung verschiedene Framesets anzeigen.
02-04 die verwendeten Variablen werden definiert.
05 Mit WMI kann man auch auf Remotecomputer zugreifen. Im Normalfall will man jedoch auf seinen eigenen Computer zugreifen, was man durch den Punkt erreichen kann.
06 Das WMI Service Objekte wird instantiert.
07 WMI stellt die Informationen in einer Datenbank ähnlichen Struktur zur Verfügung die mit einer an SQL angelehnten Syntax abgefragt werden kann. Ich komme dann noch später dazu wie man auf diese SQL Kommandos kommt.
08-11 Mittels einer Forall Schleife werden alle Sätze gelesen. Normalerweise sollte hier nur ein Satz zurückgegeben werden, ausser der Benutzer hat mehrere Monitore;-)
Obiges Gerüst kann man natürlich nicht nur für den obigen Zweck verwenden sondern mit den richtigen WMI SQL's kann man praktisch auf jede Info die in Windows gespeichert ist zugreifen. Um den Querystring zusammenzubauen kann man entweder die Doku in der MSDN durcharbeiten oder besser auf den genialen WMI Code Creator zurückgreifen.
Mit dem kann man sich bequem die Informationen zusammenklicken und bekommt dann den Code in vbscript angezeigt. Mittels diesen Infos kann man dann oben angeführtes Lotus Script Beispiel überarbeiten und auf die gewünschten Infos zugreifen.
Heute möchte ich aber zeigen, dass man den selben Mechanismus auch bequem von Lotus script für die Beschaffung von diversen Infos verwenden kann. Als Beispiel möchte ich einen Agenten anführen, der z.B. die derzeitige Bildschirmauflösung ausliest. Eventuell will man ja in einem Notesscript je nach verwendeter Bildschirmauflösung verschiedene Framesets anzeigen.
Sub Initialize Dim objWMIService As Variant Dim colItems as Variant Dim strComputer As String strComputer="." Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\CIMV2") Set colItems = objWMIService.ExecQuery("SELECT * FROM Win32_DesktopMonitor",,48) Forall objItem In colItems print "Monitor Höhe:" & objItem.ScreenHeight Print "Monitor Breite:" & objItem.ScreenWidth End forall End Sub
02-04 die verwendeten Variablen werden definiert.
05 Mit WMI kann man auch auf Remotecomputer zugreifen. Im Normalfall will man jedoch auf seinen eigenen Computer zugreifen, was man durch den Punkt erreichen kann.
06 Das WMI Service Objekte wird instantiert.
07 WMI stellt die Informationen in einer Datenbank ähnlichen Struktur zur Verfügung die mit einer an SQL angelehnten Syntax abgefragt werden kann. Ich komme dann noch später dazu wie man auf diese SQL Kommandos kommt.
08-11 Mittels einer Forall Schleife werden alle Sätze gelesen. Normalerweise sollte hier nur ein Satz zurückgegeben werden, ausser der Benutzer hat mehrere Monitore;-)
Obiges Gerüst kann man natürlich nicht nur für den obigen Zweck verwenden sondern mit den richtigen WMI SQL's kann man praktisch auf jede Info die in Windows gespeichert ist zugreifen. Um den Querystring zusammenzubauen kann man entweder die Doku in der MSDN durcharbeiten oder besser auf den genialen WMI Code Creator zurückgreifen.
Mit dem kann man sich bequem die Informationen zusammenklicken und bekommt dann den Code in vbscript angezeigt. Mittels diesen Infos kann man dann oben angeführtes Lotus Script Beispiel überarbeiten und auf die gewünschten Infos zugreifen.
Wednesday, January 9, 2013
Detail Formatter erleichtern das Debuggen in Eclipse
Wer kennt nicht diese ärgerlichen Klassen, die toString() nicht überschreiben und deshalb im Debugger keine vernünftigen Informationen zu Objekten dieser Klassen angezeigt werden.
Man sieht hier auf den ersten Blick nur, dass das eine Objekt die id 18 hat und das andere die id 31. Erst wenn man das Objekt aufklappt, wird einem eine unter Umständen lange und unübersichtliche Liste aller Felder dieses Objekts angezeigt. Bei eigenen Klassen kann man die fehlende toString() Methode ja noch nachrüsten, aber bei fremden Klassen wäre man verloren wenn es nicht die "Detail Formatter" Funktion von Eclipse geben würde.
Einfach einen Rechtsklick auf das Objekt für den man einen Formater erstellen und die Funktion "New Detail Formatter" aufrufen.
Jetzt kann man den Javacode angeben, der den String berechnet, den man gerne als Anzeige für diese Klasse im Debugger haben möchte. In meinen Fall hätte ich gerne für jedes Person Objekt den Vor und Nachname angezeigt.
Schon haben wir in der Detailanzeige des Debuggers nicht mehr die Objektid sondern schon unseren schönen aussagekräftigen Inhalt.
Immer noch nicht ganz ideal, den viel schöner wäre wenn man nicht auf eine Zeile klicken müsste, sondern wenn gleich unter Value der berechnete Wert stehen würde. Aber auch dafür bietet Eclipse eine Lösung. Unter Preferences->Java->Debug->Detail Formatters kann man die Option "As the label for variables with detail formatters" auswählen und schon wird der berechnete Text auch in der Value Spalte angezeigt.
Die Detail Formatters bleiben persistent, das heißt sobald ich mir diesen einmal für eine Klasse erstellt habe, wird dieser in jeder Debugsession von Eclipse verwendet. Ich muss also jeden "Detail Formater" nur einmal definieren.
Man sieht hier auf den ersten Blick nur, dass das eine Objekt die id 18 hat und das andere die id 31. Erst wenn man das Objekt aufklappt, wird einem eine unter Umständen lange und unübersichtliche Liste aller Felder dieses Objekts angezeigt. Bei eigenen Klassen kann man die fehlende toString() Methode ja noch nachrüsten, aber bei fremden Klassen wäre man verloren wenn es nicht die "Detail Formatter" Funktion von Eclipse geben würde.
Einfach einen Rechtsklick auf das Objekt für den man einen Formater erstellen und die Funktion "New Detail Formatter" aufrufen.
Jetzt kann man den Javacode angeben, der den String berechnet, den man gerne als Anzeige für diese Klasse im Debugger haben möchte. In meinen Fall hätte ich gerne für jedes Person Objekt den Vor und Nachname angezeigt.
Schon haben wir in der Detailanzeige des Debuggers nicht mehr die Objektid sondern schon unseren schönen aussagekräftigen Inhalt.
Immer noch nicht ganz ideal, den viel schöner wäre wenn man nicht auf eine Zeile klicken müsste, sondern wenn gleich unter Value der berechnete Wert stehen würde. Aber auch dafür bietet Eclipse eine Lösung. Unter Preferences->Java->Debug->Detail Formatters kann man die Option "As the label for variables with detail formatters" auswählen und schon wird der berechnete Text auch in der Value Spalte angezeigt.
Die Detail Formatters bleiben persistent, das heißt sobald ich mir diesen einmal für eine Klasse erstellt habe, wird dieser in jeder Debugsession von Eclipse verwendet. Ich muss also jeden "Detail Formater" nur einmal definieren.
Thursday, December 27, 2012
Hochperformante und sichere SQL Zugriffe in Java
Beim Zugriff auf SQL Datenbanken wird immer gerne der Fehler gemacht, dass wenn ein SQL Statement mehrmals mit verschiedenen Parametern ausgeführt werden soll nicht die dafür vorgesehenen PreparedStatements sondern die SQL Befehle mit String Konkatinierung zusammengebaut und mit execute() ausgeführt werden. Sogar in Java Lehrbüchern findet man immer wieder Beispiele wie das folgende, dass man aber in der Praxis auf keinen Fall so verwenden sollte.
Es gibt zwei Gründe warum man seinen SQL Code nicht jedes mal als String zusammenbauen und dann mit execute() ausführen soll.
Bei wiederholter Ausführung des selben SQL Code ist die Performance viel besser, wenn der SQL Code nicht jedesmal geparst, geprüft und in einen Zugriffsplan übersetzt werden muß. Der Vorgang ein SQL Kommando in einen Zugriffsplan zu übersetzen ist je nach verwendeter Datenbank und Komplexität der Anweisung extrem aufwendig. Der oben angeführte Codeblock in dem die Zeit gemessen wird, läuft wenn man Preparedstatements verwendet, ca. 3 mal schneller als mit dem oben angeführten Code.
Was aber fast noch wichtiger ist, wenn ich SQL Befehle mit String Konkatinierung zusammenbaue, dann wird der Code anfällig für SQL Injections. Das heißt, es kann in der Variable mit ein paar Tricks beliebiger SQL Code eingeschleust werden. Dies ist eine der häufigsten Einfallstore für Hacks auf Webseiten. Also selbst wenn ein Statement nur einmal verwendet wird, sollte man auf jeden Fall um SQL Injections zu vermeiden Preparedstatements verwenden.
Noch dazu ist die Verwendung von Preparedstatements eigentlich extrem einfach. Man ändert den Typ von stmt auf PreparedStatement, und erstellt das Objekt mit prepareStatement(). Für jeden Wert der in der Anweisung variabel sein soll fügt man ein Fragezeichen ein. Der sqlCode aus obigen Beispiel heißt dann "select * from adressen where adnr=?". Bei jeder Verwendung der SQL Anweisung muss dann mit der passenden set Methode der Platzhalter im Statement mit dem richtigen Wert befüllt werden. Am leichtesten zu verstehen ist es wenn man sich folgendes Beispiel anschaut.
Die Preparedstatements können natürlich nicht nur für "Selects", sondern genauso gut auch für "Inserts" und "Updates" verwendet werden.
Wer JDBC Zugriffe in seinen xPages, Plugins oder Agenten verwendet, sollte prüfen ob er auch wirklich überall schon PreparedStatements verwendet. Der Performancegewinn und vor allem die zusätzliche Sicherheit vor SQL Injections sollte den geringen Änderungsaufwand auf jeden Fall lohnen.
public class StatementJDBC { private static Statement stmt; /** * @param args */ public static void main(String[] args) { //Verbinde mit Datenbank und initalisiere Anweisung AS400JDBCDataSource dataSource = new AS400JDBCDataSource("localhost", "user", "password"); try { Connection con=dataSource.getConnection(); stmt=con.createStatement(); //Gib verschiedene Namen aus der Adressdatei mit verschiedenen Adressnummern aus. Date start=new Date(); System.out.println(getName("40")); System.out.println(getName("41")); System.out.println(getName("42")); System.out.println(getName("43")); System.out.println(new Date().getTime()-start.getTime()); } catch (SQLException e) { e.printStackTrace(); } } /** * Liest mittels SQL den Namen eines Adressatzes. * * Hier wird jedes mal ein SQLStatement mit String Konkatinierung zusammengebaut * und ausgeführt. * * Dies soll man in der Praxis nicht machen. * @param adressNummer * @return Name */ private static String getName(String adressNummer) throws SQLException { ResultSet rs=stmt.executeQuery("select * from adressen where adnr="+adressNummer); if(rs.next()) return rs.getString("adnam1"); return ""; } }
Es gibt zwei Gründe warum man seinen SQL Code nicht jedes mal als String zusammenbauen und dann mit execute() ausführen soll.
Bei wiederholter Ausführung des selben SQL Code ist die Performance viel besser, wenn der SQL Code nicht jedesmal geparst, geprüft und in einen Zugriffsplan übersetzt werden muß. Der Vorgang ein SQL Kommando in einen Zugriffsplan zu übersetzen ist je nach verwendeter Datenbank und Komplexität der Anweisung extrem aufwendig. Der oben angeführte Codeblock in dem die Zeit gemessen wird, läuft wenn man Preparedstatements verwendet, ca. 3 mal schneller als mit dem oben angeführten Code.
Was aber fast noch wichtiger ist, wenn ich SQL Befehle mit String Konkatinierung zusammenbaue, dann wird der Code anfällig für SQL Injections. Das heißt, es kann in der Variable mit ein paar Tricks beliebiger SQL Code eingeschleust werden. Dies ist eine der häufigsten Einfallstore für Hacks auf Webseiten. Also selbst wenn ein Statement nur einmal verwendet wird, sollte man auf jeden Fall um SQL Injections zu vermeiden Preparedstatements verwenden.
Noch dazu ist die Verwendung von Preparedstatements eigentlich extrem einfach. Man ändert den Typ von stmt auf PreparedStatement, und erstellt das Objekt mit prepareStatement(). Für jeden Wert der in der Anweisung variabel sein soll fügt man ein Fragezeichen ein. Der sqlCode aus obigen Beispiel heißt dann "select * from adressen where adnr=?". Bei jeder Verwendung der SQL Anweisung muss dann mit der passenden set Methode der Platzhalter im Statement mit dem richtigen Wert befüllt werden. Am leichtesten zu verstehen ist es wenn man sich folgendes Beispiel anschaut.
public class PreparedStatementJDBC { private static PreparedStatement stmt; /** * @param args */ public static void main(String[] args) { //Verbinde mit Datenbank und initalisiere Anweisung AS400JDBCDataSource dataSource = new AS400JDBCDataSource("localhost", "user", "password"); try { Connection con=dataSource.getConnection(); stmt=con.prepareStatement("select * from adressen where adnr=?"); //Gib verschiedene Namen aus der Adressdatei mit verschiedenen Adressnummern aus. Date start=new Date(); System.out.println(getName("40")); System.out.println(getName("41")); System.out.println(getName("42")); System.out.println(getName("43")); System.out.println(new Date().getTime()-start.getTime()); } catch (SQLException e) { e.printStackTrace(); } } /** * Liest mittels SQL den Namen eines Adressatzes. * @param adressNummer * @return Name */ private static String getName(String adressNummer) throws SQLException { //Parameter im vorbereiteten Statement setzen. stmt.setInt(1, new Integer(adressNummer).intValue()); ResultSet rs=stmt.executeQuery(); if(rs.next()) return rs.getString("adnam1"); return ""; } }
Die Preparedstatements können natürlich nicht nur für "Selects", sondern genauso gut auch für "Inserts" und "Updates" verwendet werden.
Wer JDBC Zugriffe in seinen xPages, Plugins oder Agenten verwendet, sollte prüfen ob er auch wirklich überall schon PreparedStatements verwendet. Der Performancegewinn und vor allem die zusätzliche Sicherheit vor SQL Injections sollte den geringen Änderungsaufwand auf jeden Fall lohnen.
Friday, December 14, 2012
"equal" vs "==" in Java
Ein typischer Anfängerfehler in Java ist, zwei Objekte in einer if Klausel mit "==" statt mit .equals() zu vergleichen. Dies ist aber in den meisten Fällen grundfalsch. Das tückische dabei ist, dass der Fehler nicht immer sofort auffällt, da unter manchen Umständen der Vergleich mit "==" auch funktioniert.
Um zu verstehen warum die beiden Vergleiche unterschiedlich sind, muss man zuerst wissen, wie Java eigentlich Objekte verwaltet. Wenn mit new ein neues Objekt erzeugt wird und einer Variable zugewiesen wird, wird nicht das Objekt in der Variable gespeichert, sondern das Objekt wird am Heap (Hauptspeicher) erzeugt und ein Zeiger auf die Stelle im Heap an der das Objekt gespeichert ist, wird der Variable zugewiesen. Man kann sich sozusagen die Variable als einen primitiven Datentyp vorstellen, der eine Referenz auf den Heap speichert. Mehrere Variablen können die selbe Referenz auf das selbe Objekt im Heap zugewiesen haben. Wenn nun mit "==" verglichen wird, wird das Objekt im Heap gar nicht angeschaut, sondern es wird nur verglichen, ob die Variable die gleiche Referenz enthält. Wenn ja wird true zurückgeliefert und wenn nein wird false zurückgeliefert. Ganz anders verhält es sich beim equals(). Hier müssen die Objekte nicht einmal vom gleichen Typ sein, sondern es kommt auf die Implementierung der "equals" Methode an, ob das Ergebnis true oder false ist. Im Normalfall wird man immer mit equals() vergleichen, da ich im Normalfall wissen will, ob es sich um ein logisch gleiches Objekt handelt und nicht um das selbe Objekt. Wenn alles so klar ist, warum funktioniert dann folgender Code:
Um zu verstehen warum die beiden Vergleiche unterschiedlich sind, muss man zuerst wissen, wie Java eigentlich Objekte verwaltet. Wenn mit new ein neues Objekt erzeugt wird und einer Variable zugewiesen wird, wird nicht das Objekt in der Variable gespeichert, sondern das Objekt wird am Heap (Hauptspeicher) erzeugt und ein Zeiger auf die Stelle im Heap an der das Objekt gespeichert ist, wird der Variable zugewiesen. Man kann sich sozusagen die Variable als einen primitiven Datentyp vorstellen, der eine Referenz auf den Heap speichert. Mehrere Variablen können die selbe Referenz auf das selbe Objekt im Heap zugewiesen haben. Wenn nun mit "==" verglichen wird, wird das Objekt im Heap gar nicht angeschaut, sondern es wird nur verglichen, ob die Variable die gleiche Referenz enthält. Wenn ja wird true zurückgeliefert und wenn nein wird false zurückgeliefert. Ganz anders verhält es sich beim equals(). Hier müssen die Objekte nicht einmal vom gleichen Typ sein, sondern es kommt auf die Implementierung der "equals" Methode an, ob das Ergebnis true oder false ist. Im Normalfall wird man immer mit equals() vergleichen, da ich im Normalfall wissen will, ob es sich um ein logisch gleiches Objekt handelt und nicht um das selbe Objekt. Wenn alles so klar ist, warum funktioniert dann folgender Code:
String test1="Test"; String test2="Test"; System.out.println(test1==test2); //Bitte auf keinen Fall so machen System.out.println(test1.equals(test2); //So vergleicht man richtig.Im Normalfall würde man erwarten, da man zwei String Literale hat, dass der erste Vergleich false ergeben würde. Doch die JVM verwendet für Stringliterale einen Cache und so wird der zweite Literal wegoptimiert und beide Variablen verweisen auf das selbe Objekt im String Cache. Nur sollte man sich auf keinen Fall auf das verlassen, da eine andere JVM Implementierung auf diesen Cache eventuell verzichtet, oder der Cache bereits voll ist und dann hat man plötzlich zwei unterschiedliche Objekte und der erste Vergleich ergibt false.
Thursday, December 6, 2012
System.out Ausgaben in eine Datei umleiten
Manchmal hat man Java Programme, die statt einem Loggingframework alle Statusausgaben mit System.out.println() machen. Wenn nun so ein Programm während der Ausführung abstürzt hat man natürlich nicht mehr viel von den Statusmeldungen. Wenn ich so ein Javaprogramm habe, mache ich einfach eine kleine Wrapperklasse darum, mit der die Standardausgabe in eine Datei umgeleitet wird.
Ein kleines Beispiel:
Ein kleines Beispiel:
public class LogginWrapper { /** * @param args */ public static void main(String[] args) { // Leite die Ausgabe von Standard Out und ERR in Log Dateien um try { System.setOut(new PrintStream(new FileOutputStream(System.getenv("TEMP") + File.separator + "$$log" + new Date().getTime() + ".out"))); System.setErr(new PrintStream(new FileOutputStream(System.getenv("TEMP") + File.separator + "$$log" + new Date().getTime() + ".err"))); } catch (FileNotFoundException e) { e.printStackTrace(); } // Aufruf des Programms ohne Loggingframework. Test.main(args); } }Dann kann man einfach statt der Programmklasse die Wrapperklasse aufrufen und alle Ausgaben an Out und ERR werden in das Tempverzeichnis geschrieben. Im Fehlerfall hat man dann Anhaltspunkte was schiefgegangen ist.
Tuesday, December 4, 2012
Einen Notesagenten aus einem cmd script starten.
Im atnotes Forum wurde die Frage gestellt, wie man einen Notes agent aus einem cmd Befehlszeilenscript aufrufen kann. Über Befehlszeile oder über eine URL ist das relativ schwierig, da aber Lotus Notes sein API über COM anbietet ist es ein leichtes dass in einem vbscript zu implementieren. Dieses vbscript kann dann aus dem cmd script aufgerufen werden.
Dim s Dim db Dim agent Set s=CreateObject("Lotus.NotesSession") Call s.Initialize Set db=s.GetDatabase("servername","db.nsf") Set agent=db.GetAgent("agent") Call agent.Runservername, db.nsf und agent müssen natürlich angepasst werden.
Subscribe to:
Posts (Atom)
ad