Von ASCII über ISO-8859-1 zu Unicode

Die Übertragung von Daten spielte in die IT schon immer eine zentrale Rolle. Daher haben sich unterschiedliche Standards herausgebildet.

ASCII

Um Dokumente austauschen zu können, führte die American Standards Association im Jahr 1963 eine 7-Bit-Kodierung ein, die ASCII (von American Standard Code for Information Interchange) genannt wird. ASCII gibt jedem Zeichen der 128 Zeichen (mehr passt in 7 Bit nicht hinein) eine eindeutige Position, die Codepoint (Codepositionen) genannt wird. Es gibt 94 druckbare Zeichen (Buchstaben, Ziffern, Punktionszeichen), 33 nicht-druckbare Kontrollzeichen (etwa Tabulator und viele andere Zeichen die bei Fernschreibern nützlich waren, aber heute uninteressant sind) und das Leerzeichen, das nicht als Kontrollzeichen gezählt wird. Am Anfang des ASCII-Alphabets stehen an den Positionen 0-31 Kontrollzeichen, an Stelle 32 folgt das Leerzeichen und anschließend alle druckbaren Zeichen. An der letzten Position 127 wird ASCII von einem Kontrollzeichen abgeschlossen.

ISO/IEC 8859-1

An dem ASCII-Standard gab es zwischendurch Aktualisierungen, sodass einige Kontrollzeichen entfernt wurden, doch in 7 Bit konnten nie alle länderspezifischen Zeichen untergebracht werden. Wir in Deutschland haben Ümläüte, die Russen ein kyrillisches Alphabet, die Griechen Alpha und Beta, und so weiter. Die Lösung war, statt einer 7 Bit-Kodierung, die 128 Zeichen unterbringen kann, einfach 8 Bit zu nehmen, womit 265 Zeichen kodiert werden können. Da in weiten Teilen der Welt das lateinische Alphabet genutzt wird, sollte diese Kodierung natürlich alle die Buchstaben zusammen mit einem Großteil aller diakritischen Zeichen (das sind etwa ü, á, à, ó, â, Å, Æ) umfassen. So setzte sich ein Standardisierungsgremium zusammen und schaffte 1985 den ISO/IEC 8859-1-Standard, der 191 Zeichen beschreibt. Die Zeichen aus dem ASCII-Alphabet behalten ihre Positionen. Wegen der lateinischen Buchstaben hat die informelle Bezeichnung Latin-1 als Alternative zu ISO/IEC 8859-1 etabliert.

Alle Zeichen aus ISO/IEC 8859-1 sind druckbar, sodass alle Kontrollzeichen – etwa der Tabulator oder das Zeilenumbruchszeichen – nicht dazu gehören. Von den 256 möglichen Positionen bleiben 65 Stellen frei bleiben. Das sind die Stellen 0 bis 31 sowie 127 von den ASCII-Kontrollzeichen und zusätzlich 128 bis 159.

ISO 8859-1

Da es kaum sinnvoll ist, den Platz zu vergeuden, gibt es eine Erweiterung des ISO/IEC 8859-1-Standards, die unter dem Namen ISO 8859-1 (also ohne IEC) geläufig ist. ISO 8859-1 enthält alle Zeichen aus ISO/IEC 8859-1 sowie die Kontrollzeichen aus dem ASCII-Standard an den Positionen 0-31 und 127. Somit steckt ASCII vollständig in ISO 8858-1 aber nur die druckbaren ASCII-Zeichen in ISO/IEC 8859-1. Auch die Stellen 128 bis 159 sind in ISO 8858-1 definiert, wobei es alles recht unbekannte Kontrollzeichen (wie Padding, Start eine Start einer Selektion, kein Umbuch) sind

Windows-1252

Weil die Zeichen an der Stelle 128 bis 159 uninteressante Kontrollzeichen liegen, belegt sie Windows mit Buchstaben und Punktionszeichen und nennt die Kodierung Windows-1252. An Stelle 128 liegt etwa das €-Zeichen, an 153 das ™-Symbol. Diese Neubelegung der Plätze 128 bis 159 hat sich mittlerweile auch in der nicht-Windows Welt etabliert, sodass das, was im Web als ISO-8859-1 deklariert ist, heute die Symbole aus den Codepoints 128 bis 159 enthalten können, und von Browsern dargestellt wird.

Unicode

Obwohl Latin-1 für die „großen“ Sprachen alle Zeichen mitbrachte, fehlen Details, wie Ő, ő, Ű, ű für das Ungarische, das komplette griechische Alphabet, die kyrillischen Buchstaben, chinesische, japanische Zeichen, mathematische Zeichen und vieles mehr. Um das Problem zu lösen, hat sich das Unicode-Konsortium gebildet, um jedem Zeichen der Welt zu kodieren und einen eindeutigen Codepoint zu geben. Unicode enthält alle Zeichen aus ISO 8859-1, was die Konvertierung von Dokumenten vereinfacht. So behält zum Beispiel „A“ den Codepoint 65 von ISO 8859-1, was der Buchstabe wiederum von ASCII erbt. Die letzte Version vom Unicode Standard ist 5.1 und beschreibt ca. 107.000 Zeichen.

Wegen der vielen Zeichen ist es unpraktisch diese dezimal anzugeben, sodass sich die hexadezimale Angabe durchgesetzt hat. Der Unicode-Standard nutzt den Präfix „U+“ gefolgt vom Hexadezimalzahlen. Der Buchstabe „A“ ist dann U+0041.

Unicode Zeichenkodierung

Da es im Unicode 5.1 Standard um die 107.000 Zeichen gibt, werden zur Kodierung eines Zeichens 4 Byte, bzw. 32 Bit verwendet. Ein Dokument, welches Unicode 5.1-Zeichen enthält, wird dann einen Speicherbedarf von 4 × Anzahl der Zeichen besitzen. Wenn die Zeichen auf diese Weise kodiert werden, sprechen wie von einer UTF-32 Kodierung.

Für die meisten Texte ist UTF-32 reine Verschwendung, denn besteht der Text aus nur einfachen ASCII-Zeichen, sind 3 Byte gleich 0. Gesucht ist eine Kodierung, die die allermeisten Texte kompakt kodieren kann, aber dennoch jedes der Unicode 5.1 Zeichen zulässt. Zwei Kodierungen sind üblich: UTF-8 und UTF-16. UTF-8 kodiert ein Zeichen entweder in 1, 2, 3 oder 4 Byte, UTF-16 in 2 Byte oder 4 Byte. Das folgende Beispiel[1] zeigt die Kodierung für den Buchstaben „A“ und „ß“, dem chinesischen Zeichen für Osten und ein Zeichen aus dem Deseret, einem phonetischen Alphabet.

Glyph

A

ß

clip_image002

Unicode Codepoint

U+0041

U+00DF

U+6771

U+10400

UTF-32

00000041

000000DF

00006771

00 01 04 00

UTF-16

00 41

00 DF

6771

D801 DC00

UTF-8

41

C3 9F

E6 9D B1

F0 90 90 80

Werden Texte ausgetauscht, sind diese üblicherweise UTF-8 kodiert. Bei Webseiten ist das ein guter Standard. UTF-16 ist für Dokumente seltener, wird aber häufiger als interne Textrepräsentation genutzt. So verwendet es zum Beispiel intern die JVM oder die .NET-Laufzeitumgebung. Denn standardmäßig ist ein char nur 2 Byte. Das heißt aber auch, die ein Zeichen größer als 65.536 irgendwie anders kodiert werden muss. Dazu muss ein „großes“ Unicode-Zeichen durch zwei chars zusammengesetzt werden. Dieses Pärchen wird Surrogate-Paar genannt.


[1] http://java.sun.com/developer/technicalArticles/Intl/Supplementary/

Labels:

Bitte Feed-Adresse auf den Blog aktualisieren auf http://feeds.feedburner.com/javainsel

Zwei lustige Geschichten von Jonathan Schwartz (ex Sun CEO) …

… zählt Heise (http://www.heise.de/newsticker/meldung/Jonathan-Schwartz-plaudert-aus-dem-Naehkaestchen-950758.html) auf. Seit dem er nicht mehr CEO ist, kann er lustig plaudern. Das macht er auch unter http://jonathanischwartz.wordpress.com/. Passenderweise heißt sein Blog “What I Couldn't Say…”

Java 7 Projekt Coin – Ist die Luft schon raus?

Ein Überblick über die Posts der letzten Monate:

März (bisher). Messages: 6

Februar. Messages: 2

Januar. Messages: 35

Das Projekt begann im Feb. 2009. Im März 2009 erreichen die Anzahl Nachrichten einen Höhepunkt.

Im Moment ist alles auf dem Tiefstand. Im Februar 2010 gerade mal 2 Nachrichten. Keine guten Nachrichten wie ich finde …

Labels:

Smart GWT 2.1 ist raus

Von den Release Notes http://www.smartclient.com/smartgwt/release_notes.html#2_1:

    • GWT 2.0.3 compatible

    • New Graphite theme

    • ListGrid enhancements

      • Record RollOver controls
      • RollUnder Canvas support
      • Background components
      • Support for arbitrary widgets in cells
      • Ability to display row numbers
      • setMaxExpandedRecords(..) to control max. number of simultaneous expanded records
      • ListGridField.setCanDragResize(), setCanReorder(), setAutoFreeze(), setShouldPrint() API's
      • Checkbox selection with grouping
      • MultiColumn sort enhancements
    • TreeGrid enhancements

      • Support for Checkbox tree with Cascade selection
      • Support for tri-state checkboxes (selected, unselected, partial)
      • Performance enhancements
    • ToolStrip enhancements

      • Significant improvement in appearance
      • Added ToolStripButton and ToolStripMenuButton classes
      • Vertical ToolStrips
    • Print support enhancements

      • ability to control which components display in print view
      • print styling on a per-component basis
      • support print window customizations
      • API for the number of records displayed in print view (can be different from UI view)
    • Browser Plugins as widgets

      • Flashlet widget
      • Applet widget
      • ActiveXControl widget
      • SVG widget
    • Other Widget enhancements

      • Window : support for footer controls
      • Calendar : control dragability of events
      • New IMenuButton & IPickTreeItem classes with improved appearance
      • AdvancedCriteria enhancements and support for programmatic construction
      • SectionStack drag reordering support
      • FilterBuilder support for working with very large number of fields
      • Convenience FormItem.setRequiredMessage(..) API
      • TileGrids now automatically relayout if a tile resizes
      • Added support for grouping for formula and summary fields
    • Performance enhancements

      • Snappier TreeGrid expand / collapse
      • Faster Canvas resize
      • Faster Tab close (deferred destroy)
    • Logging of warnings and error to the GWT Developer Console in addition to the Smart GWT Dev. Console.

    • Improved exception handling and reporting.

    • i18n enhancements

    • Showcase enhancements and several new samples under the "New Samples" side nav

    • 27 additional enhancements and bug fixes that were logged in tracker

Labels: , ,

Unentscheidbarkeit für Java-Programmierer

Es wird niemals eine Software geben, die sich eine andere Software anschaut und entscheidet, ob sie etwas bestimmtes macht.
In der theoretischen Informatik gibt es das Halteproblem.
Man kann kein Programm schreiben, das sich ein anderes beliebiges Programm anschaut und nach endlich vielen Schritten erkennt, ob es hält.
(Es kann auch interpretiert werden, aber man hat nicht beliebig Zeit. Wenn ein Programm exakt 10 Jahre läuft, kann man das nicht „testen“, da der Test ja auch 10 Jahren dauert.)
Nehmen wir an es gibt ein Programm
bollean willStop( char[] program )
das entscheidet, ob ein anderes Programm endet.
So sollte folgendes true ergeben:
willStop("return");
willStop("for(int i=0;i<100000000;i++)print(i);");
und folgendes false:
willStop("while(true);");
Eine zweites Methode:
void reverser( char[] program ) {
while ( willStop( program ) )
  out.println( "willStop will stop" );
}
Umgangssprachlich:
- Wenn willStop() true liefert, endet reverser() nicht.
- Wenn willStop() false liefert, endet reserver().
Frage: Was passiert bei folgendem Aufruf?
void reverser( "void reverser(char[]…" );
Ausgefaltet:
void reverser( char[] program ) {
while ( willStop( "void reverser(char[]…" ) )
  out.println( "willStop will stop" );
}
Stoppt reserver(), hat willStop("void reserver…") aber false gegeben. Aber warum ergibt willStop() dann false? Die Funktion stoppt doch? (Umgekehrtes gilt auch.)
Durch diesen Widerspruch muss die Annahme falsch sein, dass es willStop() überhaupt gibt.
 
Aus dem Seminar: Codeanalyse mit FindBugs, PMD, Checkstyle und JDepend

Prabhakar Chaganti. Packt Publishing. ISBN 1847191002. 15. Februar 2007. 248 Seiten

Didaktisch ist das Buch deutlich besser aufgebaut als GWT in Action, allerdings geht es deutlich weniger in die Tiefe. Während die Autoren ein einfaches Beispiel zur Internationalisierung angeben und dann schreiben „The I18N support in GWT is quite extensive and can be used to support either simple or complicated internationalization scenarios.“ geht hier das Hanson-Tacy-Gespann deutlicher in die Tiefe. Sehr gut gefallen haben mir den praktischen Beispiele, die Ajax so bekannt gemacht hatten, etwa die Listen mit Kandidaten bei eingegebenen Suchbegriffen oder weiteres. Allerdings gibt es auch ein paar Schwachpunkte. Zunächst betrifft es die GWT-Version: das Buch basiert auf GWT RC1 von Ende 2006. So kommen Neuigkeiten aus GWT 1.4 (aktuell ist GWT 2) nicht zur Sprache. Zudem ist die Formatierung oft ungenügend. Es beginnt schon früh mit dem Satz:

When we wish to draw your attention to a particular part of a code block, the relevant lines or items will be made bold:

calendarPanel.add(calendarGrid);
calendarPanel.add(todayButton);

Und dann steht das noch nicht mal in der Einleitung in bold.

Einrückung und Formatierung sind im ganzen Buch sehr merkwürdig. Die Listings besitzen oft am Anfang eine sehr hohe Einrückung, um dann die verbleibenden Zeilen an den unmöglichsten Stellen umbrechen zu müssen. Einige Fehler sind sicherlich nur Unachtsamkeiten. Wie die folgende:

Primitive types—character, byte, short, integer, long, Boolean, float, and double
Primitive type wrapper classes—character, byte, short, integer, long, Boolean, float, and double

Oder dann zeigt ein Screenshot bei den Primzahlenbeispielen eine Zahl in Anführungszeichen, doch im Quellocode steht:

Window.alert("Yes, "+ primeNumber.getText() ...

Es fehlt hier, genauso wie bei der Fallunterscheidung beim No, das einleitende Hochkomma. Bei Konstruktoren ist ein einfaches super(); sicherlich nicht als explizite Anweisung nötig. Einige Kritikpunkte betreffen die Namensgebung. Da heißt dann eine Methode großgeschrieben ShowText() oder onEventpreview(). Stilistisch lässt sich vielleicht noch for (; rs.next();) mit einem einfachen while( rs.next() ) schreiben. Und warum sehe ich das bei so vielen Autoren Felddeklarationen der Art

private String[] items = new String[]{"apple", "peach", "orange", "banana", "plum", "avocado", ...

Wenn es auch einfach nur

private String[] items = {"apple", "peach", "orange", "banana", "plum", "avocado", ...

heißen könnte? Viele Beispiele tragen im Quellcode für die GWT-Komponenten CSS-Zuweisungen wie
searchText.setStyleName("liveSearch-TextBox");
Doch die CSS-Datei ist nicht angegeben! Für die Listings hätte das eigentlich auch wegfallen können—hier muss man die Beispiele von CD oder aus dem Internet nehmen. Mit den Styling ist auch eine andere Sache krumm. Statt <img border='0' src='images/blank.gif'/> für eine Tabelle zu schreiben, wäre hier wohl CSS besser, also etwa <img class="border:0" src='images/blank.gif'/>. Bei den Schaltflächen müssen HTML-Zeichen nicht ausmaskiert werden: new Button("&lt;", this); new Button("&gt;", this); ist schlicht falsch. In der Abbildung auf Seite 41 taucht plötzlich eine Schnittstelle RemoteServiceAsync auf. Die angeblich selbst geschriebene Schnittstelle gibt es nicht, das sollte PrimesServiceAsync heißen. Beim Beispiel mit Auto Form Fill überträgt der GWT-RPC-Service eine HashMap mit den Daten. Eine interessante Alternative wäre, eine serialisierbare Bean zu deklarieren und diese zu versenden. Da kommt in den Beispielen nirgendwo vor. Platz nehmen recht viel Codeduplikate ein, da der Autor bei den Beschreibungen einen Aufbau gewählt hat, in dem erst der Quellcode als Tue-Dies-Anweisungen aufgeführt wird und später die zentralen Stellen beim Was-haben-wir-eigentlich-gemacht-Teil wiederholt. Das kostet natürlich Platz beim Druck und hätte kompakter ausfallen können. Einige Beispiele geben Beispiele für eine Ajax-Bibliotehk an, die sonst aber nicht so weit verbreitet ist. Eine Sache gibt es sogar, die im Action-Buch nicht steht – und die ich auch dort vermisste habe: wie man Dokumente lädt. Hier ist es: HTTPRequest.asyncGet("customers.csv", new ResponseTextHandler() ). Eine Auflistung der unterstützten APIs fehlt jedoch auch hier. In der Summe bleibt ein nettes gut lesbares Buch, welches schnell gelesen ist und auch nicht schwer ist.

Buchkritik “GWT in Action. Easy Ajax with the Google Web Toolkit”

Robert Hanson, Adam Tacy. Manning. ISBN 1-933988-23-1. Juni 2007. 632 Seiten

Die Autoren kennen sich mit GWT gut aus und sind selbst an einigen GWT-Komponenten beteiligt (die allerdings nicht sonderlich spektakulär sind). So hat auch Robert Hanson einen Blog unter http://roberthanson.blogspot.com/ und aktualisiert in hin und wieder mit Neuerungen des GWT. Dieses Detailwissen in GWT scheint dem Autor aber an einigen Stellen im Wege zu sein, wenn etwa das CSS-Styling der Komponenten oder der Aufbau eigener Widgets sowie der native Zugriff auf JavaScript (das sogenannte JSNI) noch vor dem GWT-RPC vorgestellt wird, was dann unter Advanced zählt – da gehört für mich eher JSNI hinein, aber viel weniger GWT-RPC. Da das Buch zu einem der ersten GWT-Büchern gehört, gibt es noch einige Bezüge zu GWT 1.3, die stören aber nicht. Offensichtliche Fehler oder Ungenauigkeiten sind mir bis auf eine fehlende Implementierung bei

public static ServerService getInstance();

und der verrückten StringBuffer-„Optimierung“ nicht aufgefallen.

StringBuffer query = new StringBuffer();

query.append("param1=" + URL.encodeComponent(value1));

query.append("&");

query.append("param2=" + URL.encodeComponent(value2));

query.append("&");

query.append("param3=" + URL.encodeComponent(value3));

String url = "/search?" + query.toString();

Und so gibt es bis auf die etwas verwirrenden Kapitelreihenfolgen nichts zu bemängeln.

Kapitel 2 und 10 sind online unter http://www.manning.com/hanson/ als PDF verfügbar. Wollen wir hoffen, dass das Buch bald auf GWT 2 gebracht wird. Ich würde wir auch wünschen, dass es ein Kapitel mit einer Vorstellung von Zusatzkomponenten gib, denn die eingebauten GWT-Komponenten sind genauso gammelig wie die AWT-Komponenten. Smart GWT, bzw. Ext GWT sollten auf jeden Fall genannt und beschrieben werden. In der Summe ein gutes Buch, wenn man sich schon mit einfachen Beispielen aus dem Netz mit dem GWT warmgemacht hat und noch mehr Interna lernen möchte.

Labels:

Java Decompiler: JD, Jad

Der Java-Compilers erzeugt aus der Quellcodedatei eine Klassendatei und der Decompiler dreht die Arbeitsweise um. Decompiler gibt es für die verschiedenen Programmiersprachen und Java gehört zu den Sprachen, bei der die Zurückübersetzung einfacher ist als bei optimierten Maschinenprogrammen, die zum Beispiel ein C++-Compiler erzeugt. Der Grund ist, dass im Bytecode viele wertvolle Informationen enthalten sind, die in herkömmlichen Maschinencode nicht auftauchen. Darunter sind etwa Typinformationen oder Hinweise, ob ein Methodenaufruf virtuell ist oder nicht. Sie sind für die Java-Laufzeitumgebung wichtig und eine große Hilfe, wenn es darum geht, mit einem Decompiler verlorenen Quellcode wiederzubeleben oder an fehlende Informationen aus Paketen von Fremdherstellern zu gelangen.

Ein Decompiler liest die Klassendatei als Bytefeld ein und beginnt mit der Analyse. Da der Bytecode gut dokumentiert ist, ist das Extrahieren von Variablen- oder Methodennamen einfach. Schwierig sind die Anweisungen. Aus dem Java-Bytecode für eine Methode baut ein Decompiler einen Kontrollfluss-Graphen auf und versucht, Anweisungen und Ausdrücke zu erkennen, die bei der Übersetzung bestimmter Sprachkonstrukte entstanden sein müssten. Das ist eine nicht-triviale Aufgabe und immer noch Gegenstand einiger Diplomarbeiten. Und da Variablennamen durch einen Obfuscator eventuell ungültig gemacht worden sind, muss ein guter Decompiler diese illegalen Bezeichnernamen korrigieren und weitere Tricksereien vom Obfuscator rückgängig machen. Diese Umbenennung ändert den Algorithmus nicht, und ein Decompiler hat es bei dieser Art von Verschleierung einfach.

Ist das legal?   Lassen wir einen Decompiler auf den eigenen Programmcode los, weil etwa der Quellcode verschwunden ist, dann ist die Anwendung kein rechtliches Problem. Das Reverse Engineering von vollständigen Anwendungen, die unter Urheberschutz stehen, muss nicht unbedingt ein Problem darstellen. Vielmehr beginnt die Straftat, wenn dieser Quelltext verändert und als Eigenleistung verkauft wird.

Da mittlerweile auch andere Compiler auf dem Markt sind, die Java-Bytecode erzeugen – etwa aus EIFFEL-Programmen oder aus diversen LISP-Dialekten –, ist über den Umweg Compiler/Klassendatei/Decompiler ein Crosscompiling denkbar. Hier sind jedoch einige Einschränkungen bezüglich der auf dem Markt befindlichen Decompiler erkennbar. Denn fremde Compiler, die Java-Bytecode erstellen, haben andere Techniken, die der Decompiler dann nicht immer passend übersetzen kann.

Java Decompiler project (JD) und Alternativen

Der Markt an leistungsstarken Decompilatoren ist sehr übersichtlich. Das beste Tool (aber auch nicht ganz fehlerfrei) ist zurzeit JD (http://java.decompiler.free.fr/). Das frei verfügbare – aber nicht quelloffene – Programm ist als Bibliothek JD-Core, als alleinstehende grafische Anwendung JD-GUI und Eclipse-Plugin  JD-Eclipse verfügbar. JD selbst ist in C++ geschrieben und benötigt daher keine JVM. JD verarbeitet den Bytecode verschiedener Compiler, wobei das JDK 1.1 bis JDK 6 selbstverständlich mit in der Liste ist, genauso wie der Eclipse-Compiler. (Die Unterscheidung ist nicht ganz uninteressant, da die Compiler sich in machen Details in der Bytecode-Abbildung doch unterscheiden.) JD-GUI ist für die Plattformen Windows, Linux und Mac unter dem Punkt http://java.decompiler.free.fr/?q=jdgui#downloads verfügbar und bietet neben dem Decompileren einzelner Java-Klassen und ganzen Java-Archiven eine angenehme Quellcodedarstellung mit farblicher Unterlegung und Drag & Drop.

JD

Sehr lange war der Decompiler Jad die Referenz. Doch nur von 1997 bis 2001 hat Pavel Kouznetsov das Kommandozeilenprogramm in C++ entwickelt und dann auch 2009 seine Webseite vom Netz genommen. Eine Privatperson hat jedoch die Webseite gespiegelt und unter http://www.varaneckas.com/jad lebt das Projekt (auf unbestimmte Zeit) weiter. Wer Projekte bis Java 1.4 decompilieren möchte, ist mit dem Tool sehr gut bedient. Für Java 5 Projekte hilft JadRetro (http://jadretro.sourceforge.net/)  noch ein wenig nach, in dem es Java 5 Bytecode auf Java 1.4 anpasst und kleine Änderungen im Bytecode durchführt. FrontEnd Plus ist eine grafische Oberfläche für Jad, doch auch sie ist vom Internet verschwunden, seit dem es Jad nicht mehr offiziell gibt. Unter http://jadclipse.sourceforge.net/ ist auch ein Plugin für Eclipse erhältlich, dessen Ende aber ebenfalls eingeläutet ist.

Labels:

Der Diassembler javap

Ein Disassembler ist ein Werkzeug, welches den Bytecode und die Struktur einer Java-Klassendatei anzeigt. Ein Decompiler geht einen Schritt weiter und versucht aus Klassendateien wieder Quellcodedateien zu gewinnen, die später compiliert wieder den gleichen Bytecode ergeben würden. Genau diese „leichte“ Lesbarkeit vom Bytecode oder Decompliation möchte ein anderes Werkzeug, der Obfuscator, erschweren. Das Ziel von Obfuscation ist das möglichst effektive verschleiern aller Bytecodeinformationen, sodass Menschen den Spaß am Bytecode verlieren und das Decompiler bei ihrem Rücktransformation sogar aus dem Tritt kommen.

Das JDK liefert im bin-Verzeichnis der Installation mit javap ein Werkzeug aus, das zwar nicht die Implementierung von Methoden hervorzaubert, aber immerhin die statische Struktur einer Klasse mit den Vererbungsbeziehungen, Variablen, Methoden, Parametern anzeigt.

In der einfachsten Variante wird javap mit dem Klassennamen aufgerufen. Unter der Annahme, javap steht nicht im Suchpfad, und wir befinden uns auf der Kommandozeile direkt im bin-Verzeichnis vom JDK, setzen wir den Klassenpfad und geben anschließend als Kommandozeilenargument für javap die Klasse Quadrat aus dem ersten Kapitel an, die disassembliert werden soll.

c:\Programme\Java\jdk1.6.0\bin>javap -classpath Z:\Documents\Insel\programme\1_01_Intro Quadrat

Compiled from "Quadrat.java"

public class Quadrat extends java.lang.Object{

public Quadrat();

static int quadrat(int);

static void ausgabe(int);

public static void main(java.lang.String[]);

}

Abzulesen sind auch Dinge, die der Compiler automatisch generiert und im Bytecode stehen, wir aber im Allgemeinen nicht schreiben würden, etwa der voll qualifizierten Klassenname java.lang.Object oder java.lang.String, die Vererbungsbeziehung zu Object oder der automatisch angelegte Standardkonstruktor.

Das Tool javap erlaubt noch mehr Parameter, die die Option -help anzeigt.

$ javap -help

Usage: javap <options> <classes>...

where options include:

-c Disassemble the code

-classpath <pathlist> Specify where to find user class files

-extdirs <dirs> Override location of installed extensions

-help Print this usage message

-J<flag> Pass <flag> directly to the runtime system

-l Print line number and local variable tables

-public Show only public classes and members

-protected Show protected/public classes and members

-package Show package/protected/public classes

and members (default)

-private Show all classes and members

-s Print internal type signatures

-bootclasspath <pathlist> Override location of class files loaded

by the bootstrap class loader

-verbose Print stack size, number of locals and args for methods

If verifying, print reasons for failure

Java-Bytecode am Beispiel

Interessanter ist der Schalter -c, der den Bytecode der Methoden/Konstrukturen/Initialisierer anzeigt. Am Beispiel:

$ javap -c -classpath Z:\Documents\Insel\programme\1_01_Intro Quadrat

Compiled from "Quadrat.java"

public class Quadrat extends java.lang.Object{

Steigen wir nicht chronologisch ein, sondern bei der statischen Methode quadrat(). Sie bekommt als Argument ein int und liefert es multipliziert mit sich selbst zurück:

static int quadrat(int);

Code:

0: iload_0

1: iload_0

2: imul

3: ireturn

Die Ausgabe macht die Stack-Natur des JVM sichtbar. Der Übergabeparameter n von quadrat(int n) steht auf Position 0 im Stack. Zur Bilden des Quadrats wird der aktuelle Parameter zweimal mit iload_0 auf den Stapel gelegt und dann mit imul multipliziert. imul löscht die beiden Werte vom Stapel und ersetzt sie mit dem Ergebnis der Multiplikation. ireturn liefert des obersten Stackwert als int zurück. Der Präfix „i“ bei imul und ireturn zeigt, dass die Operationen auf Ganzzahlen durchgeführt werden. Andere Präfixe sind „b” für byte, „c” für char, „d“ für double oder „a“ für Objektreferenzen.

Kommen wir zur statischen main-Methode:

public static void main(java.lang.String[]);

Code:

0: iconst_4

1: invokestatic #59; //Method ausgabe:(I)V

4: return

}

Im Rumpf der main()-Methode steht der Aufruf ausgabe(4), was im Bytecode dazu führt, dass mit iconst_4 der Wert 4 auf dem Stack gelegt, und dann invokestatic die Methode ausgabe() aufruft.

Der Standardkonstruktor von Quadrat ruft lediglich den Standardkonstruktor der Oberklasse Object auf.

public Quadrat();

Code:

0: aload_0

1: invokespecial #8; //Method java/lang/Object."<init>":()V

4: return

Bei Konstruktoren und Objektmethoden ist automatisch an Position 0 im Stack die this-Referenz, da die Aufrufer automatisch an Position 0 diese Referenz übergeben. (Bei statischen Methoden ist das nicht so.) Bei unserem Konstruktor Quadrat() setzt also aload_0 diese this-Referenz auf den Stack, damit der Konstruktor der Oberklasse, also Object aufgerufen werden kann. Konstrukturaufrufe werden im Bytecode mit invokespecial durchgeführt. Im Kern ist ein Konstruktor eine Methode mit dem speziellen Namen <init> und der Rückgabe void. Die Angabe #8 ist ein Verweis auf eine interne Tabelle, doch das Java-Kommentar macht den Eintrag für uns lesbar.

Am komplexesten ist die statische Methode ausgabe(). Im Original sieht sie so aus:

String s;

int i;

for ( i = 1; i <= n; i = i + 1 )

{

s = "Quadrat(" + i + ") = " + quadrat(i);

System.out.println( s );

}

Parameter und lokalen Variablen werden auf dem Stack gespeichert und haben intern nur Positionen.

Variable

Positionen der Parameter/Variablen

n

0

s

1

i

2

Der erste Ausschnitt ohne Schleifenrumpf:

static void ausgabe(int);

Code:

0: iconst_1

1: istore_2

2: goto 44

5: …

41: iinc 2, 1

44: iload_2

45: iload_0

46: if_icmple 5

49: return

Unsere for-Schleife beginnt mit 1, und so setzt iconst_1 den Wert 1 auf den Stack und istore_2 speichert den Wert für die Variable i auf dem Stack. Da for-Schleifen kopfgesteuerte Schleifen sind, also erst testen, bevor sie den Rumpf durchlaufen, springt goto – im Bytecode gibt es diesen Sprungbefehl – über den Schleifenrumpf zum Test. iload_2 lädt die Variable i und vergleicht ihn mit n, der Parametervariablen auf Position 0 auf dem Stack. Ist i < n, dann springt if_icmple zur Position 5, was den Schleifenrumpf ausführt. In der Zeile 41 inkrementiert iinc 2, 1 die Variable i; 2 steht hier für den Index der Variablen (die Variable i steht auf Platz 2 des Stacks) und 1 für das Inkrement.

Der Rumpf der Schleife besteht aus zwei Teilen. Einmal aus dem Zusammenhängen der Strings und einmal aus der Ausgabe auf dem Bildschirm. Zur Konkatenation müssen wir uns zurückerinnern, dass das + bei Strings zu einer Folge von append()-Aurufen auf ein StringBuilder (vor Java 5 StringBuffer) wird.

5: new #20; //class java/lang/StringBuilder

8: dup

9: ldc #22; //String Quadrat(

11: invokespecial #24; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V

14: iload_2

15: invokevirtual #27; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

18: ldc #31; //String ) =

20: invokevirtual #33; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

23: iload_2

24: invokestatic #36; //Method quadrat:(I)I

27: invokevirtual #27; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

30: invokevirtual #38; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;

33: astore_1

Nach dem Ablauf steht die Referenz auf das String-Objekt auf dem Stack und astore_1 überträgt ihn auf den Stack an Position 1, was für die String-Variable s reserviert war.

Es folgt die Ausgabe auf dem Bildschirm:

34: getstatic #42; //Field java/lang/System.out:Ljava/io/PrintStream;

37: aload_1

38: invokevirtual #48; //Method java/io/PrintStream.println:(Ljava/lang/String;)V

Es greift getstatic auf die statische Variable System.out zu und setzt die Referenz auf den aktuellen PrintStream auf den Stack. Dann setzt aload_1 die Referenz vom String s auf den Stack und invokevirtual ruft println() aus.

Dieses Beispiel gibt einen kleinen Einblick in den Bytecode von Java. Weitere Informationen gibt die „The Java Virtual Machine Specification“ und insbesondere das Kapitel „Compiling for the Java Virtual Machine“ unter http://java.sun.com/docs/books/jvms/second_edition/html/Compiling.doc.html. Normale Programmier müssen Bytecode nicht lesen und schreiben können, aber das Wissen ist nützlich und auch nötig, wenn Bytecode selbst erstellt werden soll.

Interna Wichtig zu wissen ist, dass das Programm im Bytecode keine strikte Ablaufanweisung für die JVM ist. Java Bytecode ist nur das „Transportformat“, in dem Programmcode zur JVM gelangt. Die JVM wiederum liest den Bytecode ein, und transformiert ihn in hochoptimierten Maschinencode. Eine Interpretation gibt es zwar noch am Anfang der Ausführung, aber nach ein paar Durchläufen beginnt HotSpot mit der Übersetzung in Maschinencode und da fallen diverse Operationen aus dem Bytecode raus.

Labels:

Eclipse 3.5SR2 ist raus. Und immer noch diese dumme Fehler drin,…

… nämlich das trotz Bestätigung der Lizenzbedingungen der Next und Finish Button deaktiviert bleibt. Hier bleibt nichts anderes übrig, als es mehrfach zu versuchen bis es klappt. Der Fehler scheint erst in Eclipse 3.6 behoben zu sein.

Links:

Labels: , ,

Thema der Woche: Java Sicherheit und Angriffe

Zur Vorbereitung

  • Suche über die Nutzung von Escape Sequences \uxxxx im Internet und wo sie im Java-Programmcode überall genutzt werden können.
  • Lies über die Methode exec() von Runtime und den ProcessBuilder.
  • Lies über den Klassenlader und Klassenladehierarchien.
  • Mit der Java Compiler API lässt sich ein Java-Programm aus einem anderen Java-Programm heraus übersetzen. Wie sieht die API aus? Seit wann gibt es sie?

http://www.blackhat.com/presentations/bh-usa-09/WILLIAMS/BHUSA09-Williams-EnterpriseJavaRootkits-PAPER.pdf ist ein schöner Artikel, wie Entwickler den Quellcode kompromittieren können, um “böse” Sachen anzustellen. Zwar ist die Information über den Java-Compiler, den der Tomcat nutzt, nicht korrekt, aber Jeff Williams fasst wunderbar verschiedene Angriffsfälle zusammen.

Lies den Text und beantworte folgende Fragen:

  • Welcher Annahme im Programm bei “Abusing the JSP Compiler” wird gemacht? Ist das Beispiel realistisch?
  • Wie lässt es sich verhindern, dass man private Attribute auslesen kann? Lässt sich das in der Praxis realisieren?
  • Was ist BCEL? Seit wann und warum integriert das JDK BCEL?
  • Gibt es Unternehmen (in Deutschland), die Code Audits durchführen? Auch von bekannten Open-Source Libraries?

Wer weiter Interesse an dem Thema hast, kann sich http://www.blackhat.com/presentations/bh-usa-09/WEBER/BHUSA09-Weber-UnicodeSecurityPreview-SLIDES.pdf anschauen.

Labels:

Version 1.3.1 von Google App Engine

Nach fast exakt 2 Monaten gibt es mit der Version 1.3.1 das erste Update der 1.3er Reihe:

JDO/JPA Changes

Die Unterstützung eines Cursors gehört mit den größten Neuerungen. Zudem listet der Blog-Eintrag http://googleappengine.blogspot.com/2010/02/app-engine-sdk-131-including-major.html auf:
  • Datastore Query Cursors - Cursors allow applications to save and 'bookmark' their progress through a query, so that it can be resumed later. This works great in combination with paging URLs, as well as processing in the Task Queue API, but there are many other uses. Watch for an upcoming blog post that explores Cursors in the near future. They're also really handy in the context of the next change...
  • No more 1000 result limit - That's right: with addition of Cursors and the culmination of many smaller Datastore stability and performance improvements over the last few months, we're now confident enough to remove the maximum result limit altogether. Whether you're doing a fetch, iterating, or using a Cursor, there's no limits on the number of results.
  • Reduced error rate with Automatic Datastore Retries - We've heard a lot of feedback that you don't want to deal with the Datastore's sporadic errors. In response, App Engine now automatically retries all datastore calls (with the exception of transaction commits) when your applications encounters a datastore error caused by being unable to reach Bigtable. Datastore retries automatically builds in what many of you have been doing in your code already, and our tests have shown it drastically reduces the number of errors your application experiences (by up to 3-4x error reduction for puts, 10-30x for gets).


Labels:

GWT 2.0.1 und GWT 2.0.2

In kurzer Folge hat Google ein erstes Update für die GWT 2-Reihe veröffentlicht. Von http://code.google.com/intl/de/webtoolkit/release-notes.html#Release_Notes_2_0_1:

Release Notes for 2.0.2

This 2.0.2 release contains a couple of fixes that were not included in the 2.0.1 release.

Noteworthy Fixed Issues

  • Standard.css missing new layout styles (#4429)
  • Using a PopupPanel in Internet Explorer without a history IFrame throws a NullPointerException (#4584)

Release Notes for 2.0.1

This 2.0.1 release contains fixes for bugs found in the 2.0.0 release.

Potentially breaking changes and fixes

Noteworthy Fixed Issues

  • UiBinder Image class with resource attribute, removes styles on that image (#4415)
  • Widgets lose focus if its placed on FocusPanel (Opera, Safari) (#1471)
  • Remove method in SplitLayoutPanel is broken (#4217)
  • Splitter constructor hard codes the background color of the splitter to white (#4335)
  • Image should provide method to set alternative text (#4335)
  • CssResource cannot parse unescaped '-', '_' in class selectors and unknown at-rules (#3946)
  • Focusable implementation breaks ScrollPanels in Safari (#1313)
  • RequestBuilder restricted to GET and POST (#3388)
  • HTMLTable.Cell.getElement() calls getCellFormatter().getElement() with row and column swapped RequestBuilder restricted to GET and POST (#3757)
  • MenuBar steals focus when hovered (#3884)
  • TabLayoutPanel tabs don't line up properly on IE (#4447)
  • webAppCreator produces ant build files which support the gwt.args property for passing additional flags to the gwtc and devmode rules, such as ant -Dgwt.args="-style PRETTY" gwtc.

See the GWT issue tracker for the complete list of bug fixes and enhancements in this release.

Genau wie andere auch, hatte ich den Bug #3946 gemeldet und freue mich, dass der CSS-Parser nun auch das "-" für proprietäre CSS-Stile parst.

Labels: ,

Einrücken von mit XMLStreamWriter geschriebenen XML-Dokumenten

Um mal eben schnell ein XML-Dokument zu schreiben ist XMLStreamWriter genau das richtige. Etwas traurig ist, dass er nicht, wie JAXB einen Schalter kennt, um das geschriebene XML-Dokument einzurücken. Hier bietet sich aber ein Filter an, der das tut. In den Klassenpfad nimmt man etwa die beiden Dateien
auf und dekoriert dann seinen eigenen Stream-Writer:

StringWriter stringWriter = new StringWriter(1024);
XMLOutputFactory factory = XMLOutputFactory.newInstance();
XMLStreamWriter writer = new IndentingXMLStreamWriter( factory.createXMLStreamWriter( stringWriter ) );
writer.writeStartDocument( "utf-8", "1.0" );
...

Labels:

GWT Drag and Drop

Das Projekt unter http://code.google.com/p/gwt-dnd/ gehört mit den zu den bekanntesten Drag & Drop Bibliotheken für GWT. Die von Fred Allen-Sauer geschriebene Bibliothek ist ordentlich mit Beispielen hinterlegt, sodass der Einstieg einfach ist. Ein kleines Beispiel soll die Bibliothek demonstrieren.

a) Nach dem Einbinden der Jar-Datei ist in der XML-Datei für GWT folgendes einzutragen:

<inherits name='com.allen_sauer.gwt.dnd.gwt-dnd'/>

b) Von http://code.google.com/p/gwt-dnd/source/browse/trunk/DragDrop/war/DragDropDemo.css sind die Einträge beginnend mit demo-FlexTableRowExample in die eigene CSS-Datei mit aufzunehmen (nicht alle Einträge sind nötig)


c) Aus http://code.google.com/p/gwt-dnd/source/browse/trunk/DragDrop/#DragDrop/war/images nimmt man die Grafik row-dragger-8.gif passend etwa in das WEB-INF/images mit auf und schaut auf den URL-Eintrag in der CSS, dass der Pfad passt.


c) Von http://code.google.com/p/gwt-dnd/source/browse/trunk/DragDrop/#DragDrop/demo/com/allen_sauer/gwt/dnd/demo/client/example/flextable kopiert man die Dateien



  • FlexTableRowDragController

  • FlexTableRowDropController

  • FlexTableUtil

in das eigene GWT-Projekt.


In onModuleLoad() kann es dann so aussehen:


AbsolutePanel panel = new AbsolutePanel();
panel.setPixelSize(450, 300);
panel.addStyleName("demo-FlexTableRowExample");

FlexTableRowDragController dragController = new FlexTableRowDragController( panel );
FlexTable table = new FlexTable();

table.addStyleName( "demo-flextable" );

HTML handle1 = new HTML( "<b>Heinzelmann</b> (100 €)" );
handle1.addStyleName( "demo-drag-handle" );
table.setWidget( 0, 0, handle1 );
dragController.makeDraggable( handle1 );

HTML handle2 = new HTML( "<b>Wumme</b> (200 €)" );
handle2.addStyleName( "demo-drag-handle" );
table.setWidget( 1, 0, handle2 );
dragController.makeDraggable( handle2 );

HTML handle3 = new HTML( "<b>Fred</b> (90 €)" );
handle3.addStyleName( "demo-drag-handle" );
table.setWidget( 2, 0, handle3 );
dragController.makeDraggable( handle3 );

panel.add(table, 10, 20);
FlexTableRowDropController dropController = new FlexTableRowDropController(table);
dragController.registerDropController(dropController); 

RootPanel.get().add( panel );

Anschließend haben wir eine Webseite mit

Heinzelmann (100 €)

Wumme (200 €)

Fred (90 €)

wobei wir die 3 Einträge in der Reihenfolge verschieben können.

Labels: ,

Dokumentation zur standardisierten Dependency Injection (CDI)

Beschreibt die zweiteilige Dokumentation unter http://www.theserverside.com/tt/articles/article.tss?l=DependencyInjectioninJavaEE6. Die Referenzimplementierung von Contexts and Dependency Injection for Java EE (CDI) ist Weld und auch dort gibt es eine sehr gute Dokumentation. DZone hat auch schon gleich eine Reference Card.

Labels:

Erste Spezifikation der neuen Java 7 Closures

Die gibt es unter http://mail.openjdk.java.net/pipermail/lambda-dev/2010-January/000349.html. Das ganze heißt “Projekt Lambda”. Vom ersten Überfliegen her wirklich eine starke Vereinfachung der ersten BGGA-Closures Variante und ohne große Überraschungen.

Labels:

“This is still an issue.” – Bug-Fixes bei Eclipse

2006 habe ich einen https://bugs.eclipse.org/bugs/show_bug.cgi?id=149380 bei Eclipse eingetragen. Heute purzelt mal wieder eine Nachricht rein “This is still an issue.” Wie wahr nach 4 Jahren. Aber vielleicht bin ich einfach zu ungeduldig…

Denormalisierung für schnelle Key/Value Speichersysteme

RDBMS kommen im distributed Cloud-Computing selten vor. Daher muss man auch die Datenhaltung überdenken. Ein Blog-Eintrag diskutiert die Änderungen sehr gut: http://highscalability.com/how-i-learned-stop-worrying-and-love-using-lot-disk-space-scale. Im Prinzip geht es darum, aus Joins zu verzichten, und Daten in den verschiedenen Entities zu duplizieren. Die Erfahrung habe ich bei meinen GWT und GAE/J Projekt ebenfalls gemacht. Es führt zu weniger Lesezugriffen insgesamt, wenn man die Daten lokal in der Entity hält und nicht erst aus verschiedenen Entities zusammensucht, wie man bei normalisierten relationalen Modellen tut. (Außerdem ist es bei vielen lese-Zugriffen auch billiger, die Daten an einer Stelle zu haben, anstatt sie von verschiedenen Stellen über Lesezugriffe, die jeweils Kosten nach sich ziehen, einzusammeln.)

In meinen GWT-GAE/J-Projekt habe ich noch einen anderen Ansatz, die Zugriffe auf die Big-Table zu minimieren. Grundsätzlich: Alle GWT-RPC Implementierungen sind Fassaden, die auf Services zurückgreifen (Googe Guice injiziert diese in die RPC-Fassaden). Für diese Endpoints gibt es dann noch einmal einen Caching-Dekorator als eine Art Caching-Aspekt, der sich wie ein Proxy um die eigentlichen RPC-Implementierungen legt. Diese speichert relevante Daten im MemCache zwischen und minimiert so (langsame) Zugriffe auf die Big-Table. Bei Schreibzugriffen löscht der Caching-Proxy die relevanten Daten aus dem Cache, sodass sie neu geladen werden müssen. Das ist einfach und fix.

Labels: ,

Groovy 1.7 und Groovy Eclipse 2.0

Ein paar Tage ist es schon her, da wurde Groovy 1.7 veröffentlicht. Die Neuerungen gibt es unter http://docs.codehaus.org/display/GROOVY/Groovy+1.7+release+notes. Im Wesentlichen sind es die Unterstützung von geschachtelten und anonymen inneren Klassen, ein paar AST-Sachen.

Ganz frisch ist nun das Update der Groovy IDE auf Eclipse Basis. Die Version 2.0 ist fertig und ist nahezu ein vollständiger rewrite. Die News listet http://docs.codehaus.org/display/GROOVY/Groovy-Eclipse+2.0.0+New+and+Noteworthy auf. Weiterhin mit bunten Bildern:

Labels:

Java 6 Update 18

Die Änderungen http://java.sun.com/javase/6/webnotes/6u18.html sind vielfältig. Zum einen für die Systemkonfigurationen:

Dann:

Im JDK gibt es ein Update der Datenbank

Aus dem Bereich XML:

Und vieles mehr im Bereich Tuning und Fehlerbehebung.

Labels:

Thema der Woche: “Sicheres” Programmieren

Studiere im Artikel http://java.sun.com/security/seccodeguide.html die Guidelines 0 bis 5.

Gib für alle einzelnen Tipps ein alternatives Beispiel. (Aufgabe für 2 Wochen.)

Labels:

Ant 1.8.0RC1 ist auf dem Weg

Ant 1.7 gibt’s ja schon gefühlte ewige Zeit und bei Ant, dem make des 2.0 Zeitalters, steht ein Update ein. Nichts großes, sondern eher Detailverbesserungen:

Apache Ant 1.8.0RC1 is now available for download .

  • a new top level element extension-point allows build files to be extended with custom targets more easily
  • if and unless attributes will be evaluated according to the values of the properties entered if these properties evaluate to true, false, on, off
  • Ant now requires Java 1.4 or later
  • new task include provides an alternative to <import> that should be preferred when you don't want to override any targets
  • numerous bug fixes and improvements as documented in Bugzilla and in WHATSNEW

While in open source projects a final release date strongly depends on the free time of the volunteers/committers, the final release is expected one to two months maximum after this RC. So Ant 1.8.0 is expected between mid February and mid March 2010.

Labels:

Googles erstes Smartphone mit Android 2.1 verfügbar