Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Tuesday, August 18, 2015

Create a Heapdump of the JVM running the Notes standard client

Normally the Garbage Collection of the JVM works without problems, but sometimes caused by programming mistakes the Garbage Collector can not free heap memory and the heap grows and grows till an OutOfMemory Exception is thrown. The best way to find such problems is to use a Heap Analyzer like Eclipse MAT. Before you can use the Heap Analyzer you have to get a heap dump from Notes with these simple steps.

  • Open a command line
  • Change the current directory to the framework\rcp directory in your notes directory
  • Enter the command "rcplauncher.exe -com.ibm.rcp.core.logger#dump heap -dumps heapdump"


You can find the heap dump in the "..\workspace\logs" directory in your Notes data directory.

Sunday, March 22, 2015

In Java 0 is not always equal to 0

I am a big fan, of the Java BigDecimal class for arithmetic operations. It provides fast and easy to use methods to do calculations in arbitrary precision. But last week i have got a bug report that in one of my programs a check whether a BigDecimal variable is 0 returns a wrong result. Here is the code:


if(value.equals(BigDecimal.ZERO))
 System.out.println("Value is zero");
else
 System.out.println("Value is not zero");


The check for a zero value has always worked, but suddenly last week it stopped working and after some investigation i have found out, that it stops working, because the scale of the value has changed from zero, to two. When you have a look in the java doc of the equals method you see, that this works as designed.

This method considers two BigDecimal objects equal only if they are equal in value and scale (thus 2.0 is not equal to 2.00 when compared by this method.

As a workaround for this problem you can replace all your equals method to compareTo which only compares the value and not the scale of the BigDecimal object. 

if(value.compareTo(BigDecimal.ZERO)==0)
 System.out.println("Value is zero");
else
 System.out.println("Value is not zero");

Tuesday, June 3, 2014

Access the Serial Com Port from java code

Although serial com ports are a very old legacy technology, they are still used in many applications, for example to control some production machines or to access GSM gateways to send sms. The support of the serial port in java was always very weak. In the JDK 1.1 days we had the Java Communication API, and i have used it in some projects with success. But this API was not updated for newer Java versions and i can not get it to run on a new JDK and Windows 64 bit.

So i have to find a new solution and after some googling i have found the "Java simple serial Connector" project which is an excellent solution to access the serial com port from java. The library consists of one jar (jssc.jar) which contains some java classes and the native libraries for Windows (32bit and 64bit) Mac OS X and Linux. To use the library in your project you have to add the jssc.jar to your class path.

Example how to write to the serial com Port in Java

public class TestComPort {
 public static void main(String[] args) {
  SerialPort serialPort = new SerialPort("COM5");
  try {
   serialPort.openPort();// Open serial port
   serialPort.setParams(SerialPort.BAUDRATE_9600, SerialPort.DATABITS_8, 
     SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
   serialPort.writeBytes("Hello World".getBytes());
   System.out.println(new String(serialPort.readBytes(10)));
   serialPort.closePort();
  } catch (SerialPortException e) {
   e.printStackTrace();
  }
 }
}



Eclipse 4.4 Luna - Release Teaser

Eclipse 4.4 Luna will be released soon. Watch this little teasers to get an idea how this fantastic new release will look like and what new features will be available.


Wednesday, March 19, 2014

JDK 8 is released

The long awaited JDK 8 is released. See https://blogs.oracle.com/thejavatutorials/entry/jdk_8_is_released or visit the Java 8 landing page for details. This release has many great features like Lamba support and the new Streams API. Unfortunatly all Notes Developer have to use the very dated JDK 1.6 from IBM. So lets hope that IBM will update the JDK in Notes soon.


Thursday, November 14, 2013

Open mail database of the session user in Java

In many Notes/Domino Applications you have to work with the mail file of the user. In Lotus script it is very easy to open the mail file of the session user.

Dim mailDB As New NotesDatabase( "", "" )
Call mailDB.OpenMail

Unfortunately the OpenMail method is not available in Java. As a workaround you can get the mail database of the session user from the DBDirectory.
Database mailDB = ses.getDbDirectory(null).openMailDatabase();

ses should be a valid Notes Session Object.

Wednesday, September 11, 2013

The latest JDK update includes Java Mission Control as a great new feature

Today Oracle has posted update 40 for Java 1.7 on their Java Downloads site. This update does not only bring bug fixes and security updates, but it brings also a great new feature to analyze performance problems in your java programs called "Oracle Java Mission Control" . This powerful tool was ported from the JRockit to the Hotspot JVM.


I have run some short tests with "Mission Control" and it looks really very interesting. You will get a deep understanding what is going on in the JVM which runs your code. You will see how long your program execution is stopped by garbage collection or what overhead the compilation of hotspots in your code will add to the execution of your program.



Unfortunately "Java Mission Control" can only connect to Oracles JVM and not to other JVM's like the one from IBM. So if you want to analyze plugins running in Notes you still have to use the "IBM Support Assistance Workbench" which looks a little bit old compared to the new "Oracle Java Mission Control".

A strange thing is, that "Java Mission Control" is based on Eclipse RCP and SWT and not Netbeans RCP and Java FX.




Saturday, August 10, 2013

Was gibts neues in Java 8

Vielleicht ist es ja etwas früh sich mit Java 8 zu beschäftigen, da wir in Notes leider noch nicht einmal die Version 7 bekommen haben. Aber Java 8 bietet so viele tolle Neuerungen wie Lamda Expressions, Erweiterungen bei den Annotations und eine komplett neue Bibliothek für das Datum und Zeithandling, dass ich mich einfach schon damit beschäftigen muss. Vielleicht haben wir ja auch das Glück und die IBM überspringt die Version 7 und bietet nächstes Jahr Notes gleich mit der Version 8 an. Nicht verschweigen darf man aber, dass  einige lange erwartete Funktionen wie Projekt Jigsaw in das nächste Release verschoben wurden. Alles in allen bin ich aber von den neuen Funktionen wirklich sehr beeindruckt und sie zeigen, dass Java nach wie vor Zukunft hat und vor allem im Vergleich zu den neueren JVM Programmiersprachen wie Scala den Vorteil bietet, dass es zu 100% kompatibel mit bestehenden Code ist.

Einen sehr guten Überblick über die Neuerungen in der Programmiersprache findet man auf Heise Developer

Wenn man auf den Geschmack gekommen ist, kann man eine Vorabversion von Java 8 auf java.net herunterladen.

Wednesday, August 7, 2013

Contextsensitive help for Notesplugin developer in Eclipse

When you develop plugins for the notes platform the target platform, does not contain any javadocs. So you do not get context sensitive help on java classes in Eclipse. This makes the development especially for beginners needlessly difficult and annoying.

Here is an example: You want to make a new SWT Text Field and get only a the Constructor signature with not very helpful parameter names. What the hell is arg1? So you have to open a browser go to the javadocs of SWT and search for the Text class and after reading the description go back to eclipse.

 

Wouldn't it be so much nicer if you can get useful parameter names and the javadoc direct in the syntax completion window like you get it when you develop plugins against the standard RCP target.


Follow this steps to teach the eclipse IDE that it shoukld search for the source in another place.

First go to your plugin in the package Explorer in your eclipse IDE. Open the  "Plugin Dependenices" and search for the plugin for which you want do add java source. In our example this is org.eclipse.swt.win32.win32.x86.versionNumber.



Download the Eclipse RCP source from the eclipse download archive page in the correct version. In our example the correct version is 3.6.2.

Unzip the "org.eclipse.swt.win32.win32.x86.source.version.jar" from the downloaded SDK to a new directory where you want to store all java source packages for Notes. Do not place this directory somewhere in the Notes program directory.

Right click the Notes plugin in package explorer and select "Properties" from the context menu. Paste the fully qualified path to the extracted source plugin in the Location path or select external File and browse to the source plugin file. Then finish the dialog with ok. Now your have context help for every SWT Class in your eclipse IDE.


You can repeat the above steps for other plugins in Notes which are eclipse based, for example jface, eclipse forms or the workbench. Be aware, that most other plugins are not version 3.6.2, but 3.4.2. So you have to download the 3.4.2 SDK from the download archive.

I think this is really a great step forward for every plugin developer for Notes.



Saturday, July 20, 2013

First steps with the Java UCI API to access a starface PBX

In my last Starface related blog post i have shown how to configure the UCI API of the starface PBX in eclipse. Today i want to show you how to use the API to access data and functions in the starface PBX.

The first step to access data on the starface PBX is to create an UciProxy Object. The proxy object manages the connection to the PBX in the background. The proxy object is really handy, because it reestablish the connection automatically in the background if the connection to the PBX has been lost. The proxy object can use different transport methods to access the PBX. Here is an example for a connection without callback over HTTP.


   //Create a Ucpransportfactory to access the starface PBX over the HTTP protocol.
   UcpTransportFactory ucpTransportFactory = new HttpUcpTransportFactory("YOURSTARFACE", 80, false);
   //Create a UciProxyFactory with the above created Transportfactory.
   UciProxyFactory uciProxyFactory = UciProxyFactory.createWithTransportFactory(ucpTransportFactory);
   //Create a proxy with the given credentials
   uciProxy = uciProxyFactory.createUciProxy("0001", "PASSWORD");
   //Establish the connection to the starface PBX
   uciProxy.connect();

Please replace "YOURSTARFACE", "0001" and "PASSWORD" with the host name, your user id and your password.

The next step is to create a so called  "Request Object". Every access able function in the starface PBX is handled by this objects. Here is a list of all Request Objects and their use:

Request Object Use
UciCallListRequests Get and manipulate the call list
UciCallRequests start and end telephone calls or get the state of your telephone
UciFaxListRequests Get and manipulate the list of your faxes or get the transmission report of a fax.
UciFaxRequests Send new Faxes
UciFunctionKeyRequests Get manipulate and press the function keys of your telephone
UciGroupRequests Get and set Group settings
UciPhoneRequests Manage your phones or set your primary phone
UciRedirectRequests Change the redirect settings of your telephones
UciUserStateRequests Get and set your avatar and manipulate your presence awareness status.
UciVoicemailListRequests Get and manipulate the list of your voice mails

And here is the code to access your call list and write all inbound calls to the console.

   // Get a CallListRequest Object to access the calllist
   UciCallListRequests requests = uciProxy.getRequests(UciCallListRequests.class);
   // Get the inbound calllist for the lastday with no group calls,
   // ordered by startTime Ascending. If there are more then 1000
   // entries only the the first 1000 will be retrieved.
   CallList callList = requests.getCallList(new Date(), new Date(new Date().getTime() - 86400000),
     CallListEntryDirection.INBOUND, null, GroupRestriction.NON_GROUP,
     CallListEntryProperties.startTime, OrderDirection.ASCENDING, 0, 1000);
   // Create date and timeformater
   DateFormat df = SimpleDateFormat.getDateInstance();
   DateFormat tf = SimpleDateFormat.getTimeInstance();
   // Iterate through the callist entries and print every entry to
   // standard out.
   for (CallListEntry entry : callList.getEntries()) {
    System.out.println(entry.getId() + "/" + entry.getCalledNumber() + "/" + entry.getCallerNumber() + "/"
      + df.format(entry.getStartTime()) + " " + tf.format(entry.getStartTime()) + "/"
      + entry.getDuration());
   }

So you can see that the UCI API is very easy to use and with only a few lines of code you can access many information's in your PBX which are normally only available in the web interface. In the next post in the starface series i will show you how to get notifications about events occurring in the PBX. So stay tuned.

Friday, April 12, 2013

The Art of Java performance tuning.

There was a very interesting session at Eclipse Con 2013 in Boston about low level java performance tuning from Ed Merks. You can find the session slides at: http://www.eclipsecon.org/2013/sites/eclipsecon.org.2013/files/JavaPerformanceTuning.pptx

P. S. The interesting slides start at slide 17. 

Thursday, February 28, 2013

Performance bei der String Konkatenierung in Java

Ein immer wieder gern gemachter Fehler der zu schlechter Performance in Java Programmen führt ist, das Zusammenbauen von Strings mit dem "+" Operator. Vor allem wenn dieses in einer Schleife gemacht wird steigt der Speicherverbrauch enorm an und der Garbagge Collector läuft Amok. Ein kleines Beispiel. Wir haben eine Liste (List<Person>) mit 100 Namen und wollen diese in eine CSV Datei ausgeben. Folgender Code erledigt die Aufgabe zwar völlig richtig. Wenn man das Programm aber in einem Profiler laufen lässt sieht man, dass jede Menge Hauptspeicher verschwendet wird und das Programm die meiste Zeit mit Garbagge Collecting verbringt.

  String result = "\"Vorname\",\"Nachname\"\n";
  for (Person person : personen) {
   result = result + "\"" + person.getVorname() + "\",\"" + person.getNachname() + "\n";
  }
  System.out.println(result);

Warum ist das so? Die Erklärung liegt darin, dass ein String in Java unveränderbar ist. Das heißt es ist in Java nicht möglich, dass man einen String einfach zu einem anderen hinzufügt. Viel mehr wird bei jeder Konkatenierung ein neuer String erzeugt. Mit diesem Hintergrund sieht man sofort, dass in unserem Programm jede Menge sinnloser Strings erzeugt werden, die sofort wieder von der Garbagge Collection entsorgt werden müssen. Vor allem böse ist aber die "result=result+..." Anweisung. Den der result String wird mit jedem Schleifendurchlauf länger und länger und dadurch wird auch der Hauptspeicher der bei jedem Schleifendurchlauf für den String angefordert werden muß größer und größer. Bei 100 Namen wird das vielleicht noch nicht so viel ausmachen. Bei 1000 Namen kommen da aber gleich mal viele Garbagge Collection Zyklen zusammen und schon haben wir wieder ein Programm, dass die urban legend das Java langsam ist scheinbar bestätigt.

Doch natürlich besitzt die Javaklassenbibliothek mit der StringBuilder Klasse eine Lösung für das Problem. Mit dieser veränderlichen Klasse können fast beliebig lange Strings einfach und effizient zusammengebaut werden.

  StringBuilder result = new StringBuilder();
  result.append("\"Vorname\",\"Nachname\"\n");
  for (Person person : personen) {
   result.append("\"");
   result.append(person.getVorname());
   result.append("\",\"");
   result.append(person.getNachname());
   result.append("\n");
  }
  System.out.println(result.toString());

Mit dieser Variante haben wir die Anzahl der unnötig erstellen String Objekte dramatisch reduziert. Intern verwendet der StringBuilder ein char Array, dass immer wieder vergrössert wird. Das char Array ist standardmäßig mit 16 Zeichen intialisiert und bei jeder Erweiterung wird die Kapazität verdoppelt. Das ist in unserem Beispiel natürlich immer noch eine Verschwendung. Deshalb empfiehlt es sich den StringBuilder als Parameter eine Schätzung der maximalen Größe des StringBuilder mitzugeben. Dadurch kann man nocheinmal einen Performancegewinn erzielen.

Falls das Zusammensetzen des Strings aus mehreren Threads erfolgen soll, sollte man statt des StringBuilders die Klasse StringBuffer verwenden. Letztere ist nämlich im Gegensatz zu StringBuilder Threadsafe.

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.


Wednesday, January 2, 2013

Notes 9 SE erste Eindrücke aus Sicht des Plugin Entwicklers

Nach dem ich mir ein wenig den neuen Client, iNotes und das Browserplugin angeschaut habe, möchte ich mir heute den neuen Client aus der Sicht eines Plugin Entwicklers ansehen.

Die Einrichtung von Eclipse zur Entwicklung von Plugins für Notes 9 Social Edition hat schon Mikkel Heisterberg in einem sehr guten Howto (Eclipse 3.x, Eclipse 4.2) beschrieben. Deshalb kann ich mir dies hier sparen.

Ich habe dann also mal in meine neue Notesumgebung sämtliche Features und Plugins, die wir für den Notes Client entwickelt haben eingespielt und erfreulicherweise laufen alle Plugins ohne Probleme und Einschränkungen in Notes 9 Social Edition. Aber auch hier zeigt sich, dass sich die IBM wenig Mühe gegeben hat, ein konsistentes UI zu erreichen. Notes 8.x war sehr gut an das Farbschema (blau weiße Farbverläufe) von Eclipse angepasst. Deshalb haben sich Plugins die das Standarddesign der Platform übernommen haben sehr gut in den Notes Client eingefügt. Als kleines Beispiel wie das aussieht hier ein Screenshot aus unserem Hardwareinventoryplugin unter Notes 8.5.3:


Die Blautöne der Eclipsebereiche harmonieren relativ gut mit den Blautönen die in Lotus Notes 8.x verwendet wurden.

Leider passen die blauen Farbverläufe nicht mehr zu den grauen Farbverläufen von Notes 9


Dabei sollte es für die IBM ein leichtes sein, die Eclipseplugins dahingehend anzupassen, dass zum ausgewählten Theme passende Farben zurückgegeben werden, wenn ein Plugin Defaultfarben abruft. Ich habe mal Quick and Dirty das "org.eclipse.ui.forms" Plugin von Notes gepatched und schon sehen alle Plugins etwas mehr nach der Farbgebung von Notes aus.


Mit etwas Mühe hätte man da jeden Pluginprogrammierer viel Arbeit ersparen können und selbst erstellte Plugins würden sich automatisch ohne viel Aufwand in den neuen Notesclient einfügen.

Leider gibt es ausser den Änderungen beim Design praktisch kaum etwas neues für Plugin Entwickler. Für eine 8.5.4 wäre es ja auch durchaus in Ordnung gewesen, dass die IBM keine Updates an den Frameworks gemacht hat. Aber wenn man schon mit Notes 9 eine komplett neue Version akündigt kann ich nicht verstehen, warum man den Eclipse RCP Basiscode nicht aktualisiert hat. Wenn man bedenkt, dass jedes Jahr eine neue Version von Eclipse erscheint, dann ist relativ klar, dass viele aktuelle Plugins nicht mehr die uralte 3.4.2 Version von Notes 9 unterstützen. Hier würde ich mir wünschen, dass die IBM so rasch wie möglich zumindest auf die neueste 3.x Version updated. Derzeit ist ja schon 4.2 aktuell. Auch dass noch immer auf Java 1.6 statt 1.7 gesetzt wird, finde ich persönlich sehr schade. Ein echtes Highlight wäre für mich, wenn die IBM hier noch nachbessert und vielleicht bei nächster Gelegenheit Java FX integriert.

Auch die Domino Java API's haben kein Update erfahren. Hier wäre wirklich schon dringender Handlungsbedarf, da sich die Java API von Domino vom Design her sich immer noch wie Java 1.1 anfühlt. z.B. wird noch immer Vector verwendet, statt den mit 1.2 verbesserten Collectionsklassen. Auch Generics werden nach wie vor nicht unterstützt. Nicht einmal die neuen Calendarklassen werden offiziell unterstützt, wenn Sie auch in der Betaversion scheinbar drinnen sind.

Als Fazit kann man nur sagen, dass die IBM alle Leute die sich mit 8.x stark in der Pluginentwicklung engagiert haben mit Version 9 hängen lässt. Bei uns in der Firma geht der Trend dahin, dass wir unsere Plugins die wir für den Notesclient entwickelt haben, nach Vanilla Eclipse portieren und den Notes nur noch da verwenden, wo es gar nicht anders geht.


Für weitere Infos zur neuen Version schauen Sie auch auf meine Übersicht über alle Postings zum Thema Notes/Domino 9

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.

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:
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:

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

Fehlerquelle beim Dividieren von BigDecimals in Java

Ich verwende bei Berechnungen sehr gerne die BigDecimal Klasse von Java. Da mit dieser beliebig große Zahlen und auch in beliebig großer Genauigekeit gerechnet werden können. Beim Dividieren bekommt man aber bei Berechnungen die zu keinem eindeutigen Ergebnis (z.B. 10/3) kommen die Exception "Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result." 

Deshalb sollte man bei Divisionen mit BigDecimal immer die Anzahl der gewünschten Dezimalen und den Rundungsmodus wie in der letzten Berechnung des kleinen Beispiels angeben.
 
public static void main(String[] args) {
 // Berechnung ergibt das endliche Ergebnis 0.5
 System.out.println(new BigDecimal(1).divide(new BigDecimal(2)));
 // Hier tritt eine ArithmeticException auf.
 System.out.println(new BigDecimal(10).divide(new BigDecimal(3)));
 // Berechnung ergibt 3.33 und wirft keine Exception, da wir die Anzahl
 // der Stellen beschränkt haben. Das Ergebnis ist aber natürlich nicht
 // 100% korrekt, aber in der Praxis bei für die Anwendung genügend
 // signifikante Stellen ausreichend.
 System.out.println(new BigDecimal(10).divide(new BigDecimal(3), 2, BigDecimal.ROUND_HALF_UP));
} 

Friday, November 30, 2012

Generische Collection in ein Array verwandeln.

Das Collectionsframework von Java ist vor allem seit der Einführung von Generics eine wirkliche tolle Sache. Aber leider hat man manchmal das Problem, dass man die Collection z.B. für die Übergabe an eine Funktion als Array benötigt. Dafür gibt es in der Collection Klasse die Methode toArray(). Bei nicht spezifizierten Collections funktioniert diese auch ziemlich einfach. Wenn man aber eine Collection mit einem bestimmten Typ hat, dann gibt toArray() auch ein Object Array zurück, was natürlich nicht verwendbar ist.

Ein kleines Beispiel wir haben eine List vom Typ String und möchten die Funktion test(String[]) aufrufen.

public class Test {
 public static void main(String[] args) {
  List<String> list = new ArrayList<String>();
  list.add("Test1");
  list.add("Test2");
  test(list.toArray());
 }
 private static void test(String[] test) {
  // mache irgendwas.
 }
}

Der Compiler wird folgenden Fehler ausgeben: "The method test(String[]) in the type Test is not applicable for the arguments (Object[])"

Nach längerer Suche im Internet habe ich herausgefunden, dass man ein leeres Array des Typs den die Collection hat als Parameter für toArray() übergeben muss, damit es funktioniert.

public class Test {
 public static void main(String[] args) {
  List<String> list = new ArrayList<String>();
  list.add("Test1");
  list.add("Test2");
  test(list.toArray(new String[0]));
 }
 private static void test(String[] test) {
  // mache irgendwas.
 }
}

ad