Tuesday, August 28, 2012

String Prüfung mit Regularexpressions in Java

Eine oft mühsame und aufwendige Aufgabe ist die Prüfung von Strings auf Gültigkeit. Gott sei Dank bietet die String Klasse viele Methoden (z.B. contains(), startsWith() usw.) die eine solche Aufgabe vereinfachen. Die aber wohl Mächstigste ist die .matches(String regex) Methode. Diese Methode gibt den Wert "true" zurück wenn die übergebene RegularExpression mit dem String übereinstimmt.

Ein Beispiel wir wollen prüfen, ob ein String ausschließlich die Zahlen "0-9" enthält.

//Prüfe diverse String Literale ob Sie nur die Ziffern 0-9 enthalten.
System.out.println("145T".matches("[0-9]*")); //ergibt False
System.out.println("145".matches("[0-9]*"));//ergibt true

Wenn wir uns das Regex genauer anschauen gibt der Bereich in den eckigen Klammern den Bereich an, der erlaubt ist und der * sagt, dass eine beliebige Anzahl Zeichen aus der eckigen Klammer erlaut sind.


Um beispielsweise auf eine Kundennummer zu prüfen, die 5 stellig numerisch sein muss, kann man folgendermaßen vorgehen .

// Prüfen ob 5 stellig numerisch
System.out.println("1452434".matches("[0-9]{5}")); // ergibt False da zu lange
System.out.println("RALFP".matches("[0-9]{5}"));   // ergibt False da nicht numerisch
System.out.println("12345".matches("[0-9]{5}"));   // ergibt true

Natürlich kann man auch viel komplexere Gültigkeitsprüfungen mit .matches() und Regular Expression durchführen.

z.B. Prüfung auf eine gültige IP Adresse

// Prüfen eines String ob er eine gültige IP Adresse ist.
System.out.println("172.16.2.3"
    .matches("(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")); // ergibt true, da es eine gültige IP Adresse ist														
System.out.println("256.256.256.256"
    .matches("(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)")); // ergibt false, da keine gültige IP Adresse.
Alles in allem sieht man, dass .matches und Regular Expressions wirklich eine sehr mächtige Kombination sind. Und das schöne an Regular Expressions ist, dass es sehr viele fix fertige Beispiele zur Prüfung auf diversen Beispielwebseiten gibt. Das heißt man muss sich nicht alles selber zusammenbauen, sondern kann auf erprobte Regular Expressions zurückgreifen.

zum Beispiel

http://www.regular-expressions.info/examples.html

http://www.mkyong.com/regular-expressions/10-java-regular-expression-examples-you-should-know/

http://regexlib.com/DisplayPatterns.aspx

und viele mehr lassen sich über google finden



Sunday, August 26, 2012

Zeilennummern in Stacktraces im Notesclient anzeigen

Meiner Meinung nach hat es die IBM bei der JVM Optimierung für Notes etwas übertrieben. Denn die IBM hat in den JVM.Properties eine Einstellung gesetzt, die die Anzeige von Zeilennummern in Stacktraces verhindert.Die Zeilennummern in den Stacktraces sind aber eine der wichtigsten Hilfen um Fehlern auf die Spur zu kommen. z.B. sagt ein typischer Stacktrace wie in Notes anzeigt augrund der fehlenden Nummern nicht wirklich viel aus.

java.io.IOException: Cannot run program ""C:\Program": CreateProcess error=2, Das System kann die angegebene Datei nicht finden. 
at java.lang.ProcessBuilder.start(Unknown Source) 
at java.lang.Runtime.exec(Unknown Source) 
at java.lang.Runtime.exec(Unknown Source) 
at java.lang.Runtime.exec(Unknown Source) 
at mycopmany.eclipse.teamviewercontroller.TeamViewerControllerView$5.run(Unknown Source) 
at mycopmany.eclipse.teamviewercontroller.TeamViewerControllerView$2.widgetDefaultSelected(Unknown Source) 
at mycopmany.ui.widgets.SimpleTable.onDefaultSelection(Unknown Source) 
at mycopmany.ui.widgets.SimpleTable$5.handleEvent(Unknown Source)

Ich weiß jetzt zwar, dass irgendwo in meiner run Methode der TeamViewerControllerView ein Fehler aufgetreten ist, aber ich habe keine Anhnung wo. Bei einer längeren Methode die oft native Programme aufruft ein Ding der Unmöglichkeit den Fehler zu finden.

Um diese ungünstige Optimierung der JVM für Notes zu deaktivieren sind zwei Schritte notwendig.

Schritt 1: In der Datei JVM.Properties in "NotesProgDir\framework\rcp\deploy den Eintrag "vmarg.Xnolinenumbers=-Xnolinenumbers" mit einem "#" auskommentieren. Dies verhindert, dass die Zeilennummern bei neuen Klassen die die JVM ausführt entfernt werden. Für Klassen die sich bereits im sogennanten Shared Class Cache der JVM befinden, hilft dieser erste Schritt nicht und man muss den Cache wie in Schritt 2 beschrieben löschen.

Schritt 2: Notes verwendet einen eigenen Shared Class Cache der im Verzeichnis "NotesDataDir\workspace\.config\org.eclipse.osgi" gespeichert wird. Um den Cache zu löschen muss man auf der Commandline in das Verzeichnis der Notes jvm "NotesProgDir\jvm\bin" wechseln und dort den Befehl

java -Xshareclasses:name=xpdplat_.jvm,controlDir="NotesDataDir\workspace\.config\org.eclipse.osgi",destroy

eigeben. NotesDataDir muss natürlich durch den richtigen Pfad ersetzt werden.

Danach bekommt man in Notes vernünftige Stacktraces

java.io.IOException: Cannot run program ""C:\Program": CreateProcess error=2, Das System kann die angegebene Datei nicht finden.
at java.lang.ProcessBuilder.start(ProcessBuilder.java:471)
at java.lang.Runtime.exec(Runtime.java:604) at java.lang.Runtime.exec(Runtime.java:442)
at java.lang.Runtime.exec(Runtime.java:339)
at mycompany.eclipse.teamviewercontroller.TeamViewerControllerView$5.run(TeamViewerControllerView.java:178)
at mycompany.eclipse.teamviewercontroller.TeamViewerControllerView$2.widgetDefaultSelected(TeamViewerControllerView.java:113) at mycompany.ui.widgets.SimpleTable.onDefaultSelection(SimpleTable.java:287)
at mycompany.ui.widgets.SimpleTable$5.handleEvent(SimpleTable.java:142)

und kann den Fehler in Zeile 178 beheben.

Thursday, August 23, 2012

Eclipse Befehlszeilenparameter an notes.exe übergeben.

Eclipse als Basis für Lotus Notes ab der Version 8 bietet jede Menge praktischer Befehlszeilenparameter. Normalerweise kann man diese bei einer RCP Anwendung einfach hinter die ausführbare Datei anhängen.

z.B. "eclipse.exe -console" um die OSGI Console mit eclipse mitzustarten.

Bei Lotus Notes geht das nicht so einfach, da Notes eigene Befehlszeilenparameter wie z.B. den "-sa" Parameter verwendet. Es gibt aber Abhilfe, in dem man den  Parameter "-RPARAMS" + den eclipse RCP Befehlszeilenparameter voranstellt.

z.B. um die OSGI Console mit Notes mitzustarten kann man "notes.exe -RPARAMS -console" aufrufen.

Ein anderer praktischer Befehlszeilenparamter ist "-clean" Es weist Eclipse an nicht den Extension Registry Cache zu verwenden, sondern die Plugins neu einzulesen. Dies muss man z.B. machen, wenn man neue Plugins in die Verzeichnisstruktur von Lotus Notes einkopiert hat und diese beim start von Notes verwendet werden sollen.


Eine Übersicht über alle Befehlszeilenparameter die Eclipse und damit auch Lotus Notes unterstützt findet man in der Eclipse Doku.

Wednesday, August 22, 2012

Automatisches Upgrade der ODS am Client

In jeder grösseren Notes/Domino Version wird die sogenannte ODS (On Disk Structure) verändert. Die ODS Version ist das Dateiformat in dem Notes/Domino die Daten der betreffenden Replik lokal speichert. Die ODS Version wird nicht repliziert. Das heißt eine Replik am Server kann eine andere ODS Version als der Client haben. Bei einem Upgrade auf eine neue Version wird die ODS Version am Server meistens mit einem copy style compact auf die aktuelle Version gehoben. Diese Änderungen wird aber dann nicht auf lokale Repliken übertragen.

Um auch die lokalen Repliken auf den neuesten Stand zu bringen, gibt es aber seit 8.5.2 den Notes.ini Parameter NSF_UpdateODS=1. Wenn dieser Parameter gesetzt ist, versucht Notes alle Datenbanken auf die neueste ODS Version zu konvertieren. Ein Teil der Datenbanken wird als Hintergrundtask konvertiert. Der Rest wird beim nächsten Starten des Client abgearbeitet. Ab Version 8 aufwärts muß man zusätzlich noch die Verwendung  der neuen ODS mit der Notes.ini Variable Create_R85_Databases=1 (oder für ODS 4.8 Create_R8_Databases=1) erlauben.

Der Parameter  NSF_UpdateODS=1 kann auch über eine Desktop Policy (Mail Tab->Alle lokalen NSF-Datenbanken auf die neueste ODS-Version aktualisieren) gesetzt werden.

 Für Details zu dieser neuen Funktion gibt es auch eine Technote der IBM
 

Tuesday, August 21, 2012

JVM Profiler im JDK

Wenn man Programmcode optimieren will, ist es wichtig dass man weiß an welchen Stellen eine Optimierung des Codes wichtig ist. Man muß sozusagen die Hotspots im Code finden an denen die meiste Zeit vertrödelt wird. Dazu verwendet man sogennante Profiler die auf der einen Seite einen genauen Einblick in den Hauptspeicher eines laufenden Javaprogramms als auch eine genaue Analyse der Lauzeit und Häufigkeit der Verwendung von Methoden erlauben.

 Man kann jetzt natürlich einen Profiler aus dem Internet herunterladen, aber zumindest seit Version 1.6 gibt es im JDK auch den sehr guten Java Visual VM im "bin" Verzeichnis. Da dieser auf jedem PC auf dem sich das JDK befindet installiert ist hat man immer schnell einen Profile bei der Hand.


Ersatz für @Explode in Java

In Notesanwendungen hat man oft die Aufgabe Text, der durch Trennzeichnen getrennt ist in eine Liste sprich Array zu verwandeln. Dazu verwendet man die Funktion @Explode.

z.B. @Explode("a,b,c") gibt eine Liste mit den Elementen a,b und c zurück.

Etwas ganz ähnliches kann man in Java mit der split Methode der String Klasse machen. Die gleiche Funktion wie oben kann in Java so codiert werden:

 z. B. "a,b,c".split(",") gibt ein Array mit den Elementen "a", "b", "c" zurück.

Doch da das Trennzeichen nicht einfach nur ein Zeichen sondern eine Regular Expression sein kann ist die Funktion noch viel mächtiger. Stellen wir uns z.B. vor wir haben einen String der verschiedene Trennzeichen haben kann.

z.B. "a;b:c,d".split("[,:;]") gibt ein Array mit den Elementen "a", "b", "c", "d" zurück.

Genauso kann man mit einer anderen Regularexpression vor und nach dem Trennzeichen Whitespace entfernen.

z.B.  "a, b, c".split(",") ergibt ein Array mit den Elementen "a"," b"," c" was nicht gewünscht ist aber "a, b, c".split(""\\s*,\\s*") ergibt das korrekte Array mit den Elementen "a", "b","c".

Aufpassen beim split muss man nur, dass standardmäßig leere Elemente am Anfang nicht in das Ergebnisarray aufgenommen werden.

z.B. ",a,b".split(",") ergibt das Array "a","b" und nicht "","a", "b". Um dies zu vermeiden kann man als zweiten Paramter ein -1 angeben. ",a,b".split(",",-1) mit dem man das erwartete Ergebnis erhält.

Friday, August 10, 2012

Extension aus Dateinamen in Java extrahieren.

Oft möchte man die Extension eines Dateinamens extrahieren. Dies ist mit den Funktionen der String Klasse sehr leicht möglich.

Entweder man macht sich eine statische Methode.
public static String getExtension(String fileName) {
 int pos = fileName.lastIndexOf(".");
 return fileName.substring(pos + 1);
}
Oder man nimmt den Einzeiler
fileName.substring( fileName.lastIndexOf(".") + 1);


Die Funktion geht aber davon aus, dass es eine Extension gibt. Andernfalls müsste man noch Fehlerbehandlungscode einbauen.

Thursday, May 24, 2012

Blue J eine Umgebung zum einfachen Lernen von Java

Java ist prinzipiell eine sehr einfache Sprache die mit sehr wenigen reservierten Schlüsselwörtern auskommt. Was das Erlernen trotzdem kompliziert macht ist, die Mächtigkeit und Komplexität der von Java verwendeten Konzepte wie Objektorientiertheit, Vererbung, Ployphormismus usw. Weiters natürlich auch der Umfang der Klassenbiliothek und der Umgang mit den Tools die nötig sind um selbst einfache Programme zu schreiben. Der grösste Fehler wäre seine ersten Schritte in Java mit einer ausgewachsenen IDE wie eclipse zu starten. Bitte nicht falsch verstehen, ich arbeite sehr gerne mit eclipse oder auch netbeans aber zum Anfangen sind diese Umgebungen einfach schlecht geeignet, da man von der Vielzahl an Möglichkeiten einfach erschlagen wird.

Deshalb empfehle ich für das Erlernen von Java die Umgebung Blue J. Dies ist eine sehr einfache Entwicklungsumgebung die speziell dafür geschrieben wurde um einfache Java Klassen zu schreiben und sie sofort auszuprobieren. Man benötigt dazu keine ganzen Programmen sondern kann seine Klassen sofort nach dem Erstellen instantieren und Methoden aufrufen.

Hier ein kleines Beispiel:

Nach dem Laden von Blue J den Menüpunkt Projekt öffnen auswählen:


und das people Beispiel auswählen. Normalerweise installiert Blue J die Beispiele in das Programme Verzeichnis was natürlich ungünstig ist, wenn man keine Schreibberechtigung in dieses Programmverzeichnis hat. Darum habe ich die Beispiele bei mir auf den Desktop kopiert.

Danach muss man den Compile Button klicken und wenn alles gut geht, werden sämtlich Klassen in dem Beispiel kompiliert und man sieht folgendes Bild.


Die orangen Felder sind die einzelnen Klassen des Projekts und die Pfeile geben die Beziehungen an. Staff und Student erben die Eigenschaften von Person und Person wird in der Klasse Database verwendet. Diese Pfeile werden von Blue J auch bei eigenen Projekten automatisch erstellt und helfen am Anfang die Vererbungsbeziehungen in einem Projekt zu verstehen.

Man kann nun jederzeit von einer Klasse eine Instanz erstellen. Dazu klickt man mit der rechten Maustaste auf die entsprechende Klasse (in unserem Fall Database) und wählt einen Konstruktor (Methode die eine Instanz erzeugt) der Klasse.
Die Instanz wird, wenn der Konstruktor keine Parameter hat nach Eingabe eines Namens für die Instanz sofort erstellt und im unteren Bereich von Blue J eingezeigt..

Das gleiche machen wir jetzt für die Klasse staff. Die hat einen Konstruktor mit Parametern. Diese fragt Blue J dann automatisch ab. Wichtig ist, dass man Strings mit "" eingibt.


Den Namen der Instanz. Sie können jetzt natürlich gleich eine beliebige Anzahl von Personen anlegen.

Die Instanzen werden immer im unteren Bereich von Blue J angezeigt und Sie  können mit rechte Maustaste auf die Instanz und dem Punkt inspect jeder Zeit die Variablen einer Instanz anzeigen.




Im nächsten Schritt möchte ich noch zeigen, dass man auch die Instanzen die wir gerade erstellt haben problemlos an die Instanz people hinzufügen kann.

Mit der rechten Maustaste auf die Instanz People klicken und die Methode addPerson auswählen.

Blue J frägt dann welche Instanz man gerne anhängen möchte und ich kann dann die von mir erstelle Instanz der Klasse Staff wählen. (Achtung immer auf Großkleinschreibung achten) Man kann die Instanz natürlich auch in der Combobox auswählen. Übrigens ist mir hier ein kleiner Fehler unterlaufen, denn in Java sollten Namen von Instanzen immer mit einem Kleinbuchstaben beginnen ;-)

Dann kann man auch andere Methoden der Instanz Database ausprobieren wie z.B. listAll() die eine Liste der Personen an die Standardausgabe schickt.

Mit einem Doppelklick auf eine Klasse kann man sich auch jederzeit den Source der betreffenden Klasse anzeigen.

Wenn man selbst schon Klassen geschrieben hat, kann man diese natürlich jederzeit in Blue J importieren kompilieren und genauso interaktiv ausprobieren wie man es hier gesehen hat.

Blue J ist meiner Meinung nach eine tolle Umgebung um einfache Klassen auszuprobieren oder selber zu entwickeln. Einfach ein gutes Java Buch nehemen und die Beispiele in Blue J ausprobieren.

Es lohnt sich.
ad