20.07.2010
11:43

Java 6 Update 21 und Eclipse

Alexander Frey ist Consultant bei aformatik

 

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

 

 

 

 

13.07.2010
16:46

Refactoring Snippets

Sebastian Petzelberger Senior Consultant bei aformatik

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.

 

09.11.2009
16:02

Refactoring Snippet: Closure

Sebastian Petzelberger Senior Consultant bei aformatik

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

Vorstellung

Folgende Methodeninhalte kommen in dem Client-Code vor.

Ganz allgemein formuliert haben wir an einer Stelle:

	a();
x1();
b();

an einer anderen:

	a();
x2();
b();

usw. mit weiteren xn.

 

kleine Probleme

Redundanz: Das Problem ist hier bereits minimiert aufgeführt, weil die wiederkehrenden Aufrufe in den Methode a() und b() zusammengefasst sind. Ein Rest an Redundanz liegt noch vor.

Abhängigkeit: Hier nach dem Motto: "Wer a sagt, der muss auch b sagen!". Das halte ich für noch gewichtiger als die Redundanz. Obwohl oft entgegengehalten wird, dass doch jeder weiß, dass auf a() auch b() folgen muss. Aber genau das sollte der Code widerspiegeln. Es soll kein externes Wissen geben, sondern der Code soll exakt das sprechen, was eben zu sprechen ist. So verstehe ich gute Programmier-Sprache.

Fehleranfälligkeit: Eine Java-Methode darf - entgegen älterer Konventionen - mehrere Ausgänge haben. Diese werden bekannterweise mit return realisiert. Nun kann es passieren, dass bei einem Ausgang der Methode das b() nicht mehr erfolgt. Wenn eine Methode kurz und übersichtlich ist, wie sie sein sollte, kann dies noch recht einfach vermieden werden. In der Praxis können Methoden jedoch durchaus komplexer und unübersichtlicher werden und somit durchaus die Ausführung von b() mal unter den Tisch fallen.

Praktisch relevanter formuliert sieht das Problem wie folgt aus:

	open();
x1();
close();

kleine Lösung

Zuerst einmal wird ein Interface benötigt:

public interface Executor 
{
public void execute();
}

 

Dann wird eine Utility-Methode erstellt. Sie hat eine Instanz des Interfaces als Parameter und sorgt für die a/b Klammer, hier jetzt open/close.

public static void handle(Executor executor) 
{
open();
executor.execute();
close();
}

 

Jetzt können die Stellen im Client-Code verbessert werden, durch:

Executor executor =
new Executor()
{
public void execute() {x1();}
};

Utils.handle(executor);

 

Beurteilung

Vorteile: Auflösung der Redundanz. Keine Abhängigkeiten mehr. Im Client-Code wird nicht mehr geöffnet und geschlossen, und dadurch die Fehleranfälligkeit minimiert.

Nachteile: So klein ist die Lösung dann doch nicht. Der Code ist schwieriger zu verstehen.

Mein Urteil: Vielleicht gibt es mal in einer späteren Java-Version für die Umsetzung eine kürzere Notation. Es wird zwar viel beschrieben, aber inhaltlich eben eingespart. Ich bin für eine Einführung in ein Projekt, vor allem dann, wenn Probleme mit fehlendem close auftauchen. Da darf dann auch das Argument mit dem schwierigerem Code nicht ziehen, letztlich gehört die hier beschriebene Lösung zum Java-Standard. Es muss ja nicht jeder Mitarbeiter eine derartige Lösung selber entwickeln. Es muss nur die vorgefertigte Lösung anhand eines Beispiels nachvollzogen werden. Ich bin ein Pragmatiker und würde diese Lösung nicht für ein Projekt vorschlagen, wenn dies nur wenige Stellen betreffen würde.

praktisches Beispiel

Hier wird die Verbindung zu einer Datei verborgen. Auch möglich wäre eine derartige Einführung für die Verbindung zur Datenbank. Das Executor-Interface ist wie folgt deklariert:

import java.io.IOException;
import java.io.PrintWriter;

public interface WriteExecutor
{
public void execute(PrintWriter out) throws IOException;
}

Die Utility-Methode ist hier in einer Util-Klasse implementiert:

import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

public abstract class IOUtilsExample
{
public static void write(String filename,
WriteExecutor executor)
throws IOException
{
PrintWriter out =
new PrintWriter(new FileWriter(filename));
executor.execute(out);
out.close();
}
}

 

Jetzt der Client-Code:

WriteExecutor executor =
new WriteExecutor()
{
public void execute(PrintWriter out)
{
// jetzt kann mit out gearbeitet werden
}
};

IOUtilsExample.write("example.txt", executor);

 

Das Beispiel selbst ist natürlich noch nicht perfekt. Zum Beispiel kann hier eine Exception beim Schreiben dazu führen, dass das close() nicht aufgerufen wird. Aber der Nutzen des Closure Refactoring Snippet kommt dennoch sehr gut heraus.

04.11.2009
14:56

Noch mehr Property-File-basierte Konfiguration bei IBM WebSphere Application Server V7

Roman Seibold, Senior Consultant und technischer Leiter der Schulungsabteilung von aformatik

von Roman Seibold

In meinem letzten Beitrag zum Thema WebSphere habe ich von der neuen Möglichkeit des WebSphere Application Servers V7 berichtet, mit sogenannten Property-Dateien Konfigurationsdaten auszulesen und zu verändern. [Beitrag]

Heute möchte ich ein paar zusätzliche Worte zu diesem neuen Feature verlieren.

Zunächst einmal nochmals zur Erinnerung. Über wsadmin, und nur über wsadmin, der skriptgesteuerten Konfigurationsvariante des Applicationservers, konnte man sich mit

 

AdminTask.extractConfigProperties(
'-propertiesFileName demo.props')

eine Datei namens "demo.props" im Property-Format ("property=value" Paare) besorgen.
Ein besonderes Property-Format, weil Reihenfolgen auch eine Rolle spielten.

Wenn man sich die erzeugte Datei genauer ansieht, trifft man in manchen Zeilen auf merkwürdige Einträge, wie z.B. diesen hier:

 

WC_defaulthost=9080:!{hostName1} # integer

WC ist hier nicht das, woran man eventuell in einem ersten schwachen Moment denkt, sondern die bei IBM oft genutzte Abkürzung für "Web-Container". Der Web-Container-Default-Host hat also Port-Nummer 9080, eine Zahl, die gestandene WebSphere-Kenner nicht überraschen sollte.
Für ein Property liegt aber dennoch ein merkwürdiges Format vor, da nach dem Wert 9080 noch eine weitere Information folgt :!{hostName1}. Der Zusatz # integer ist ein Kommentar bezüglich des Wertebereiches für das Property.

hostName1 hingegen ist eine Variable, mit der die Property-Files erst so richtig interessant werden. Definiert werden die Variablen in frisch erzeugten Property-Files immer ganz am Ende. Dort findet man folgenden Abschnitt:

 

#
EnvironmentVariablesSection
#
#
#Environment Variables
hostName2=localhost
hostName1=*
cellName=was70host00Cell01
nodeName=was70host01Node01
hostName=was70host01
serverName=server1

Man könnte jetzt die Variablen-Sektion verändern, wenn man die Werte auf einen anderen Server aufspielen will. Interessanter ist aber, diesen Teil ganz aus der Property-Datei zu entfernen und in eine eigene Datei zu legen, die dann nur aus der Environment- Variables-Section besteht. Nennen wir das File "var.props". Hierin kann man dann auch eigene Variablen definieren, z.B.

 

WC_defaulthost_value=9080

Und in der anderen Datei - "demo.props" - die weiter oben zitierte Zeile anpassen

 

WC_defaulthost=!{WC_defaulthost_value}:!{hostName1}

Jetzt haben wir eine generischere Konfigurationsdatei und eine Datei, in der die Variablen gemappt werden. Beide kann man von wsadmin zusammenführen lassen und validieren. Nach erfolgreicher Validierung lässt sich alles wieder zurück in das Konfigurationsarchiv übertragen:

 

AdminTask.validateConfigProperties(
'-propertiesFileName demo.props
-variablesMapFileName var.props')
AdminTask.applyConfigProperties(
'-propertiesFileName demo.props
-variablesMapFileName var.props')
AdminConfig.save()

Man kann also mit -variablesMapFileName ein weiteres File angeben, in dem nur die Variablen und ihre derzeitige Belegung enthalten ist. Mit einer weiteren Option -variablesMap lassen sich sogar direkt im wsadmin-Command die Properties belegen.
Das ist natürlich nur sinnvoll, wenn man wenige Variablen hat, oder wenn wsadmin als Skriptfile (vielleicht sogar mit Parametern) ausgeführt wird und man die Map programmatisch füllen kann. Leider funktionieren die beiden Optionen nicht zusammen. Die Idee, die größere Anzahl an Variablen im Map-File bereits zu setzen und dann einige über die Command-Line nachträglich zu liefern, ist den WebSphere-Architekten offenbar nicht gekommen. Hier gilt ein striktes "Entweder-Oder", ansonsten erntet man NullPointerExceptions.

Trotzdem, schon bei diesem simplen Beispiel deutet sich an, wie flexibel und mächtig dieses neue Feature dennoch ist. Man kann komplette Konfigurationen vorgeben, die einige variable Teile enthalten und diese - und nur diese! - werden dann jeweils ersetzt. Viel einfacher als ein Skript,
viel wiederverwendbarer als eine Administration über die Web-Oberfläche.

Probieren Sie es einfach mal aus und schreiben Sie uns Ihre Erfahrungen - wir freuen uns auf Ihre Kommentare.

Bis dahin verbleibe ich mit konfigurativen Grüßen, Ihr

Roman Seibold

07.10.2009
14:21

Der lästige Knoten im Webserver

von Roman Seibold
Sie erinnern sich an meinen Beitrag zur Property-File-basierten Konfiguration von WebSphere Application Server V7. Bei weiteren Erkundungen zu diesem Thema habe ich mein Interesse auch auf eine ganze WebSphere-ND-Zelle ausgeweitet, die wie folgt aufgebaut ist:
[mehr]