Seit einem Monat gibt es EventBus 1.3. Die Webseite spricht im Wesentlichen von zwei Neuigkeiten:
Mein Blog-Eintrag und Folien stellen das nette Projekt vor:
Seit einem Monat gibt es EventBus 1.3. Die Webseite spricht im Wesentlichen von zwei Neuigkeiten:
Mein Blog-Eintrag und Folien stellen das nette Projekt vor:
In meiner Seminarverwaltungssoftware können Trainer die Seminarbeschreibungen ändern. Natürlich möchte ich mitbekommen, welche Stellen geändert wurden und das am Liebsten hübsches aufbereitet. Da bin ich auf http://code.google.com/p/daisydiff/ gestoßen. Man kann entweder über die Kommandozeile arbeiten oder mit einer Hilfsklasse, wobei zwei Klassen einen ersten Anhaltspunkt für die API geben:
Ein kleines Beispiel soll das Diff in HTML-Form in den Temp-Ordner C:\Users\CHRIST~1\AppData\Local\Temp\ schreiben:
package com.tutego.traida;
import java.awt.Desktop;
import java.io.File;
import java.io.FileWriter;
import org.outerj.daisy.diff.Main;
public class DaisyDiffDemo
{
public static void main( String[] args ) throws Exception
{
String html1 = „Eine zwei Polizei“;
String html2 = „Eins zwei drei Polizei“;
File fileIn = File.createTempFile( „daisyin“, „.html“ );
File fileOut = File.createTempFile( „daisyout“, „.html“ );
File fileDiff = File.createTempFile( „daisydiff“, „.html“ );
new FileWriter( fileIn ).append( html1 ).close();
new FileWriter( fileOut ).append( html2 ).close();
String[] daisyDiffArgs = {
fileIn.getAbsolutePath(), fileOut.getAbsolutePath(), „–file=“+fileDiff.getAbsolutePath()
};
Main.main( daisyDiffArgs );
fileIn.deleteOnExit();
fileOut.deleteOnExit();
Desktop.getDesktop().open( fileDiff );
}
}
Das generierte HTML greift auf allerlei Zeugs zurück. Damit die HTML-Datei gut angezeigt wird, einfach aus dem Zip die Order css, images und js in das temp-Verzeichnis C:\Users\CHRIST~1\AppData\Local\Temp kopieren. Dann sieht das Ergebnis so aus:
Auf Jazoon09 (Präsentation: http://docs.google.com/Present?docid=dcc9m6z9_1524fzspccfp) wurde ein Projekt vorgestellt, wie 4 Millionen Zeilen COBOL erfolgreich nach Java konvertiert werden konnten. (infoQ http://www.infoq.com/news/2009/07/cobol-to-java hat die Links). Im Zentrum der Konvertierung steht der Konverter (83.000 Quellcodezeilen, fast 700 Klassen), das zusammen mit der Laufzeitbibliotheken (153k Zeilen, fast 900 Klassen) auf COBOL-Programme übersetzt und ausführt. Die COBOL-Masken werden in HTML übersetzt.
Die GPL-Projekte sind unter http://code.google.com/p/naca/ zu finden (aber nicht im Source als SVN).
Eher unbekannte Projekte sind:
So viel IDE gab es noch nie. In einer Woche drei wichtige Neuerungen.
Von der Webseite:
JaQue provides an infrastructure for Microsoft LINQ like capabilities on Java platform. Using ASM, JaQue builds expression trees, which are used to build a query in domain specific technology or language, such as SQL. This way Java developers can focus on writing application logic in the language they know – Java, regardless what the underlying technology or language is in use. JaQue to Objects and JaQue to XML are currently supported and JaQue to JPA is under development.
Ein Beispiel macht das praktisch deutlich:
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hibernate");
EntityManager em = emf.createEntityManager();
JaqueEntityManager jem = new JaqueEntityManager(em);
Queryable<Order> orders = jem.from(Order.class);
System.out.println(count(where(new Predicate<Order>() {
public Boolean invoke(Order t) throws Throwable {
return t.getOrderID() > 11000;
}
}, orders)));
Wie bei LINQ soll eine eine API für die verschiedenen Datenquellen geben, also XML, Objekte, Datenbanken, … Für JPA schreibt die Seite “Currently it’s able to perform only simple SELECTs, JOINs and AGGREGATEs”. Das ist natürlich nicht viel. Insofern ist diese Lösung WEIT von den LINQ to SQL-Möglichkeiten entfernt.
Der Hinweis der Webseite auf “Interoperability with Java Closures” ist natürlich hinfällig. Dadurch, dass Closures aber wegfallen, wird die ganze API viel aufgeblähter, als wenn man Closures hätte. Die Scala-Variante ist daher auch viel kürzer.
PS: Die nächsten 2 Wochen gibt es keine Blog-Einträge, da ich ich Afrika bin.
Im Google Code Blog werden einige Videos vorgestellt, die den aktuellen Zustand von GWT widerspiegeln. Etwa
GWT Can Do What?!?! A Preview of Google Web Toolkit 2.0 (PDF):
Und weitere:
Google Web Toolkit Architecture: Best Practices for Architecting your GWT App
Measure in Milliseconds: Performance Tips for Google Web Toolkit
Effective GWT: Developing a Complex, High- performance App with Google Web Toolkit
The Story of your Compile: Reading the Tea Leaves of the GWT Compiler for an Optimized Future
Progressively Enhance AJAX Applications with Google Web Toolkit and GQuery
Nicht immer können und müssen Objektgraphen von XML-Dateien – entweder pur als XML-DOM, oder gemappt über etwa JAXB – im Speicher gehalten werden. Muss nur einmal eine XML-Datei abgelaufen werden (natürlich können in diesem einen Durchlauf dann der XML-DOM aufgebaut werden), kann gut ein Pull-Parser eingesetzt werden.
Aufgabe: Implementiere einen XHTML-Prüfer, der meldet, ob im img-Tag das Attribut alt gesetzt ist.
GroupingStore<BaseModel> store = new GroupingStore<BaseModel>();
BaseModel c1 = new BaseModel();
c1.set( „title“, „Java 1“ );
c1.set( „category“, „JAVA“ );
c1.set( „price“, 100 );
store.add( c1 );
BaseModel c2 = new BaseModel();
c2.set( „title“, „Java 2“ );
c2.set( „category“, „JAVA“ );
c2.set( „price“, 200 );
store.add( c2 );
BaseModel c3 = new BaseModel();
c3.set( „title“, „C#“ );
c3.set( „category“, „.NET“ );
c3.set( „price“, 100 );
store.add( c3 );
List<ColumnConfig> config = new ArrayList<ColumnConfig>();
config.add( new ColumnConfig( „category“, „Kategorie“, 200 ) );
config.add( new ColumnConfig( „title“, „Titel“, 100 ) );
config.add( new ColumnConfig( „price“, „Preis“, 100 ) );
store.groupBy( „category“ );
final ColumnModel cm = new ColumnModel( config );
GroupingView view = new GroupingView();
view.setShowGroupedColumn( false );
view.setForceFit( true );
view.setGroupRenderer( new GridGroupRenderer()
{
public String render( GroupColumnData data )
{
String header = cm.getColumnById( data.field ).getHeader();
String items = data.models.size() == 1 ? „Eintrag“ : „Einträge“;
return header + “ “ + data.group + “ (“ + data.models.size() + “ “ + items + „)“;
}
} );
EditorGrid<BaseModel> grid = new EditorGrid<BaseModel>( store, cm );
grid.setView( view );
grid.setBorders( true );
grid.setAutoHeight( true );
ContentPanel cp = new ContentPanel();
cp.add( grid );
cp.setHeight( 500 );
RootPanel.get().add( cp );
Nach dem ich nun eine Woche eine Anwendung mit Ext GWT (GXT) zusammengebaut habe, kommen mir Zweifel, ob Ext GWT überhaupt das richtige für meinen Anwendungsfall ist. Einige Fragen in dem Zusammenhang:
Ist Ext GWT 2.0 M2 gut gewählt?
Ext GWT 2 gibt es noch gar nicht lange (http://extjs.com/blog/2009/05/20/ext-gwt-20-milestone-2-released/), neues M2 Release also vor 2 Wochen, und die Komponenten sind grundsätzlich toll. Auf der Demo Seite http://extjs.com/examples-dev/explorer.html#overview kann man sich das anschauen.
Probleme: Ext GWT 2.0 hat in meinen Augen sehr vielen Änderungen in der API. Quellcode für Ext GWT 1.0 findet man im Netz, doch viele Beispiele lassen sich nicht ohne weiteres auf die 2er Version übertragen. Wer migrieren will/muss wird noch seinen Spaß bekommen. Einige Beispiele laufen in der Demo nicht (http://extjs.com/examples-dev/explorer.html#grouping), bei anderen fehlt der Quellcode im Demo. Da muss man dann die Quellen laden.
Laut Ankündigung müsste GXT schon längst fertig sein.
Was passt mir an Ext GWT nicht?
War Ext GWT eine gute Wahl, oder hätte es doch SmartGWT sein sollen?
Das weiß ich nicht, denn mit SmartGWT habe ich nur einfache Beispiele programmiert. Ext GWT hat aber den gleichen RIA-Ansatz wie SmartGWT, und unterscheidet sich nicht großartig im Ansatz. Die GXT-Komponenten sehen auf jeden Fall super aus. Daher hat mich GXT ja auch so angezogen. Wer hübscher ist gewinnt 🙂 Die Komponenten sind fancy und meine Lieblinge sind http://extjs.com/examples-dev/explorer.html#advancedcharts (cool), http://extjs.com/examples-dev/explorer.html#gridplugins, http://extjs.com/examples-dev/explorer.html#grouping, http://extjs.com/examples-dev/explorer.html#filtertree, http://extjs.com/examples-dev/explorer.html#gridtogrid.
Ist ein RIA-Framework wie GXT immer gut?
Das ist eigentlich die zentrale Frage.
Ich habe ja schon nicht mehr damit gerechnet: SwingX hat es in den 1.0 Status geschafft. Die Fixes/Enhancements sind aber eigentlich minimal und die Freigabe hätte schon früher kommen können …
Und wenn man liest, “From now on, the Java 5 compatibility will no longer be maintained.” heißt das nur, dass die kommenden Versionen mindestens Java 6 erwarten; SwingX 1.0 ist selbstverständlich unter Java 5 lauffähig.
Im Mittelpunkt steht com.extjs.gxt.ui.client.widget.tree.Tree, dem entweder com.extjs.gxt.ui.client.widget.tree.TreeItem-Objekte zugeordnet werden, oder ein komplexeres Modell zugewiesen wird. Mit TreeItem ist schnell ein statischer Baum aufgebaut:
Tree tree = new Tree();
TreeItem rootTreeItem = new TreeItem( „Hauptobjekte“ );
tree.getRootItem().add( rootTreeItem );
rootTreeItem.add( new TreeItem( „Kunden“ ) );
rootTreeItem.add( new TreeItem( „Seminare“ ) );
rootTreeItem.add( new TreeItem( „Referenten“ ) );
rootTreeItem.setExpanded( true );
tree.addListener( Events.OnClick, new Listener<TreeEvent>()
{
@Override public void handleEvent( TreeEvent be )
{
if ( be.getItem().isLeaf() )
Info.display( „Element: „, be.getItem().getText() );
}
} );
contentPanel.add( tree );
Wie bei Swing gibt es ein Root-Icon und darunter liegen die Kinder.
Mit einem Listener lässt sich erfragen, ob der Baum ausgefaltet wird oder ob Blätter ausgewählt wurden. Das Beispiel hört nur auf die Auswahl der Kinder und gibt eine Meldung aus.
Quaqua ist ein Swing-LaF, was besonders gut an die Apple Human Interface Guidelines ranreicht.
Das Demo läuft auch unter Windows.
Features (von der Webseite):
Neben dem LaF für Standardkomponenten gibt es mit JBrowser und JSheet noch zwei “Spezialkomponenten”.
Die Lizenz ist License (LGPL or BSD), und die Doku mit vielen Screenshots. Tolle Arbeit!
In Google Wave steckt eine Zeile, die einen Einsatz
vom GWT nahe legt:
<link rel="stylesheet" href="/squared/styles/squared.css">
<script language="javascript" src="/squared/js/templates.js"></script>
<script language="javascript" src="/squared/api/com.google.quality.views.squared.client.Squared.nocache.js"></script>
Verfolgt man den Link ist das typische obfuscated JavaScript zu sehen. Wer viiiiel Zeit hat, kann das ja mal debuggen und hier berichten. Ein kleiner Test mit FireBug zeigt, dass Squared sich über Service per RPC die Objekte geben lässt
["com.google.quality.views.squared.shared.model.Workspace/4054808271","US presidents",
"com.google.quality.views.squared.shared.model.Suggestions/3280816700",
"java.util.ArrayList/3821976829",
"com.google.quality.views.squared.shared.model.Entry/3459296909" ...
Für unseren Seminarbetrieb erstellen wir nach dem Seminarabschluss aus einer XML-Datei die Rechnung und Zertifikate für den Kunden. Die Vorlagen sind in OpenOffice verfasst und können ohne Probleme verändert werden. Ein großer Vorteil ist weiterhin, dass OO einen PDF Exporter mitbringt.
Der Nachteil der Lösung, OpenOffice für die PDF-Erzeugung fernzusteuern ist, dass es sehr schwergewichtig. OO muss installiert und gestartet werden. Das ist auf einem Server, etwa einem einfachen Servlet-Container oder sogar der Google App Engine for Java natürlich nicht denkbar.
Ein anderer Weg ist daher, zwar weiterhin OpenOffice für die Erstellung einer Vorlage zu verwenden, aber beim PDF-Export anders vorzugehen. Die Lösungen können Acrobat Forms (Acroforms) bieten, also eigentlich interaktive Felder, die man später über ein Programm füllen kann. Im ersten Schritt erzeugt man daher mit OpenOffice Draw eine Formular. (Das wird etwa beschrieben unter http://www.devx.com/opensource/Article/38178/.) Dann exportiert man das Dokument in PDF unter Erhaltung der Formulareigenschaften. Dieses PDF lässt sich nun mit iText auslesen, die Formularzellen füllen und wieder als PDF schreiben. Dabei kann die “Formulareigenschaft” wegfallen, dass man später bei dem PDF-Dokument nichts mehr von interaktiven Elementen sieht.
import java.io.FileOutputStream;
import com.lowagie.text.pdf.*;
public class FillInPdfForm
{
public static void main(String[] args) throws Exception
{
PdfReader reader = new PdfReader(„c:/rein.pdf“);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(„c:/raus.pdf“));
BaseFont font = BaseFont.createFont(„c:\\windows\\fonts\\Calibri.ttf“, BaseFont.CP1252, BaseFont.NOT_EMBEDDED);
AcroFields form = stamper.getAcroFields();
for( Object o : reader.getAcroForm().getFields() )
form.setFieldProperty( ((PRAcroForm.FieldInformation) o).getName(), „textfont“, font, null);
form.setField(„name“, „Christian Ullenboom“);
form.setField(„content“, „Brav sein\nLieb sein“);
stamper.setFormFlattening(true);
stamper.close();
}
}
Etwas lästig ist, dass beim Ausfüllen der in OO zugewiesen Font flöten geht. Daher muss man diesen neu zuweisen. Sonst ist es Arial/Helvetica.
Wirklich interessant ist ist die Tatsache, dass die Clientseite von Google Wave in GWT implementiert ist. Das ist in meinen Augen ein unschlagbares Argument für die Ausgereiftheit von GWT, wenn Google das in einem Projekt einsetzt, was von unglaublichen vielen Menschen verwendert werden wird und definitiv performant laufen muss. Dabei sollte laut einem Blog-Eintrag http://mtwong.ning.com/profiles/blogs/google-io-conference-google-1 Wave auch überhaupt nicht in GWT entwickelt werden, da der Projektleiter Zweifel hatte, GWT würde gescheit laufen. Aber Wave hat wohl auch die Entwicklung von GWT positiv beeinflusst, etwa bei den Tools. Der Blog-Eintrag erwähnt interessante weitere Projekte und GWT-Features:
Änderungen listet http://java.sun.com/javase/6/webnotes/6u14.html auf. Interessant sind meines Erachtens: Compressed Object Pointers und Garbage First (G1) Garbage Collector, weil diese Dinge sind, die für Java 7 vorgesehen waren. Aber nun kann man die schon mal “in the wild” testen, was eine gute Sache ist. Dann noch JAX WS 2.1.6 and JAXB 2.1.10 und ein Update von JavaDB (wobei Derby schon deutlich weiter ist, komisch).
Strings in switch,
Joe Darcy
Improved Exception Handling for Java,
Neal Gafter
Automatic Resource Management,
Josh Bloch
Improved Type Inference for Generic Instance Creation,
Jeremy Manson
Elvis and Other Null-Safe Operators, Neal Gafter, Stephen Colebourne
In der näheren Auswahl sind desweiteren noch:
Integer-Literale:
Byte and Short Integer Literal Suffixes,
Bruce Chapman
Binary Literals,
Derek Foster
Underscores in numbers,
Derek Foster
Language support for JSR 292
(wiki),
John Rose
Indexing access syntax for Lists and Maps,
Shams Mahmood Imam
Collection Literals,
Joshua Bloch
Large arrays (revised),
James Lowden
Alle andere Vorschläge, die bisher in der Mailingliste http://mail.openjdk.java.net/pipermail/coin-dev/ vorstellt wurden, sind damit raus. (Eine Begründung für die Ablehnung gibt es nicht zwangsläufig.)