SmartGWT 1.2

Aus dem Blog http://www.jroller.com/sjivan/entry/smartgwt_1_2_released:

SmartGWT 1.2 has been released. I have added several new samples to the Showcase including a real world mini-application. The other new samples can be found under the „New Samples“ side nav item.

This is a feature-complete production ready release. There are only around 20 enhancement requests and 20 low / medium priority issues in the SmartGWT tracker which I think is pretty telling for such a comprehensive library. I hope to get to them over the weeks to come.

Here are some of the key features of this release :

  • GWT 1.7 is fully supported and integration with GWT widgets has been improved significantly. Along with standard GWT widgets, you can now easily add Google Maps or even a Google Visualization Chart to your SmartGWT application
  • Hosted mode performance improvements
  • Fully implemented the highly requested ResultSet API.
  • ListGrid performance improvements
  • Full Support for Safari 4.x
  • Support for Grid editing with all cell editors active
  • Auto-loading of dependent XML schema for loadWSDL() and loadXMLSchema()
  • Extended WebService APIs to allow simplified input data and allow setting SOAP headers
  • Numerous enhancements. See the detailed API Changes document. Around 35 additional enhancements and bug fixes that were logged in tracker
  • Official Maven Repository
  • Enhancements to RPC Tab in Developer Console (shows component that initiated request, if applicable)

Looking ahead there are several exciting new features that are going to be in the next release. Deep level of customization of pretty much any widget is going to be supported. For example you’ll be able to fully customize grid headers, provide your own widget implementation to use as a Tile in a TileGrid, or even customize pretty much any aspect of the Calendar component.

NetBeans 6.8 Milestone 1

Gibt es nun auch zum Downloaden unter http://bits.netbeans.org/netbeans/6.8/m1/. Und die News gibt es hier unter http://wiki.netbeans.org/NewAndNoteworthyNB68. Interessant ist:

  • Milestone1 enables basic support for development of applications for Java Enterpise Edition v6.
  • support for JPA 2.0
  • Initial PHP 5.3 support
  • Upgraded bundled JRuby to 1.3.1
  • Support for creating Rails 2.3.2 apps with dispatchers
  • Neue Profiling tools für C++
  • Issue tracking integration now supports JIRA

iPhone-Applikationen mit Java entwickeln (XMLVM)

Ein großartiges Projekt ist http://www.xmlvm.org/. Es steht zwar erst am Anfang, aber der sieht sehr vielversprechend aus. Die Idee von XMLVM ist einfach: Man nehme den Bytecode, repräsentierte diesen als XML, transformiere den über XSLT in Objective C und kompilieren dann.

XMLVM Overview Diagram

(Bilder von der Webseite)

 

XMLVM Frontend

Die Stack-Operationen vom Java-Bytecode werden über XSLT einfach in Objective C abgebildet, wobei die Stack-Operationen beibehalten werden. Die Mühe über einen internen AST oder so macht man sich nicht.

<xsl:template match=“jvm:irem“>
  <xsl:text>
    _op2.i = _stack[–_sp].i; // Pop operand 1
    _op1.i = _stack[–_sp].i; // Pop operand 2
    _stack[_sp++].i = _op1.i % _op2.i; // Push remainder
  </xsl:text>
</xsl:template>

Das gibt zwar für den GCC ‘ne Menge zu optimieren, aber das ist der einfachste Weg der Transformation. Später sieht das dann so aus:

@interface org_xmlvm_test_HelloWorld : java_lang_Object
+ (void) main___java_lang_String_ARRAYTYPE :(NSMutableArray*)n1;
@end
@implementation org_xmlvm_test_HelloWorld;
+ (void) main___java_lang_String_ARRAYTYPE :(NSMutableArray*)n1
{
    XMLVMElem _stack[2];
    XMLVMElem _locals[1];
    int _sp = 0;
    XMLVMElem _op1, _op2, _op3;
    int _i;
    for (_i = 0; _i <1; _i++) _locals[_i].o = nil;
    NSAutoreleasePool* _pool = [[NSAutoreleasePool alloc] init];
    _locals[0].o = n1;
    _op1.o = [java_lang_System _GET_STATIC_java_lang_System_out];
    _stack[_sp++].o = _op1.o;
    _stack[_sp++].o = @“Hello World“;
    _sp -= 2;
    [((java_io_PrintStream*) _stack[_sp].o) println___java_lang_String:_stack[_sp + 1].o];
    [_pool release];
    return;
}
@end

 

Weitere Beispiele gibt http://xmlvm.org/showcase/ und der Blog http://www.cokeandcode.com/aboidblog.

Insgesamt ein sehr spannendes Projekt, welches auch die Frage Android –> iPhone Entwicklung angeht, und .NET -> Java Cross-Compilation bietet. Mal sehen, wie sich das Entwickeln wird. MONO für iPhone ist auch bald bereit und dann wird iPhone Entwicklung wirklich einfach. (Bekommen wir dann noch mehr Schrott im Store?)

Über die Sicherheitsarchitektur von Google Android

Vom 25.-30. Juli lief in in den USA die Sicherheitsmesse Black Hat. Dort hat Jesse Burns in einem Vortrag die Sicherheitsarchitektur von Android vorgestellt. Sein Paper dazu kann man hier (alternativ unter http://www.isecpartners.com/files/iSEC_Securing_Android_Apps.pdf) runterladen.

Weiterhin lesenswert ist

Frage: Kann man alle Instanzen einer Klasse ermitteln?

Das geht nicht wirklich und wenn, dann nur mit großen Umwegen etwa über die Java Debugging API, mit der man sich an die JVM hängen kann. Auch ein Blick auf den Quellcode von jconsole und jmap/jhat helfen hier, weil die Tools genau das machen und Zahlen geben.

Der Objektgraf verändert sich ständig und so könnte man auch die Objekte stark referenzieren und den GC am Löschen hindern. Das würde zu einer großen Anzahl von Problemen führen. (Schwache Referenzen könnte das Problem abmildern, aber der GC muss hier Zusatzarbeit machen und die Laufzeit würde sich (messbar) verschlechtern.) Die Objekte sind ja immer eine Momentaufnahme. Da kämen ja Millionen von Objekten raus, wenn man etwa nach „Gib mir alle Strings“ fragt. Laufend ändert sich diese Menge.

Wenn der Nutzer diese Instanzen wirklich braucht, kann er sie an einer Objekt-Registry anmelden.

  • Von Hand kann man Exemplare etwa in eine Map<Class,List<?>> setzen. Das muss man nicht unbedingt manuell machen, sondern man kann hier einen Aspekt schreiben, der Bytecode in den Konstruktor für solch ein Anmelden einfügt. Dann ist das Abmelden aber noch so eine Sache. Das kann aber eine PhantomReference übernehmen und so meldet man das Objekt an der Registry wieder ab.
  • Wenn man Spring benutzt, deklariert ListableBeanFactory (implementiert etwa von XmlBeanFactory) eine Methode Map getBeansOfType(Class type) für genau diesen Fall.
  • Sind die Exemplare alle MBeans, ist es einfach, dann sind sie schon an einem Container registriert, und Query liefert sie sogar nach gewissen Kriterien.

Thema der Woche: Repository-Pattern in DDD und DAO

Zur Abstraktion von Zugriffen auf konkreten Datastores (oft eine relationale Datenbank) haben sich DAOs (http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html) etabliert. Im Domain Driven Design (DDD) gibt es etwas, das so aussieht wie ein DAO, und zu großer Diskussion in der Community führt.

Lassen sich hier schon Unterschiede herausstellen?

Verfolge den “Streit” über den Unterschied zwischen Repos/DAO in den Blogs

Fragen:

  • Was sagt Eric Evans zu der Diskussion? Kann ein Repo als DAO implementiert sein?
  • Stehen Repo und DAO beide auf der Ebene vom Domain-Model?
  • Warum sagen Kritiker, dass Repos eine zusätzliche (unnötige) Zwischenschicht sind?
  • Einige EJB-Advocates injizieren gerne bei Java EE 5 Anwendungen den Entity-Manager in den DAO bzw. sehen den EM als DAO selbst, den man dann in Session-Beans injiziert. Ist das ein Design im Sinne von DDD?

Optional. Wie sieht Paginierung aus? http://tech.groups.yahoo.com/group/domaindrivendesign/message/5795

Java Datastore API für die Google App Engine

Um in der Google Cloud Daten zu speichern bietet Google drei API an: JPA, JDO und eine Low-Level-API. Infos dazu gibt liefert http://code.google.com/intl/de/appengine/docs/java/datastore/. JPA und JDO basieren im Kern auf der Low-Level API, die auf die http://en.wikipedia.org/wiki/BigTable zurückgreift.

Für JPA und JDO gibt es selbst von Google viele Beispiele, aber die Low-Level-API ist nicht so gut dokumentiert und selbst das Beispielprogramm in der JavaDoc enthält Fehler. Zeit daher, ein sehr einfaches Beispiel mit einer 1:n Relationen anzugehen.

Im Mittelpunkt der API steht der DatastoreService, der ein bisschen an den EntityManager von JPA erinnert. Er bietet Methoden für die CRUD-Operationen. Mein Beispiel geht schon ein bisschen “pseudo-ORM” an die Aufgabe ran, einer Person Nachrichten zuordnen zu können:

Die Personen-Klasse:

package com.tutego.server.entity;

import java.util.ArrayList;
import java.util.List;

import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Query;

public class Person
{
  private final static String ENTITY_NAME = „Person“;
  Entity personEntity;

  public enum Gender
  {
    MALE, FEMALE
  }

  public Person()
  {
    personEntity = new Entity( ENTITY_NAME );
  }

  private Person( Key key )
  {
    try
    {
      personEntity = DatastoreServiceFactory.getDatastoreService().get( key );
    }
    catch ( EntityNotFoundException e )
    {
    }
  }

  private Person( Entity entity )
  {
    personEntity = entity;
  }

  public static Person get( Key key )
  {
    return new Person( key );
  }

  public void setUsername( String username )
  {
    personEntity.setProperty( „username“, username );
  }

  public String getUsername()
  {
    return personEntity.getProperty( „username“ ).toString();
  }

  public void setGender( Gender gender )
  {
    personEntity.setProperty( „gender“, gender.toString() );
  }

  public Gender getGender()
  {
    return Gender.valueOf( personEntity.getProperty( „gender“ ).toString() );
  }

  public Key put()
  {
    return DatastoreServiceFactory.getDatastoreService().put( personEntity );
  }

  public static void deleteAll()
  {
    Query deleteAllQuery = new Query( ENTITY_NAME );

    for ( Entity entity : DatastoreServiceFactory.getDatastoreService().prepare( deleteAllQuery ).asIterable() )
      DatastoreServiceFactory.getDatastoreService().delete( entity.getKey() );
  }

  private static List<Person> executeQuery( Query query )
  {
    List<Person> result = new ArrayList<Person>();
    for ( Entity entity : DatastoreServiceFactory.getDatastoreService().prepare( query ).asIterable() )
      result.add( new Person( entity ) );
    return result; 
  }

  public static List<Person> findAllPersons()
  {
    Query query = new Query( ENTITY_NAME );

    return executeQuery( query );
  }

  public static List<Person> findPersonByGender( Gender gender )
  {
    Query query = new Query( ENTITY_NAME );
    query.addFilter( „gender“, Query.FilterOperator.EQUAL, gender.toString() );

    return executeQuery( query );
  }

  @Override
  public String toString()
  {
    return String.format( „Person[%s,%s]“, getUsername(), getGender() );
  }
}

Die Nachrichten-Klasse:

package com.tutego.server.entity;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import com.google.appengine.api.datastore.DatastoreServiceFactory;
import com.google.appengine.api.datastore.Entity;
import com.google.appengine.api.datastore.EntityNotFoundException;
import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.Query;

public class Message
{
  private final static String ENTITY_NAME = „Message“;

  private Entity messageEntity;

  public Message()
  {
    messageEntity = new Entity( ENTITY_NAME );
  }

  private Message( Key key )
  {
    try
    {
      messageEntity = DatastoreServiceFactory.getDatastoreService().get( key );
    }
    catch ( EntityNotFoundException e )
    {
    }
  }

  private Message( Entity entity )
  {
    messageEntity = entity;
  }

  public static Message get( Key key )
  {
    return new Message( key );
  }

  public void setText( String text )
  {
    messageEntity.setProperty( „text“, text );
  }

  public String getText()
  {
    return messageEntity.getProperty( „text“ ).toString();
  }

  public void setCreationTime( Date d )
  {
    messageEntity.setProperty( „creationtime“, „“ + d.getTime() );
  }

  public Date getCreationTime()
  {
    return new Date( Long.parseLong( messageEntity.getProperty( „creationtime“ ).toString() ) );
  }

  public void setReceiver( Person p )
  {
    messageEntity.setProperty( „person_fk“, p.personEntity.getKey() );
  }

  public Key put()
  {
    return DatastoreServiceFactory.getDatastoreService().put( messageEntity );
  }

  private static List<Message> executeQuery( Query query )
  {
    List<Message> result = new ArrayList<Message>();

    for ( Entity entity : DatastoreServiceFactory.getDatastoreService().prepare( query ).asIterable() )
      result.add( new Message( entity ) );
    return result; 
  }

  public static List<Message> findMessagesForPerson( Person p )
  {
    Query query = new Query( ENTITY_NAME );
    query.addFilter( „person_fk“, Query.FilterOperator.EQUAL, p.personEntity.getKey() );

    return executeQuery( query );
  }

  @Override
  public String toString()
  {
    return String.format( „Message[%s,%s]“, getCreationTime(), getText() );
  }
}

Getestet werden soll das ganze in einer einfachen Server-Funktion:

StringWriter sw = new StringWriter();
PrintWriter out = new PrintWriter( sw );

// Insert new entity

Person p1 = new Person();
p1.setUsername( „chris“ );
p1.setGender( Person.Gender.MALE );
Key key1 = p1.put();

out.println( „* Key für erste Person “ + p1 );
out.println( KeyFactory.keyToString( key1 ) );

Person p2 = new Person();
p2.setUsername( „pallas“ );
p2.setGender( Person.Gender.FEMALE );
p2.put();

Person p3 = new Person();
p3.setUsername( „tina“ );
p3.setGender( Person.Gender.FEMALE );
p3.put();

// Search for entity with a given key

Person p = Person.get( key1 );
out.println( „* Suche mit Schlüssel “ + key1 );
out.println( p.getUsername() );

// Query

List<Person> findAll = Person.findAllPersons();
out.println( „* Alle Personen“ );
out.println( findAll.toString() );

// Query

List<Person> females = Person.findPersonByGender( Gender.FEMALE );
out.println( „* Alle Frauen:“ );
out.println( females.toString() );

Message msg1 = new Message();
msg1.setText( „Hallo Maus“ );
msg1.setCreationTime( new Date(1) );
msg1.setReceiver( p );
msg1.put();

Message msg2 = new Message();
msg2.setText( „Hallo Ratte“ );
msg2.setCreationTime( new Date(2) );
msg2.setReceiver( p );
msg2.put();

out.println( „* Alle Nachrichten für “ + p );
out.println( Message.findMessagesForPerson( p ) );
out.println( „\n“ );

// Clean up

Person.deleteAll();

out.flush();

return sw.toString().replace( „\n“, „<br/>“ );

Als Ergebnis kommt HTML zurück, was der Client zum Testen anschauen kann.

Thema der Woche: Stripes, ein einfaches Web Presentation Framework

Die Listen http://java-source.net/open-source/web-frameworks und http://de.wikipedia.org/wiki/Liste_von_Webframeworks geben eine fast unendliche Aufzählung von Web-Frameworks an. Selbst bin ich ein Freund (je nach Anwendungsfall) von GWT, JSF 2.0 und Stripes.

Stripes is a presentation framework for building web applications using the latest Java technologies. The main driver behind Stripes is that web application development in Java is just too much work! It seems like every existing framework requires gobs of configuration. Struts is pretty feature-light and has some serious architectural issues (see Stripes vs. Struts for details). Others, like WebWork 2 and Spring-MVC are much better, but still require a lot of configuration, and seem to require you to learn a whole new language just to get started.

Stripes fällt die Kategorie der Action-orientierten Frameworks, wie Struts oder Spring MVC. Ein Front-Controller nimmt den Request entgegen und delegiert auf eine ActionBean-Klasse, die den Seitenfluss auf eine andere Zielseite steuert.

Aufgaben:

Trivia: Frederic Daoud ist der Autor vom Standard-Stripes Buch “Stripes: …and Java Web Development Is Fun Again”. Frederic und seine Frau Nadia haben ein zweites Kind bekommen und es Ruby genannt.

OpenJDK7 / JDK7 M4 Release

Die Ankündigung wurde unter http://blogs.sun.com/xiomara/entry/openjdk7_jdk7_release_milestone_4 gemacht. Interessant ist „For now JDK 7 is finally in sync with the JDK 6u14 updates.“ Dann wird es Zeit, dass jetzt mal die *wirklichen* Dinge implementiert werden und man nicht nur die Änderungen von Java 6 alle in Java 7 nachzieht. Bis auf NIO.2 ist hier noch nicht wirklich viel passiert. Und beim Project Coin wird viel diskutiert, aber bisher ohne Ergebnis im Java-Compiler.

GWT und sein HTML/DOM, alternativer GWT FlowPanel

Zum Layout von GWT-Komponenten ist es unerlässlich zu verstehen, was GWT für ein DOM erzeugt. Zum einen sind da Werkzeuge wie FireBug unerlässlich und zum Anderen kann man sich vorher schon bei http://javabyexample.wisdomplug.com/component/content/article/75.html informieren, was GWT für eine Struktur erzeugen wird.

Schnell entstehen bei GWT-Anwendungen eine Unzahl geschachtelter Tabellen. Sie sind für die Performance der Darstellung nicht unerheblich, denn wenn man das Fenster zum Beispiel in der Größe ändert, so müssen die ganzen Größeninformationen neu berechnet werden.

Um das HTML schlank zu halten, lässt sich auf alternative Container zurückgreifen. Wer zum Beispiel horizontal oder vertikal anordnen will, greift sofort zum HorizontalPanel bzw. VerticalPanel. Doch zur Umsetzung setzt eben GWT eine Tabelle ein. Wenn man nur zum Beispiel eine Zeile wie “blal@googlemail.com  | My favorites | Profile  | Sign out” aufbauen möchte, ist das HorizontalPanel unnötig und schwergewichtig. Es bietet sich an, eine neue Panel-Klasse zu nutzen, etwa wie sie etwa http://blog.sudhirj.com/2009/05/vertical-and-horizontal-flow-panels-in.html vorstellt. Etwas komprimiert:

import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Widget;

public class HorizontalFlowPanel extends FlowPanel
{
  @Override
  public void add( Widget w )
  {
    w.getElement().getStyle().setProperty( „display“, „inline“ );
    super.add( w );
  }
}

Diese Implementierung führt nur zu einem <div>-Block statt einer <table>.

EventBus Version 1.3

Seit einem Monat gibt es EventBus 1.3. Die Webseite spricht im Wesentlichen von zwei Neuigkeiten:

  • The ability to control the order in which subscribers are called with the Priority interface and priority annotation parameters.
  • Support for annotated inner classes and other non-public members.
  • Mein Blog-Eintrag und Folien stellen das nette Projekt vor:

    Vergleich von HTML-Dateien mit Daisy Diff

    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:

    sshot-1

    Mit GPL-Tools von COBOL nach Java migrieren

    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).

    Welches Projekt wird von Maven wie oft referenziert?

    Das sagt http://www.mvnbrowser.com/most-referenced.html. Die Liste ist interessant zu lesen. Vielleicht nicht ganz unerwartet ist ganz oben JUnit und log4j — das wird von nahezu allen Programmen referenziert. Interessant in der Liste finde ich,

    • das HSQLDB doch noch so oft (für Tests) gebraucht wird, aber Derby noch auf die erste Seite kommt,
    • Spring (schon) so weit oben seht,
    • CXF vor Axis und dem alten XFire steht,
    • JAXB so groß im Einsatz ist,
    • Plexus von CodeHaus in der Liste auf der ersten Seite steht (unter anderem von Maven2 genutztes IoC-Framwork und daher wohl so weit vorne),
    • dom4j populärer als JDOM ist,
    • Struts ist (ein wenig) wichtiger als WebWork aber weit abgeschlagen von JSF.

    Eher unbekannte Projekte sind:

    • http://classworlds.codehaus.org/
    • http://qdox.codehaus.org/
    • http://www.janino.net/

    IDE-Woche: Eclipse 3.5, NetBeans 6.7, IntelliJ 9 M1

    So viel IDE gab es noch nie. In einer Woche drei wichtige Neuerungen.

    JaQue Version 1.5: MS LINQ Expression Trees für Java

    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.

    GWT-bezogene Videos von der Google I/O Konferenz 2009

    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 Wave – Powered by GWT

    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

    Building Applications with Google APIs

    Mit AjaxSwing Swing Anwendungen als Web-Anwendungen laufen lassen

    Das macht die Swing – AJAX bridge. Das SwingSet2 Demo ist schon mal ein guter Start. Die Entwickler sagen, dass das Demo ohne Quellcodemodifikationen läuft. Lauf FAQ laufen 95% der Anwendungen vernünfitg nach 30 Minuten Konfiguration. Die Vorraussetzungen für den Web-Server, das das hostet ist minimal: es läuft schon ab Java 1.2. Auch für den Client sind die Anforderungen wirklich gering: Internet Explorer 4+, FireFox 1.2+ bzw. jeder HTML 4.0 Browser. (Vielleich sieht daher das LaF von AjaxSwing standardmäßig so schrottig aus. Lässt sich aber alles anpassen.) Probleme kann es im Einzelfall etwa beim Eventing geben, wenn der Browser nicht alle Events weitergibt. Auch bei Multithreaded-Anwendungen kann es Probleme geben, wenn im AWT-Event-Thread neue Threads aufgemacht werden und die die Gui modifizieren (auch mit SwingUtilities.invokeLater/Now). Da AjaxSwing auch schon bei JComponent mit der Abbildung beginnt, laufen auch Bibliotheken wie SwingX. Mit einen SnapshotRenderer für „harte“ Fälle lässt sich auch serverseitig rendern und dann als JPG in die Seite einfügen.