http://www.javapolis.com/JP06/campaign/index.php
Allgemein
Three Visual Eclipse Tutorials
- onEclipse – Eclipse – The Visual Tutorial (commercial, some free)
- eclipse-tutorial on java.net (free)
- Eclipse Video Courseware (free)
Sad to see, that all tutorials are old and based on Eclipse 3.1 or Eclipse 3.0.
Das oberste Stack-Element duplizieren
Die Klasse Stack besitzt zwar die Basisfunktionalität, die ein Stapel besitzen sollte, aber auch nicht mehr. Hin und wieder wünschen wir uns aber eine Funktion, die das oberste Stack-Element dupliziert, kurz dup().
Bei der Implementierung treten allerdings zwei Fragen auf, mit denen zwei völlig unterschiedliche Lösungsansätze verbunden sind. Da die Klasse Stack wie die anderen Datenstrukturen auf Objekte ausgelegt ist, müssen wir uns darüber Klarheit verschaffen, wie das obere Objekt dupliziert werden soll. Soll eine Kopie der Objekt-Referenz neu auf den Stapel gelegt werden oder etwa das gesamte Objekt geklont werden?
Die einfache Lösung
Die einfachste Lösung besteht darin, das oberste Objekt einfach mittels der schon vorhandenen Stack-Methoden push() und peek() draufzulegen. Nehmen wir an, wir haben eine Unterklasse DupStack, dann sieht die erste Variante zum Clonen so aus:
void dup() /* throws EmptyStackException */
{
push( peek() );
}
peek() gibt aber lediglich eine Referenz auf das Objekt zurück. Und das anschließende push() speichert diese Referenz dann auf dem Stapel. Nehmen wir an, wir haben zwei StringBuffer-Objekte auf dem Stapel. Wenn wir nun dup() aufrufen und den String ändern, der oben auf dem Stapel liegt, so ändern wir automatisch das zweite Element gleich mit. Dies ist aber nicht unbedingt beabsichtigt, und wir müssen uns Gedanken über eine alternative Lösung machen. Wir sehen, dass dup() in der Klasse Stack fehlt, weil seine Implementierung davon abhängt, ob eine Referenz- oder eine Wertsemantik für Kellerelemente gewünscht ist.
Die kompliziertere Lösung mit Klonen
Um das oberste Stack-Element zu kopieren, bietet sich die clone()-Methode von Object an. All die Objekte, die sich klonen lassen, und das sind längst nicht alle, implementieren das Interface Cloneable. Nun ließe sich einfach folgern: Wenn das zu duplizierende Objekt ein Exemplar von Cloneable ist, dann können wir einfach die clone()-Methoden aufrufen und das zurückgegebene Objekt mittels push() auf den Stapel bringen.
void dup2() throws CloneNotSupportedException
{
try
{
Object top = peek();
if ( top instanceof Cloneable )
push( top.clone() );
}
catch ( EmptyStackException e ) { }
}
Beziehungsweise
void dup3() throws CloneNotSupportedException /*, EmptyStackException */
{
push( peek().clone() );
}
Dies funktioniert für die meisten Objekte, allerdings nicht für Objekte der Klasse Object. Denn clone() der Klasse Object ist protected – wir dürfen also von außen nicht dran, nur eine Unterklasse und die Klasse selbst. Hier haben wir also zwei Probleme.
- Leider lässt sich nur mit Aufwand überprüfen, ob das Objekt auf dem Stapel auch wirklich ein pures Object ist, denn alle Objekte sind instanceof Object. Glücklicherweise gibt es kaum eine Anwendung, wo reine Object-Elemente gesichert werden müssen.
- Was machen wir mit Objekten, die nicht klonbar sind? Leider gibt es für diese Frage keine direkte Antwort. Eine universelle Stack-Klasse mit einer uneingeschränkten dup()-Methode gibt es nicht. Wir müssen als Stack-Benutzer festlegen, dass das oberste Element Clonable ist, um zumindest eine eigene Implementierung nutzen zu können. Oder wir bleiben dabei, bei nicht klonbaren Objekten doch nur die Referenz zu duplizieren. Das wäre zumindest für eineindeutige Objekte mit Wertsemantik die ideale Lösung.
Change insets/margin of a swing button
Use this before you start the program:
UIManager.put( "Button.margin", new InsetsUIResource(10, 20, 10, 20) );
BTW: To global change the icon of you JTree use:
Icon leafIcon = new ImageIcon( bla );
UIManager.put( "Tree.leafIcon", leafIcon );
UIManager.put( "Tree.openIcon", openIcon );
UIManager.put( "Tree.closedIcon", closedIcon );
Inselraus: Die Datenbank Derby
Derby (http://db.apache.org/derby/) ist ein pures Java-RDBMS unter der freien Apache-Lizenz. Die Datenbank geht auf Cloudscape zurück, was IBM Mitte 2004 auf der LinuxWorld in San Francisco der Apache Software Foundation übergeben hat. (1999 übernahm Informix Software Inc.XE „Informix Software Inc.“ die Datenbank Cloudscape von Cloudscape Inc., doch IBM übernahm die Datenbanktechnologien von Informix im Jahre 2001.) Ein großer Vorteil von Derby sind neben dem geringen Speicherbedarf die Transaktionsunterstützung, Trigger und SQL-Kompatibilität mit DB2.
Download und Vorbereitung
Auf der Download-Seite befinden sich drei Archive, wovon wir eine Datei mit der Endung -bin beziehen (etwa db-derby-10.1.1.0-bin.zip) und auspacken. Wir nehmen zu Testzwecken c:\Programme\derby an, sodass in C:\Programme\derby\frameworks\NetworkServer\bin die Skripte zum Starten und Stoppen des Servers zu finden sein sollten.
Derby lässt sich in zwei Modi fahren: als eingebettetes Datenbanksystem und als Netzwerkserver. Im Fall eines eingebauten Datenbanksystems ist lediglich die Klasse für den eingebetteten Treiber zu laden und die Datenbank zu bestimmen, schon geht’s los:
Class.forName( „org.apache.derby.jdbc.EmbeddedDriver“ );
Connection con = DriverManager.getConnection( „jdbc:derby:OpenGeoDB;create=true“ );
Wir wollen Derby als Netzwerkserver starten, um mit unterschiedlichen Clients – etwa einem Eclipse-Plugin – auf die Datenbank zugreifen zu können. In diesem Modus horcht Derby über TCP/IP an einem Port (standardmäßig 1527) auf eingehende Verbindungen.
Vor dem Start muss die Umgebungsvariable JAVA_HOME gesetzt sein, und DERBY_INSTALL auf das Installationsverzeichnis zeigen. Zunächst gehen wir in startNetworkServer.bat und setzen dort die nötigen Umgebungsvariablen:
Listing 20.1 startNetworkServer.bat
…
@REM — This file for use on Windows systems
@REM ———————————————————
@echo off
set JAVA_HOME=C:\Programme\Java\jdk1.5.0
set DERBY_INSTALL=C:\Programme\derby\
…
Ebenso setzen wir in startNetworkServer.bat die Umgebungsvariablen passend, da wir den Server auch wieder stoppen wollen.
Server-Start und weitere Tools
Nun lässt sich – etwa mit Doppelklick – das Skript startNetworkServer.bat starten, und die Datenbank quittiert freundlich:
Der Server ist bereit, am Port 1527 Verbindungen zu akzeptieren.
Das Programm sysinfo zeigt Versionsnummer und Klassenpfad an. Mit dem interaktiven Werkzeug ij lassen sich SQL-Anweisungen abschicken und so die ersten Versuche mit der Datenbank aufnehmen. dblook extrahiert das Datenbankschema.
JDBC-Treiber
Für einen JDBC-Zugriff ist ein JDBC-Treiber nötig, der bei Derby für eine Client-/Server-Kommunikation nicht dabei ist, denn Derby nutzt die Distributed Relational Database ArchitectureXE „Distributed Relational Database Architecture“ (DRDAXE „DRDA“), die auch DB2 verwendet. DRDA ist eine von der Open GroupXE „Open Group“ definierte Möglichkeit, von einem Client eine entfernte relationale Datenbank anzusteuern. Auf http://www-128.ibm.com/developerworks/db2/downloads/jcc/ ist die Datei db2jcc_for_derby.zip aufgeführt, die – nach einer Registrierung – auf der nächsten Seite unter »Released product: IBM Cloudscape (IBM DB2 JDBC Universal Driver, for Cloudscape/Derby)« heruntergeladen werden kann. Die beiden Jar-Dateien aus dem Archiv, db2jcc.jar und db2jcc_license_c.jar, sind in den Klassenpfad aufzunehmen. Für den Client-/Server- Modus von Derby benötigen wir keine weiteren Jar-Dateien, insbesondere keine aus dem lib-Verzeichnis von Derby.
Adjust font size in Swing applications global
Use this snippet to set the size of all fonts of the current Swing look and feel:
public static void setFontSizeGlobal( int size )
{
for ( Enumeration e = UIManager.getDefaults().keys(); e.hasMoreElements(); )
{
Object key = e.nextElement();
Object value = UIManager.get( key );
if ( value instanceof Font )
{
Font f = (Font) value;
UIManager.put( key, new FontUIResource( f.getName(), f.getStyle(), size ) );
}
}
}
Can we compact the code? Not with the extended for! It is true that UIDefaults is a subtype of Hashtable but the methods entrySet() or keySet() returns an empty collection.
JAXB 2.0 und XJC in einem Ant-Skript nutzen
Für Konfigurations-Dateien wollte ich JAXB 2.0 nutzen und es war wirklich einfach. Zuerst habe ich mit XMLBeans begonnen, was ebenfalls sehr einfach zu nutzen ist, doch die Annotationen gefielen mir bei JAXB 2.0 besser. Der Client, der auf die generierten Beans zugreift, muss nur geringfügig verändert werden, denn XMLBeans repräsentiert Unterelemente in einem Array, währenddessen JAXB eine Collection verwendet.
Nach dem Download von JAXB müssen sich für den Client im Pfad befinden: jaxb-api.jar, jaxb-impl.jar, activation.jar, jsr173_1.0.jar. Für den Ant-Task und die Generation von Klassen aus eine Schema-Datei ist jaxb-xjc.jar verantwortlich.
Für den Ant-Task meldet man (für Eclipse) am einfachsten alle genannten Java-Archive unter den Ant > Runtime > Classpath > Global Entries an. Die Ant-Datei nutzt für die Generation der Bean dann folgendes:
<project default="all" basedir=".">
<target name="all">
<xjc schema="schemas/ppt_join.xsd" target="../src/core"
package="com.javatutor.cw.ppt.jaxb.pptjoin" />
</target>
</project>
Die Schema-Datei sieht für meine Konfigurations-Dateien so aus:
<xs:schema
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:po="http://javatutor.com/pptjoin"
targetNamespace="http://javatutor.com/pptjoin"
elementFormDefault="qualified">
<xs:element name="ppt-join">
<xs:complexType>
<xs:sequence>
<xs:element name="options" type="po:options" minOccurs="0" maxOccurs="1" />
<xs:element name="fileset" type="po:fileset" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="fileset">
<xs:sequence>
<xs:element name="file" type="xs:string" minOccurs="0" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="options">
<xs:sequence>
<xs:element name="removeHidden" type="xs:boolean" minOccurs="0" maxOccurs="1" />
<xs:element name="destination-file" type="xs:string" minOccurs="0" maxOccurs="1" />
</xs:sequence>
</xs:complexType>
</xs:schema>
Nutze ich nun JAXB 2.0? Ehrlich gesagt nicht. Denn für kleine Konfigurationsdateien finde ich persönlich JAXB etwas zu aufwändig. Nun bin ich wieder am Anfang, bei XStream.
Buchkritik "UML Distilled"
Ein UML-Buch mit nur 180 Seiten ist in der Tat etwas besonderes, verglichen mit den 1.000 Seiten der UML 2.0 Dokumentation inklusive der vielen Zusatzdokumente wie MDA und so weiter. Dabei ist Fowlers Buch nicht oberflächlich, sondern er destilliert den Kern der UML, die Diagramme, und hält sich nicht mit Meta-Modellen auf. Vor der eigentlichen Notation fasst er auf etwa 30 Seiten Entwicklungsmethoden (wie RUP), Refactoring, Pattern zusammen. Dann folgen die bekannten UML-Diagramme, in der 3. Auflage auch die seit UML 2.0 neuen Timing-Diagramme. In der Schreibweise wählt Fowler einen persönlichen Stil, den ich besonders sympathisch finde. Er spricht häufiger in der Ich-Form und am offensten war das Satz zum Thema Umgang mit den politischen Schwierigkeiten in der Softwareentwicklung: „I can’t offer you any serious advice on this because I’m not a skilled corporate politician. I strongly suggest that you find someone who is.“ Das ist ein ganzes Kapitel!
In der Summe dürfte das Buch für diejenigen interessant sein, die einen schnellen, schmerzlosen Einstieg in UML suchen.