Tutorials

von Roman Seibold

Ein furchtbar schwer auszusprechendes Wort, mehr nicht, wie ich dieser Tage erfahren musste. Hintergrund war die "schnelle und einfache" Umstellung eines Servers, auf dem bislang JBoss 5.1 betrieben wurde. Bei der Umstellung sollte gleich die JBoss-Version auf die aktuelle 6.0 migriert werden.

Auf JBoss 5.1 lief eine Anwendung, die seit vielen Jahren auf div. Servern u.a. auch auf JBoss 5.0, Tomcat 5.x und IBM WebSphere Application Server 5 und 6, gelaufen ist. Zu Beginn als reine Web-Anwendung, seit der Migration auf JBoss 5.x auch als echte 3-Tier-Applikation mit EJBs.

Nie, ich betone "nie", gab es Probleme bei der Migration. Einfach neuen Server installieren, konfigurieren (Datasources, Queues usw.) und Anwendung deployen, fertig. Jetzt, mit JBoss 6, wurde alles anders.

Das Kernproblem war, dass die Anwendung, schon leicht in die Jahre gekommen, das damals sehr populäre Struts 1 verwendet. Und Struts 1 läuft in unveränderter Form nicht auf JBoss 6. Ja, Sie haben richtig gelesen. Da Struts 1 nicht mehr weiterentwickelt wird und Struts 2 jetzt nicht wirklich einfach eine aktuellere Version ist, sondern schon etwas anderes, gibt es da auch keinen Migrationspfad.

Symptom, dass die Anwendung nicht mehr läuft, sind Deployment-Errors, die auf nicht korrekte URIs hinweisen (z.B. in bsf-2.3.0.jar). Es wird von JBoss 6 moniert, dass "http://java.sun.com/j2ee/dtds/web-jsptaglib_1_1.dtd" nicht existiere. Das ist im Grunde genommen auch richtig, denn der URI in der Taglibrary-Definition sollte "http://java.sun.com/j2ee/dtds/web-jsptaglibrary_1_1.dtd" heißen (d.h. "jsptaglibrary" statt "jsptaglib"). Allerdings fragt man sich, wieso so etwas bislang auf allen Servern anstandslos gelaufen ist und nur der neue JBoss hier Probleme bereitet. Angeblich, weil JBoss etwas strikter im Umgang mit XML-Validierung geworden ist.

Die Lösung für dieses Problem ist zwar einfach, aber irgendwie nicht akzeptabel:
man extrahiert bsf-2.3.0.jar, editiert unter META-INF/taglib.tld die Datei und
ersetzt den obigen String mit seiner korrekten Version. Danach packt man das JAR wieder zusammen und ersetzt das alte. Fehler beseitigt.

Danach wird sich herausstellen, dass die Applikation wieder startet, aber nicht in allen Fällen funktioniert. Es kommt zu JSP-Compile-Fehlern. Nach längerem, scharfen Hinsehen entdeckt man, dass einige Struts-Tags in den JSPs das Problem verursachen. Nämlich solche Kandidaten wie <html:select> oder <html:option>.
Diese Tags haben Inhalt (aka "body-content"), bei option z.B. die Beschriftung, wenn sie denn nicht aus einem Ressource-File kommt. In der TLD dieser Tags fehlt aber der Hinweis auf den "body-content". Wenn man zu diesem Konfigurationseintrag etwas näher in der JSP-2.1-Spezifikation stöbert, kommt man zu dieser Stelle (S. 3-37, JSP-Spec 2.1):

"body-content: Specifies the format for the body of this tag. The default in JSP 1.2 was 'JSP' but because this is an invalid setting for simple tag handlers, there is no longer a default in JSP 2.0."

Das heißt, weil in der Tag-Library-Angabe der body-content fehlt, quittiert die JBoss 6-JSP-Runtime diese Tags mit einem Compile-Fehler, allerdings ohne sinnvolle Fehlerangabe. Man sieht nur NullPointerExceptions.

Die Lösung ist auch hier so simpel wie unverzeihlich: analog zum oben erwähnten Vorgehen bei der bsf.jar muss man die Datei struts-taglib-1.3.10.jar (Struts 1.3.10 vorausgesetzt natürlich) von Hand ändern, genauer gesagt die Datei META-INF/tld/taglib.tld, und überall wo der Autor dieser Datei davon ausging, wenn er body-content nicht angibt, dass dann der Default "JSP" zieht, ein explizites

<body-content>JSP</body-content>

einfügen. Das wars "auch schon". Man muss nur darauf kommen.

Abschließend kann man eigentlich nur resignierend resümmieren, dass es ja schön ist, wenn JBoss sich an die Spezifikationen hält und dass es natürlich nicht schön von Sun/Oracle ist, Defaults nachträglich zu entfernen. Aber es ist schon komisch, dass sich beispielsweise die letzte JBoss-Version 5.1, die auch schon JSP 2.1 implementiert hat, daran nicht störte.

Ist das vielleicht auch der Unterschied zwischen Open-Source-Software und den (oftmals teuren) Produkten großer Hersteller?

von Roman Seibold

Leider handelt es sich bei dem nachfolgenden Artikel um einen Aprilscherz. Weil der Grundgedanke dahinter aber sehr verführerisch ist, lassen wir den Text mal solange hier stehen, bis Oracle so etwas tatsächlich implementiert :-) Trotzdem wird man bei dem Cloud-Thema doch die eine Frage nicht los: "wo genau sind denn meine Daten jetzt bitteschön?"

Eine Neuigkeit für alle Interessierte: seit Java 6.0.24, der seit einigen Tagen verfügbaren neuesten Java-Version, sind für das Collection-Framework auch Cloud-Funktionen hinzugekommen und es wurden, der üblichen Sun- bzw. Oracle-Philosophie für Minor-Updates zum Trotz, neue Klassen im Paket java.util hinzugefügt. Ausgangssituation war wohl die Klage vieler Firmen, die sich gerade im serverseitigen Bereich auf Java verlassen, das häufige Auftreten der gefürchteten java.lang.OutOfMemoryErrors. In vielen solcher Fehlersituationen hat sich bei Analysen von Heap-Dumps gezeigt, dass der Speicher hauptsächlich von Collections belegt war und dass die Daten von diesen Collections eben, da noch "hart" referenziert, bei einem Garbage Collector-Lauf nicht freigegeben werden können.
Was liegt da näher, als die Daten in die Cloud auszulagern? Damit wird der knappe Speicherplatz auf dem lokalen Server wieder verfügbar und ein OutOfMemoryError ist hoffentlich Geschichte.

Neu im API sind u.a. die Klassen CloudList und CloudSet. Hier ein kleines Beispiel:

List<HeavyObject> list =
 CloudList<HeavyObject>.createSomewhere();
list.add(new HeavyObject(...));


Im obigen Beispiel kann man sehen, dass man die CloudList nicht mit new anlegt, da ansonsten deren Daten ja im lokalen Speicher verortet wären. Die createSomewhere- Methode agiert hier als Factory, die es gestattet, den günstigsten und schnellstmöglich erreichbaren Speicher zu allozieren und liefert die passende Implementierung. Danach "belastet" nur noch ein Proxy-Objekt den lokalen Speicher, der Rest der Daten liegt in der Cloud.

Damit auch bereits bestehende Collection-Klassen wie ArrayList, HashSet und co. vom neuen Feature profitieren können, wurde die Implementierung der bestehenden Klassen von Oracle einfach erweitert, bleibt dabei aber vollständig rückwärtskompatibel. Ein- und Ausschalten kann man die Erweiterung jetzt über ein System-Property use.cloud.feature, womit auch Altanwendungen ganz leicht in die Cloud gebracht werden können.


Integrieren Sie das System-Property ganz einfach in Ihre bisherige Kommandozeile, z.B.

java -Xmx512m -Duse.cloud.feature=true de.aformatik.Start

Interessant ist das Feature natürlich vor allem im Einsatz auf Application Servern, z.B. bei WebSphere oder JBoss. Hier muss man natürlich an unterschiedlichen Stellen eingreifen, um die etwas versteckte Startkonfiguration zu erreichen und damit das Property eintragen zu können. Bei WebSphere wäre das entweder über die Admin-Konsole unter server > Java and Process Management > Process Definition > Java Virtual Machine oder direkt in der Datei server.xml, dort unter

<jvmEntries ...
genericJvmArguments="-Xquickstart -Duse.cloud.feature=true">

Bei JBoss wäre dies ein Eintrag in der run.conf-Datei, dort einfach in der JAVA_OPTS-Variable die entsprechende Ergänzung machen.

So, das wars für dieses Mal. Wir wären natürlich sehr interessiert daran, ob und wie sich das Speicher- und Laufzeitverhalten Ihrer Applikationen verändert. Schreiben Sie uns doch einfach einen Kommentar und tauschen Sie mit anderen Interessierten Ihre Erfahrungen aus.

Wir freuen uns schon auf neue Erkenntnisse!

von Benjamin Reimold

Dieser Tage fand in Barcelona mit dem „Mobile World Congress“ die weltweit größte Branchenveranstaltung zum Thema „Mobile Computing“ statt und auch sonst kommt zur Zeit kaum eine Publikation, sei es nun Website, Zeitschrift oder Zeitung, ohne einen Beitrag zu den Themen Tablets, iOS, Android, neuen Smartphone Modellen, der Allianz zwischen Nokia und Microsoft oder Tipps zu den besten/neuesten/verrücktesten Apps aus. Doch was bedeuten Smartphones, Tablets und der App-Hype für Unternehmen auf der einen und uns Entwickler und Consultants auf der anderen Seite?

Zunächst lohnt sich, wie so oft in den Hoch-Zeiten eines Hypes, ein Schritt zurück, inklusive tiefem Luftholen und einer Tasse Tee, um die teilweise doch hochemotional geführten Glaubenskriege um Apps, Plattformen und den Krieg der Ökosysteme etwas pragmatischer zu betrachten.

Blickt man in der Historie einmal knapp 10 Jahre zurück, so finden sich mit Blackberry OS, Symbian OS und Windows Mobile drei Plattformen, deren Wurzeln teilweise sogar in den späten 1990er Jahren liegen und die mehr oder minder nebeneinander mobilen Zugriff mittels PDA bzw. Mobiltelefon auf Firmenemail und Kalender, Dokumente oder, in besonders fortschrittlichen Nutzungsszenarien, auch erweiterte Funktionalität beispielsweise im Außendienst boten.

Seit Apple mit dem iPhone den Markt 2007 aufrollte und mit dem Konzept des AppStores das Spiel grundlegend änderte und, so kommt es dem geneigten Entwickler zumindest vor, zu DER Referenzplattform für Smartphones wurde, verkomplizierte sich die bis dato relativ leicht zu überblickende Situation der „smart devices“ in den Unternehmen. Am einfachsten lässt sich das nun aufkommende Phänomen mit einem Klischee beschreiben: Ein  Manager, der im privaten Umfeld iPhone und iPad kennenlernt ist von den Geräten so begeistert, dass er diese „smarten“ Geräte auch bei der Arbeit einsetzen möchte.

Dieses Phänomen stellt einen kompletten Paradigmenwechsel der Technologieadaption dar. Klassisch wurde Innovation von Unternehmen zuerst genutzt, um nach einiger Zeit vom Konsumentenmarkt aufgegriffen zu werden. Mit dem iPhone, das in dieser Hinsicht wirklich den ersten „Game Changer“ darstellt, finden Innovationen zunächst für den Konsumenten statt, um dann von unten nach oben in die Unternehmen vorzudringen. Dieses Phänomen lässt sich mit dem Anglizismus „consumerised IT“ sehr gut zusammenfassen.
Verkompliziert wird dieser neue Prozess zusätzlich durch die Vielfalt der mobilen Plattformen und die rasante und undurchsichtige Entwicklung des noch jungen Marktes. Android, vor einem Jahr noch kaum in der Praxis vertreten und nur in der „Szene“ bekannt, trat einen rasanten Siegeszug im Konsumentenmarkt an (Marktanteil laut statcounter.com knapp über 20%). Windows Phone 7, HPs webOS, Symbian und MeeGo von Nokia – all diese Plattformen buhlen um die Gunst des Konsumenten und letztlich, stehend und fallend mit ihrer Verbreitung, auch um die Gunst der Unternehmen. Erkannt hat dies zum Beispiel Samsung, die ein eigenes Vetriebs- und Support-Team für Firmenkunden aufbauten und gezielt ihre Smartphones und Tablets mit dem Android OS an die Firmen bringen möchten.

War bisher lediglich der Managementebene der Einsatz der Smartphones und Tablets vorbehalten, so lässt sich in den letzten Monaten ein gesteigertes Interesse am unternehmensweiten Einsatz beobachten.

An dieser Stelle möchte ich kurz anmerken, dass ich auf die auftretenden Sicherheits- und Administrationsprobleme an dieser Stelle nicht eingehen möchte, dieser Blogeintrag ist auch so lang genug. ;-)

Hierbei zeigt sich für mich eine interessante Entwicklung. Musste man vor ein bis eineinhalb Jahren noch die Formfaktoren erklären (vom iPad war zu dieser Zeit ja nicht mehr als ein Gerücht an die Öffentlichkeit gedrungen), so ist nun die Attraktivität der Formfaktoren „Smartphone“ und „Tablet“ allgemeiner Konsens. Schwieriger sieht es da schon mit dem Einsatz der Geräte aus. Mehr als E-Mail, Websurfen, soziale Netzwerke (Facebook, Twitter, ...) sowie vereinzelter Dokumentenzugriff ist bisher im Business-Umfeld kaum zu sehen. Sicher, Apps werden als allgegenwärtige Marketingmöglichkeit verstanden. Nicht im „AppStore“ vertreten zu sein möchte sich kaum eine Marke heute leisten. Die Realität sieht jedoch, betrachtet man die Nutzung von Apps im Geschäftsumfeld, relativ nüchtern aus: Serviceangebote von Bahn und Verkehrsnetzen, Check-in über die Lufthansa-App, Notizzettel, Wetterinformationen, Maps und Navigation – im Business-Einsatz sind nur wenige Applikationen von Relevanz . Ein Grund ist sicherlich, dass gerade größere Firmen langsamer, aber auch langfristiger planen und den Einsatz vieler Apps schlicht weg nicht erlauben.

Gerade hier sehe ich nun das immense Potential der mobilen, smarten Geräte: Noch nutzen nur sehr wenige Apps die Hardware richtig aus.

Was wäre, wenn der Außendienstmitarbeiter Inhalte und Funktionalitäten des Intranet-Portals mit einer angepassten GUI, offline, unterstützt durch GPS, der Kamera als Barcode-Scanner oder einfaches OCR-System nutzen könnte? Was wäre, wenn der Teamleiter oder Lagermitarbeiter mit einem hosentaschentauglichen Gerät neben der Speisekarte der Kantine auch noch auf seine Reisekostenabrechnung, seine Urlaubsplanung und den firmeninternen Kleinanzeigenmarkt zugreifen könnte? Gleichzeitig können mittels „Near Field Communication“-Chip Warensendungen aufgenommen und gescannt werden. Über Spracherkennung lassen sich Texte nahezu freihändig diktieren und Formulare ausfüllen. Und das alles in einem Gerät, das ab 300,-€ verfügbar ist, mit einem Gewicht von 100-160g in jede Jacken- oder Hosentasche passt und das einen 10 Stunden Arbeitstag ohne Ladepause durchsteht. Die Vielzahl an Möglichkeiten ist teilweise schier unfassbar, manchmal gar unwirklich.

Sicherlich ist, bevor diese Visionen Wirklichkeit werden können, eine genaue Analyse, welche Plattform und welcher Formfaktor zum Einsatz kommen soll, nötig, doch ich konnte hoffentlich auch so schon ein wenig zeigen, welche Möglichkeiten hier offen stehen. Nicht umsonst bezeichnen manche die smarten Geräte als „mobile Revolution“.

Erste Praxiseinsätze, zum Beispiel die Deutsche Bahn mit ihrer Anwendung für Zugbegleiter (http://mobile360.de/deutsche-bahn-nutzt-android-32457.html), gibt es schon. Sie zeigen, dass eine App mehr sein kann als nur ein neues Interface für die Firmen-Webseite oder den Produktkatalog. Es liegt also an uns, den Entwicklern, den Unternehmen die wirklichen Möglichkeiten und das enorme Potential vor Augen zu führen. Ohne einen wirklichen Mehrwert, wie beispielsweise die neuen Hardware-Features in die Apps zu integrieren, die  wird das sicherlich nicht zu schaffen sein, doch zeigen uns bereits jetzt Umsetzungen und vielleicht auch dieser Blogeintrag ein wenig, wo die Reise hingeht.

von Alexander Frey

eine kleine Warnung an alle, die Eclipse zusammen mit Java 6 Update 21 (z.Zt. aktuellste Version) einsetzen wollen: es funktioniert nicht Out-Of-The-Box, es gibt aber Workarounds. Betroffen sind anscheinend alle Eclipse-Versionen von 3.3 bis 3.6 (Helios) und zwar nicht nur die IDE, sondern auch RCP-Anwendungen.

Hintergrund:

Der Eclipse-Launcher liest vor dem Java-Start unter Windows aus einer Binär-Datei die Firma der JVM aus und setzt entsprechende Parameter beim JVM-Start (passend zur VM). Bis einschließlich Update 20 war die Firma "Sun Microsystems, Inc", bei Update 21 ist es nun "Oracle" (es handelt sich hierbei nur um den Hersteller-String in einer Binär-Datei, nicht um das Property "java.vendor").

In der Folge erkennt der Launcher nicht, dass eine VM mit Hotspot gestartet wird, sondern hält die VM für JRockit. JRockit kennt leider den Parameter "-XX:MaxPermSize" nicht, weshalb der Launcher diesen Parameter nicht setzt. Bei Hotspot wird der Parameter aber dringend benötigt, da es sonst zu einem Out-Of-Memory im PermGen Space kommt.

Empfohlene Workarounds (Zitat von Eclipse.org):

  1. switch back to '1.6.0_20'
  2. add the following line after "-vmargs" to your eclipse.ini:-XX:MaxPermSize=256m

Der entsprechende Fehler unter bugs.sun.com deutet darauf hin, dass diese Änderung in der Binär-Datei wieder rückgängig gemacht wird. Wenn das nicht passieren sollte, bekommen alle Eclipse und RCP-Anwedungen mit dem nächsten automatischen Java-Update ein Problem (Update 21 ist kein Security-Update und wird deshalb nicht über den Java-Updater automatisch verteilt).

Mehr Infos gibt es hier:

https://bugs.eclipse.org/bugs/show_bug.cgi?id=319514
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6969236

von Sebastian Petzelberger

Ein Refactoring Snippet zeigt ein kleines Problem auf und gibt eine kleine Lösung dazu an. Die Problemstellungen kommen aus der Projektarbeit. Die Snippets sollen kleine Hilfen sein. Außerdem sollen sie generell zum Refactoring anregen, aber auch zu einer Diskussion darüber einladen.

Refactoring Snippet: Überflüssige Hierarchie
Vorstellung
In einem Projekt waren über einem Dutzend Klassen wie die folgenden zwei aufgebaut:

public class UpButton extends JButton
{
  public UpButton()
  {
    this.setBorderPainted(false);
    this.setMaximumSize(new java.awt.Dimension(20, 20));
    this.setMinimumSize(new java.awt.Dimension(20, 20));
    this.setPreferredSize(new java.awt.Dimension(20, 20));
    this.setIcon(new javax.swing.ImageIcon(getClass().
 getResource("/xxx/xxx/images/Up16.gif")));
  }
}
public class TopButton extends JButton
{
  public TopButton()
  {
    this.setBorderPainted(false);
    this.setMaximumSize(new java.awt.Dimension(20, 20));
    this.setMinimumSize(new java.awt.Dimension(20, 20));
    this.setPreferredSize(new java.awt.Dimension(20, 20));
    this.setIcon(new javax.swing.ImageIcon(getClass().
    getResource("/xxx/xxx/images/Top16.gif")));
  }
}

kleine Probleme

Auffällig ist:

  • Viele neue Klassen
  • Redundanz

Eine Unterklasse stellt neue Funktionalität bereit, die in neuen Methoden umgesetzt werden. Hier haben die Unterklassen keine neue Funktionalität.

Es kommt auch vor, dass vorhandene Funktionalität allgemein ausgeprägt in der Unterklasse speziell umgesetzt wird. Das wäre ein Überschreiben von vorhandenen Methoden der Oberklasse. Das hätte hier Anwendung finden können. Es wäre konsequent gewesen, die Methoden getMaximumSize, getPreferredSize und getIcon zu überschreiben. Der Code hätte so die Notwendigkeit von eigenen Klassen eher wieder gespiegelt, doch neue Funktionalität hätte trotzdem gefehlt. Gut, dass dies nicht so umgesetzt wurde, denn jetzt ist es leichter zu einer einfacheren Lösung zu kommen.  

kleine Lösung

Die oben angeführten zwei Beispiele verwenden jeweils eine Methode zum Konstruieren. Wieso nicht stattdessen eine Methode zum Erzeugen verwenden? Mein Vorschlag, eine Dienstmethode:

public static JButton createIconButton(String resource)
{
 JButton iconButton = new JButton();
 iconButton.setBorderPainted(false);
 iconButton.setMaximumSize(new Dimension(20, 20));
 iconButton.setMinimumSize(new Dimension(20, 20));
 iconButton.setPreferredSize(new Dimension(20, 20));
 iconButton.setIcon(new ImageIcon(getClass()
 .getResource(resource)));
 return iconButton;
}

Das ist nur eine erste Refactoring Maßnahme. Mein Vorschlag selbst ist natürlich noch nicht fertig. Es sind immer noch Redundanzen vorhanden, beispielsweise "new Dimension(20, 20)". Ein weiteres Refactoring ist nicht nötig, da hier nur auf überflüssige Hierarchien hingewiesen werden soll.  

Beurteilung

Wer neuartige Widgets programmiert, der benötigt (eventuell) Hierarchie. Wer aber nur zusammenbaut, der tut das besser in einer Dienst-Methode. Es ist immer die einfachere Lösung zu wählen. Eine neue Klasse ist viel mächtiger als nur eine neue Methode. Bei dem obigen Beispiel haben wir noch den Vorteil, dass der vorliegende Code nur eine Methode beinhaltet. Das Prinzip ist: Nicht vererben, sondern zusammenbauen. Es soll nicht ganz auf Hierarchien verzichtet werden, der Einsatz sollte in der Praxis nur etwas kritischer geschehen.

Es gab mal einen bekannten Swing GUI-Builder, der beliebt war aufgrund der einfachen weil visuellen Handhabung GUIs zusammenzubauen. Mein größter Kritikpunkt an diesem war, dass so viele Programmierer dann auch so entwickelt haben, wie der GUI-Builder den Swing-Code erzeugt hat. Eine noch harmlose Unsitte war, dass jede GUI-Klasse eine Unterklasse von JPanel war. Eine GUI-Klasse baut ein JPanel zusammen, ist keine neue Art von JPanel. Die riesige Methodenpalette von der Vererbungshierarchie von JPanel interessiert nur beim Zusammenbauen des JPanels, also in einer Methode. Die eigenen geschrieben Methoden der GUI-Klasse sind im Code-Assistent kaum zu finden. Das weist auch darauf hin, dass Hierarchie hier kein geeignetes Mittel ist.

In dem einen oder anderen Beispielcode von SUN sind die GUI-Klassen eine neue Art von JFrame. Eine Gui-Klasse baut ein JPanel zusammen. Dieser kann dann per Dienstmethode in einen JFrame gesetzt werden ODER in einem JDialog ODER in einem anderen JPanel Verwendung finden. Letzteres wenn nämlich eine übergeordnete GUI-Klasse diesen benutzt.