Posts mit dem Label programmierung werden angezeigt. Alle Posts anzeigen
Posts mit dem Label programmierung werden angezeigt. Alle Posts anzeigen

Dienstag, 14. Juli 2009

Tip: Tomcat 5.x Encoding-Problematik...

Das Encoding-Problem ist wohl vielen bekannt - ich wollte mir auch schon ein "Schei* Encoding" T-Shirt bestellen...

Im Apache Tomcat 6 reichte bei mir immer ein
request.setCharacterEncoding("UTF-8");
bei folgendem Seitenkopf in der JSP
<%@ page pageEncoding=”UTF-8″ contentType=”text/html; charset=UTF-8″%>
und ich konnte die Anfrageparameter in UTF-8 ohne Probleme auslesen.

Natürlich sollte man das wie z.B. im Spring-Framework wenn möglich in einen eigenen Servlet-Filter (siehe CharacterEncodingFilter) auslagern.

Beim Tomcat 5.x hatte ich mit diesem Vorgehen leider kein Glück. Weder die Context-Konfigurationsoptionen "URIEncoding" noch "useBodyEncodingForURI" in der Konfigurationsdatei brachten Besserung. Dieses Problem hatten aber wohl schon mehrere Anwender - siehe hier.

Bisher konnte ich das Problem leider nur auf folgendem Weg lösen:
String firstname = request.getParameter("firstname");
if (firstname != null) {
firstname = new String(firstname.getBytes("ISO-8859-1"),"UTF-8");
}
In diesem Fall konvertiere ich den Parameter von "ISO-8859-1" nach "UTF-8". Das sollte laut Tomcat FAQ auch kein Problem darstellen, da das Default-Encoding bei Servlets laut dem FAQ auch "ISO-8859-1" sein sollte:
Default Encoding for POST

ISO-8859-1 is defined as the default character set for HTTP request and response bodies in the servlet specification (request encoding: section 4.9 for spec version 2.4, section 3.9 for spec version 2.5; response encoding: section 5.4 for both spec versions 2.4 and 2.5). This default is historical: it comes from sections 3.4.1 and 3.7.1 of the HTTP/1.1 specification.


Update 14.07.2009: Ich konnte mit folgender Testseite alle drei Tomcat-Versionen:
  • 5.0.28
  • 5.5.27
  • 6.0.20
erfolgreich testen. Bei allen Versionen ergab der Test das gleiche Verhalten. Meine Encoding-Testseite funktionierte problemlos wenn nicht vor dem "setCharacterEncoding" ein Anfrage-Parameter abgefragt wurde.

Wirklich komisch - ich muss nochmal genau nachforschen warum das ältere Projekt im Tomcat 6.x problemlos mit dieser Variante funktionierte und bei Tomcat 5.x Probleme bereitet hatte.

Update 15.07.2009: Das Rätsel ist gelöst! eine jar-Datei hat zu diesem Phänomen bei dem alten Projekt geführt. In meinem Fall eine jar-Datei des CMS FirstSpirit namens "fs-access.jar". Wenn diese aus dem "WEB-INF/lib"-Verzeichnis entfernt wird und "setCharacterEncoding" verwendet wird funktioniert auch im Tomcat 5.x alles wie erwartet. Evtl. ist die "fs-access.jar" in diesem Fall eine veraltete Version. Warum der Tomcat 5.x damit ein Problem hat und der Tomcat 6.x nicht ist mir aber immer noch ein Rätsel.

Update 15.07.2009 / 2: Die Kontext-Konfiguration "URIEncoding" wirkt sich nur auf das URI-Encoding aus! d.h. das muss verwendet werden wenn man die Parameter z.B. im Querystring übergibt (HTTP-Methode GET). Wenn das in der server.xml konfiguriert wurde kann man sich das Umwandeln von "ISO-8859-1"-Zeichenfolgen nach "UTF-8" sparen.

Weitere Informationen:

Mittwoch, 1. April 2009

Die Programmierung, unendliche Weiten... Java: Math.log(0) = -Infinity (double)

Die Unendlichkeit ist so ein Thema für sich. Ich habe heute einen Fehler in der Java-Komponente JFreeChart gemeldet. Es kommt zu einer niemals endenden while-Schleife, da das Ergebnis von Math.log(0) auf meinem System -Infinity (Variablentyp: double) ist und das in einer while-Schleife verwendet wird.
Bei einem Kollegen mit Mac OS als Betriebsystem und dem gleichen Quelltext führt das aber komischerweise nicht zum Fehler - werde Ihn mal fragen was Math.log(0) bei Ihm liefert :)

Hier meine Fehlerbeschreibung:

Summary: endless loop in LogAxis class

Description:

JFreeChart Version 1.0.12
OS: Linux (Kernel: 2.6.27-14)
JVM: sun-java 1.6.0_10-b33
Architecture: x86_64

I get an endless loop in LogAxis.refreshTicksVertical method. This method
calls calculateLog(getLowerBound())-method. getLowerBound() returns 0.0d
and calculateLog calls Math.log on number 0. the result of Math.log(0) =
-Infinity on my system and this is the cause of the endless loop in
LogAxis.refreshTicksVertical - while (current <= end) -
current = -Infinity - is every time true.
I have added a zero (0) check to calculateLog and now everything seems to
work.

A colleague with Mac OS operating system does not have the problem with
the same code.

The class LogarithmicAxis seems to work out of the box - seems to have a
zero check already included (SMALL_LOG_VALUE = 1e-100).


Hier der Link zum Ticket bei sourceforge: link

Update: auf dem Mac gibt Math.log(0) auch -Infitity.

Sonntag, 29. März 2009

"Nested Set" mit Hibernate und Spring

Das Modell "Nested Set" kann verwendet werden um Baumstrukturen mithilfe von Mengen in einer relationalen Datenbank zu speichern.

Man denkt bei einem Baum direkt an Dinge wie z.B. das Dateisystem: Ein Verzeichnis kann mehrere Unterverzeichnisse und diverse Dateien beinhalten. Diese Parent/Child-Beziehung (von den Verzeichnissen) kann man am einfachsten in der relationalen Datenbank folgendermaßen abbilden:
Tabelle: FOLDER
+----+-------------+-----------+
| ID | NAME | PARENT_ID |
+----+-------------+-----------+
| 1 | Parent1 | NULL |
| 2 | Child1 | 1 |
| 3 | Child2 | 1 |
| 4 | Parent2 | NULL |
| 6 | Child2 | 4 |
| 7 | ChildChild1 | 6 |
| 8 | Child1New | 4 |
+----+-------------+-----------+

Die in einem Verzeichnis enthaltenen Dateien müssen natürlich mit einer Relations-Tabelle realisiert werden. z.B.:
Tabelle: FOLDER_FILES
+-----------+-------------+
| FOLDER_ID | FILE_ID |
+-----------+-------------+
| 1 | 2 |
| 2 | 3 |
+-----------+-------------+

Jetzt kommt der Kunde und möchte z.B. nur noch die Verzeichnisse sehen die Dateien beinhalten. Das hört sich erstmal sehr einfach an - nur haben wir das Problem, dass ein Verzeichnis keine Dateien beinhaltet aber in einem Unterverzeichnis Dateien zu finden sein könnten. Wir müssten also Teilmengen selektieren können. Genau zu diesem Zweck kann das "Nested Set"-Modell verwendet werden.

Ein einfacheres Modell ist "Materialzed path" (Pfad-Modell) - hier wird zu jedem Knoten (in diesem Beispiel Verzeichnis) der komplette Pfad in eine zusätzliche Spalte gespeichert:
Tabelle: FOLDER
+----+-------------+---------+-----------+
| ID | NAME | PATH | PARENT_ID |
+----+-------------+---------+-----------+
| 1 | Parent1 | .1. | NULL |
| 2 | Child1 | .1.2. | 1 |
| 3 | Child2 | .1.3. | 1 |
| 4 | Parent2 | .4. | NULL |
| 6 | Child2 | .4.6. | 4 |
| 7 | ChildChild1 | .4.6.7. | 6 |
| 8 | Child1New | .4.8. | 4 |
+----+-------------+---------+-----------+

Nun kann man einen kompletten Teilbaum mit folgender SQL-Abfrage erhalten:
SELECT * FROM FOLDER WHERE PATH LIKE '.4.%'
Hier selektiert man das Verzeichnis "Parent2" inklusive aller Kinder.

Dieses Pattern ist mit Hibernate relativ einfach zu realisieren. Einfach eine zusätzliche Property/Spalte "PATH" hinzufügen und einen Interceptor schreiben, der vor dem Schreiben in die RDBMS den "Path" pro Element ermittelt.

Leider gibt es beim Modell "Materialized path" einige Restriktionen - u.a. die Länge der PATH-Spalte restriktiert die Verzeichnisbaumtiefe, die Performance auf eine Text-Spalte mit LIKE ist nicht optimal u.v.m

Das führt uns zum Modell "Nested Set". In diesem Blogbeitrag wurde das Prinzip sehr einfach und verständlich erklärt - deshalb werde ich mich hierzu nicht weiter auslassen (DRY-Prinzip). Ich werde mich hier auf die Implementierung in Spring und Hibernate konzentrieren.

Das Resultat in der Datenbank sieht dann wie folgt aus:
Tabelle: FOLDER
+----+-------------+-----------+-----------+---------+----------+
| ID | NAME | PARENT_ID | NS_THREAD | NS_LEFT | NS_RIGHT |
+----+-------------+-----------+-----------+---------+----------+
| 1 | Parent1 | NULL | 1 | 1 | 6 |
| 2 | Child1 | 1 | 1 | 2 | 3 |
| 3 | Child2 | 1 | 1 | 4 | 5 |
| 4 | Parent2 | NULL | 4 | 1 | 8 |
| 6 | Child2 | 4 | 4 | 2 | 5 |
| 7 | ChildChild1 | 6 | 4 | 3 | 4 |
| 8 | Child1New | 4 | 4 | 6 | 7 |
+----+-------------+-----------+-----------+---------+----------+

Hier handelt es sich um eine spezielle "Nested set"-Implementierung ist. Es gibt neben den Spalten "NS_LEFT" und "NS_RIGHT" noch die Spalte "NS_THREAD".

Um hier einen Teilbaum zu erhalten genügt folgende SQL-Abfrage:
SELECT * FROM FOLDER WHERE NS_THREAD = 4 AND NS_LEFT BETWEEN 1 AND 8

Die Implementierung des Interceptors, des Modells sowie die Hibernate-Konfiguration könnt Ihr hier begutachten.

Was man also von einem "Einzeiler" aus Rails, CakePHP und anderen Frameworks kennt ist bei Hibernate wirklich ziemlich komplex zu implementieren. Hier stellt sich die Frage ob Hibernate das nicht etwas einfacher für den Benutzer (Programmierer) machen sollte.

Weitere Links zum Thema:

Dienstag, 24. Februar 2009

Grails 1.1 RC1-Test mit maven 2 erfolgreich!


Eben habe ich Grails 1.1 RC1 mal installiert, ein Projekt angelegt und getestet. Bei der Installation von Grails sind die Umgebungsvariablen JAVA_HOME und GRAILS_HOME wichtig uns müssen gesetzt sein.

Hiernach wollte ich die maven 2-Integration testen. Hierfür muss in ~/.m2/settings.xml folgendes eingetragen werden:
<settings>
  <pluginGroups>
    <pluginGroup>org.grails</pluginGroup>
  </pluginGroups>
</settings>
Danach kann man mit dem Kommando "mvn grails:create-pom -DgroupId=<m2-groupId>" eine maven pom.xml erzeugen lassen. Hier kann man dann die Abhängigkeiten pflegen und danach "mvn eclipse:eclipse" ausführen. Ich hatte den MySQL-JDBC-Treiber als Abhängigkeit hinzugefügt - hat alles super geklappt.

Das Grails Eclipse Plugin war anfangs etwas "mürrisch". Ein Grails-Projekt in Eclipse kann man einfach als "Java Application" starten. Hier verlangte Eclipse aber explizit die Einstellung von JAVA_HOME und GRAILS_HOME.

Als Rails-Fan finde ich das Konzept von Grails super. Wenn man dann auch noch alle Java-Bibliotheken, Frameworks und Tools (à la maven) verwenden kann - noch besser.
Meine "Lieblinge" unter den Java Frameworks (Spring, Hibernate) werden von Grails ja schon (intern) verwendet.

Mit der Programmiersprache Groovy konnte ich mich bisher noch nicht 100%ig anfreunden - das kommt aber bestimmt noch, wenn ich etwas mehr Zeit investiere :)

Weitere Links:
  1. Grails Eclipse Plugin
  2. Grails Maven Plugin
  3. Grails 1.1 RC1 Release Notes

Montag, 23. Februar 2009

Tapestry 5 Web-Framework

Ich lese gerade ein Buch über das Web-Framework Tapestry 5. Wer schonmal ein Java-Projekt mit JSP, JSTL realisiert hat weiss, dass das nicht wirklich Spaß macht - und ziemlich aufwendig ist.
Wenn Ihr auch von JSF (1.x) nicht so begeistert seit kann ich Euch Tapestry nur empfehlen.



Mein "Spiel-Projekt" wird Spring 2.5 und Tapestry 5 verwenden - in Kürze hoffentlich mehr.

Samstag, 21. Februar 2009

Ruby on Rails - Präsentation von Oktober 2007

Ruby on Rails Einführung

...wenn ich mal wieder Zeit finden sollte muss ich diese Präsentation mal auf den neuesten Stand bringen :)