JSR 270 – Was ist neu in Java (”Mustang”) 6 ? – Teil 3

Änderungen am Class-File Format:
Mustang bringt eine neue Form der Validierung von Klassen. Bisher wurden
Klassen vor der erstmaligen Ausführung in der VM mit einem zeit- und speicherintensiven
Verfahren verifiziert.
Die Verifizierung wird nun in zwei Phasen aufgeteilt: Beim Erzeugen der Klasse werden sogenannte “StackMap” Attribute gesetzt (Phase I), mit denen die Verifizierung zur Laufzeit (Phase II) wesentlich schneller ausgeführt werden kann. Ein StackMap Attribut beschreibt die möglichen Zustände des Stacks und der lokalen Variablen nach der Ausführung der Methode. Dieses Verfahren benötigt zum einen weniger Bytecode innerhalb der VM und zum anderen weniger Speicher im Verifizierungsprozess.

Diese neue Form der Validierung ist übrigens gar nicht so neu: Die Idee ist aus der J2ME-Spezifikation CLDC. Aufgrund der Speicher- und Resourcenbeschränkungen konnte die standardmässige Java-Verifizierung nicht im mobilen Umfeld eingesetzt werden, von daher musste ein neues Verfahren entwicklet werden, dass nun mit Mustang auch Einzug in die J2SE-Welt findet.

Allerdings birgt die Verifizierung über StackMaps auch potentielle Sicherheitslücken: Der polnische Sicherheitsexperte Adam Gowdiak konnte über die StackMap Attribute die Sandbox einer J2ME-VM umgehen und direkt auf native Methoden des Betriebssystems zugreifen. Siehe “Java 2 Micro Edition security vulnerabilities” (Achtung: PDF ist über 55MB gross!)

JSR 270 – Was ist neu in Java (“Mustang”) 6 ? – Teil 2

JDBC 4.0
Ganz im Zeichen des “Ease of Development” bringt die neue JDBC Version Annotations mit, die den Zugriff auf Tabellen vereinfachen sollen. Zudem werden auch weitere SQL Features (SQL ROWIDS, SQL/XML) unterstützt.

JAX-WS
Mustang bringt endlich die Webservices in das JDK. Unterstützt werden die neusten W3C und WS-I Standards (SOAP 1.2, WSDL 2.0 und WS-I Basic Profile 1.1). Wie bei JDBC 4.0 werden auch eigene Annotations mitgliefert, die einfachen Zugriff auf Webservices erlauben.

Attach-On-Demand
Dieses Feature erlaubt das Hinzufügen von Debugging, Profiling oder Monitoring-Tools zur Laufzeit und ohne vorherige Angabe von Startup Parametern. Das ist insbesondere für den Serverbereich interessant.

Mehr gibts im nächsten Teil…

JSR 270 – Was ist neu in Java (“Mustang”) 6? – Teil 1

Die JSR 270 ist eine sog. “Umbrella” JSR. Sie definiert nicht selbst die neuen Sprachfeatures von Java 6, sondern referenziert auf eine Sammlung von bestehenden JSRs. Momentan befindet sich JSR 270 im “Early Draft Review” Zustand, d.h. die Featureliste ist noch nicht fixiert. In dieser Postreihe möchte ich paar Features dennoch (ungruppiert) herausgreifen und kurz vorstellen:

GIF Image Writer:
Dank dem Verfall des GIF-Patents erlaubt das javax.imageio Package erlaubt nun auch das Erzeugen von GIF-Bildern. Meiner Meinung kommt das etwas zu spät, das GIF-Format hat in den letzten Jahren enorm an Bedeutung verloren.

Scripting for the Java Platform
Das neue Package javax.script definiert ein Framework zur Anbindung von externe Scriptsprachen. Das gabs bereits schon (z.B. Mozilla Rhino), allerdings eben noch nicht standartisiert.

Verbessertes Zugriff aufs Dateisystem
Bislang konnten Java-Entwickler nur beschränkt Informationen vom Dateisystem erhalten. Nun wird die java.io.File Klasse aufgebohrt, so dass z.B. auch der freie Speicherplatz ermittelt werden kann.

Mehr gibts im nächsten Teil…

Kurze Einführung in ClassLoader – Teil 4

Der Servlet Container Apache Tomcat ist die Referenzimplementierung der Servlet- und JSP-API. In ihm laufen Webapplikationen, die zur Laufzeit installiert (“deployed”) und deinstalliert (“undeployed”) werden können. Damit das funktioniert, muss Tomcat für jede Webapplikation einen eigenen ClassLoader zur Verfügung stellen. Zudem kann es Klassen geben, die von mehreren Webapplikationen gemeinsam verwendet werden.

Tomcat löst diese Anforderungen durch folgende ClassLoader Hierarchie:

ClassLoader Hierarchie des Apache Tomcats.

Common:
Alle Klassen im /common Verzeichnis des Servers sind sowohl in den Webapplikationen und für Tomcat selbst sichtbar. Hier werden üblicherweise Datenbank-Treiber abgelegt. Entwickler sollten hier keine eigenen JAR-Dateien platzieren, um eventuelle Kompatibilitätskonflikte mit Tomcat zu vermeiden.

Shared:
Die im /shared Verzeichnis befindlichen Klassen stehen allen Webapplikationen zur Verfügung. Sie müssen diese Klassen dann nicht mehr selbst mitbringen. Ein weitere Anwendungszweck ist die Kommunikation zwischen Webapplikationen oder der Einsatz von Singletons, die von mehreren Webapplikationen benötigt werden.

Server:
Die vom Tomcat Server benötigten Klassen befinden sich im /server Verzeichnis. Die Webapplikationen haben keinen Zugriff darauf.

WebApp:
Jede Webapplikation besitzt einen eigenen ClassLoader, der unterhalb vom Shared ClassLoader liegt. Interessant ist, dass hier der Delegationsmechanismus umgekehrt wird:

It is recommended also that the application class loader be implemented so
that classes and resources packaged within the WAR are loaded in preference to
classes and resources residing in container-wide library JARs.

SRV 9.7.2

Auf gut deutsch: Der ClassLoader der Webapplikation versucht zuerst die Klasse zu laden und erst dann wird delegiert. Somit können Webapplikationen Klassen vom Shared oder Common ClassLoader “überschreiben” (z.B. um zu garantieren, dass genau eine bestimmte Version einer Library zum Einsatz kommt).

Mehr zum Thema ClassLoader im Tomcat gibts direkt auf der Tomcat-Homepage. Soweit so gut. Mit diesem Teil ist die ClassLoader – Reihe vorerst abgeschlossen 🙂

P.S.: Noch ein Blogtipp von mir: Auf http://leo.freeflux.net/blog gibts ebenfalls interessante Javaartikel.

Kurze Einführung in ClassLoader – Teil 3

Ein eigener ClassLoader muss von java.lang.ClassLoader ableiten und sollte die findClass-Methode überschreiben. Diese Methode benötigt den vollständigen Klassennamen und gibt die geladene Klasse in Form eines Class Objektes zurück.

Der nachfolgende ClassLoader MyClassLoader lädt die Klassen aus einem übergebenen Dateipfad. Wie in Java üblich, wird die Packagestruktur auf das Filesystem übertragen (d.h. die Klasse ch.javablog.reloadable.MyTest liegt unter ../ch/javablog/reloadable).

Im Konstruktor von MyClassLoader wird der “parent class loader” übergeben, damit der Delegationsmechanismus funktionieren kann. Erst wenn der “parent class loader” die zu ladende Klasse nicht finden konnte, wird unsere findClass-Methode aufgerufen. Dort lesen wir das “.class”-File ein und erzeugen ein byte-Feld (Zeile 23-29).

Dieses byte-Feld wird für die Methode defineClass der Oberklasse benötigt, denn sie macht die eigentliche Arbeit und generiert aus dem byte-Feld eine Java Klasse 🙂

ch.javablog.MyClassLoader:

  1. public class MyClassLoader extends ClassLoader {
  2.     private final String startPath;
  3.     private final String fileSeparator = System.getProperty("file.separator");
  4.     public MyClassLoader(ClassLoader parent, String startPath) {
  5.         super(parent);
  6.         this.startPath = startPath;
  7.     }
  8.    
  9.     protected Class findClass(String name) throws ClassNotFoundException {
  10.         // Absoluten Pfad zur Klasse finden
  11.         StringBuffer path       = new StringBuffer(this.startPath);
  12.         String[] splittedName   = name.split("\\\\.");
  13.         List splittedNameList   = Arrays.asList(splittedName);
  14.        
  15.         Iterator it = splittedNameList.iterator();
  16.         while (it.hasNext()) {
  17.             String pathFragment = (String) it.next();
  18.             path.append(fileSeparator + pathFragment);
  19.         }
  20.         path.append(".class");
  21.         System.out.println("MyClassLoader - loading: " + path.toString());
  22.         // Klasse aus Datei laden
  23.         File classFile = new File(path.toString());
  24.         int fileLength = (int) classFile.length();
  25.         byte[] fileContent = new byte[fileLength];
  26.         FileInputStream fis = null;
  27.         try {
  28.             fis = new FileInputStream(classFile);
  29.             fis.read(fileContent);
  30.            
  31.             // Erzeugt aus dem byte Feld ein Class Object.
  32.             return super.defineClass(name, fileContent, 0, fileLength);
  33.         } catch (Exception e) {
  34.             throw new ClassNotFoundException(e.toString());
  35.         } finally {
  36.             if (fis != null) {
  37.                 try {
  38.                     fis.close();
  39.                 } catch (Exception ignored) {
  40.                    
  41.                 }
  42.             }
  43.         }
  44.     }
  45. }

In einer kleinen Main-Methode probieren wir MyClassLoader aus. Wichtig: Die Klasse ch.javablog.reloadable.MyTest befindet sich nicht im CLASSPATH, sondern in dem Verzeichnis “myclasses” (parallel zum “classes” Verzeichnis).

classes und myclasses Verzeichnis liegen auf der selben Ebene

ch.javablog.Main :

  1. public static void main(String[] args) throws Exception{
  2.         ClassLoader clCurrent = Thread.currentThread().getContextClassLoader();
  3.         ClassLoader clNew = new MyClassLoader(clCurrent, "." + fileSeparator + "myclasses");
  4.         Class myTest = clNew.loadClass("ch.javablog.reloadable.MyTest");
  5.         System.out.println(myTest + " classloader: " + myTest.getClassLoader());
  6.     }

Ausgabe:
MyClassLoader - loading: .\myclasses\ch\javablog\reloadable\MyTest.class
class ch.javablog.reloadable.MyTest classloader: ch.javablog.MyClassLoader@923e30

Interpretation:
Die MyTest wurde erfolgreich von MyClassLoader geladen. Wenn MyTest weitere Klassen importiert, werden sie ebenfalls von MyClassLoader geladen. Die untere Abbildung zeigt die Position unseres ClassLoaders in der ClassLoader-Hierarchie.

ClassLoader Struktur Teil 3

Im nächsten Teil geht es um die ClassLoader im Apache Tomcat, und warum er einen anderen Delegationsmechanismus einsetzt.

Kurze Einführung in ClassLoader – Teil 2

Wenn ein Class Loader eine Klasse laden muss, delegiert er die Anfrage zunächst an seinen “parent class loader”. Erst wenn dieser die gewünschte Klasse nicht finden konnte, probiert er es selber die Klasse zu laden.
Das testen wir doch gerade mal. Wir schreiben zwei Klassen: Customer und Main. Beide Klassen befinden sich im CLASSPATH. In der main-Methode der Main-Klasse werden folgende Objekte geholt:

  • ClassLoader des aktuellen Threads
  • ClassLoader von java.lang.String
  • ClassLoader von ch.javablog.Main
  • ClassLoader von ch.javablog.Customer

Alle diese Objekte geben wir auf der Kommandozeile aus.

Beispielcode:

  1. public static void main(String[] args) {
  2.         ClassLoader clCurrent = Thread.currentThread().getContextClassLoader();
  3.         System.out.println("current context classloader: " + clCurrent);
  4.        
  5.         ClassLoader clString = String.class.getClassLoader();
  6.         System.out.println("java.lang.String classloader: " + clString);
  7.        
  8.         ClassLoader clCustomer = Customer.class.getClassLoader();
  9.         System.out.println("ch.javablog.Customer classloader: " + clCustomer);
  10.        
  11.         ClassLoader clMain = Main.class.getClassLoader();
  12.         System.out.println("ch.javablog.Main classloader: " + clMain);
  13.     }

Ausgabe auf der Kommandozeile:
current context classloader: sun.misc.Launcher$AppClassLoader@133056f
java.lang.String classloader: null
ch.javablog.Customer classloader: sun.misc.Launcher$AppClassLoader@133056f
ch.javablog.Main classloader: sun.misc.Launcher$AppClassLoader@133056f

Interpretation:
Der ClassLoader des Threads ist der System ClassLoader (sun.misc.Launcher). Er lädt die String-Klasse nicht selber, sondern delegiert das Laden der String-Klasse an seinen “parent class loader”, dem Bootstrap ClassLoader. Dieser wird nicht als ClassLoader-Objekt repräsentiert, stattdessen wird beim Zugriffsversuch null zurückgegeben.

Die Klassen Customer und Main werden vom System ClassLoader auch an den Bootstrap ClassLoader delegiert. Der kennt sie aber nicht und von daher muss der System ClassLoader diese Klassen selber laden.

ClassLoader Struktur

Bis jetzt alles noch sehr einfach. Im nächsten Teil schreiben wir einen eigenen ClassLoader…

Kurze Einführung in ClassLoader – Teil 1

Jeder kennt Sie, jeder hasst sie: ClassCastException, ClassNotFoundException und NoClassDefFoundError.

Das Laden von Klassen durch ClassLoader erlaubt zwar wunderbare Dinge wie “Hot Deployment” (Dynamisches Austauschen von Klassen zur Laufzeit), sorgt aber auch für eine Reihe von potentiellen Stolpersteinen. Leider stolpert man gerade dann drüber, wenn man überhaupt keine Zeit für Ursachenforschung hat ;). Dewegen gibts hier eine kleine ClassLoader-Einführung.

Eins vorweg: Es gibt zwei Typen von ClassLoader:

There are two types of class loaders: user-defined class loaders and the bootstrap class loader supplied by the Java virtual machine. Every user-defined class loader is an instance of a subclass of the abstract class ClassLoader.

JLS (5.3)

ClassLoader sind hierarchisch aufgebaut. D.h. jeder besitzt genau einen “parent class loader”. Bis auf den “bootstrap class loader”. Denn er steht an der obersten Stelle der ClassLoader-Hierarchie und ist für das Laden der Java API (z.B. String oder Integer) zuständig (Konkret lädt er die Klassen aus rt.jar). Unter ihm liegt der erste “user-defined class loader”: Der System ClassLoader. Er lädt die Klassen, die im CLASSPATH angegeben werden.

Das nachfolgende Bild zeigt die ClassLoader-Struktur im einfachsten Fall (keine Sorge, es wird noch komplexer…)

So viel für heute. Im nächsten Teil gehen wir auf den Delegation Mechanismus ein…