Warum eine schlechte Webseite mich (fast) 160 € kostete und mich Air Namibia beinahe als Kunden verlor

Buchungsseiten im Internet sind kein neues Phänomen um so erstaunlicher ist es, dass es bei den Typ von Webseiten noch etwas zu optimieren gib. Als ich letztes Jahr eine weitere Reise nach Namibia plante, wählte ich Air Namibia aus, mit denen ich bisher noch nicht geflogen bin. Air Namibia fliegt von Frankfurt nach Windhoek, aber auch zu anderen Zielen. Um nach Frankfurt zu kommen kann man den Zug nehmen, denn Air Namibia bietet ein Rail & Fly Ticket an, tolle Sache!

What is Rail   Fly    Air Namibia-125410

Die HTML-Warning ist zwar peinlich, und auch, dass der Text englisch ist, obwohl “Deutsch” als Sprache voreingestellt ist, aber das ist nicht mein Problem.

Alle Flüge gehen in Deutschland von Frankfurt aus, daher ist in der Flugsuche bei “From” der Flughafen Frankfurt nur logisch:

FromAuswahl

Von dort geht es weiter, man gibt den Zielflughafen an, macht die Buchung, fertig. Einfache Sache.

Aber was ist mit dem Zugticket? Bei der Buchung wunderte mich schon, warum ich nicht auswählen konnte, dass ich Rail & Fly mit dazu buchen möchte. Wenn man bei Fluglinien wie Emirates einen Flug bucht, dann bietet diese eine schön Checkbox. Da mir das bei Air Nambia fehlt, schickte ich gleich nach der Buchung eine EMail mit der Frage ab, ob mein Ticket nun automatischer Bestandteil wäre, und wenn, wo meine IDs sind. Falls ich etwas falsch gemacht hätte, bat ich, mir das Ticket dazuzubuchen, da es für mich sehr wichtig wäre. Mehrfach frage ich nach, es ging hin und her, keine klare Antwort, immerhin eine EMail von Sylvia S.:

Dear Mr Ullenboom

As your request, rail ticket has been booked accordingly you have to pay at our office in advised.

Kind regards

“rail ticket has been booked accordingly“ Ok, gut. “Pay”? Hm, was soll das? Und “in advised”? Naja, und wo waren die Ticket-Nummern?  Ich rief in Deutschland an und man gab mir die beiden IDs für den Ticket-Automaten. Das war also mein Rail & Fly. Dachte ich.

Einen Tag vor Abflug ging ich zum Bahnhof, wollte mir dir Ticket ausdrucken, doch der Automat nahm die ID nicht an. Also rief ich wieder Air Namibia an, schilderte meiner Gesprächsperson die Situation, sie gab mir noch einmal die IDs durch. Die IDs waren die gleichen; es funktionierte nicht. Ich fragte am Telefon, was ich machen muss, aber sie sagte nur, die Daten kämen von der Bahn und sie könne mir nicht weiter helfen. Ich hatte also IDs bekommen, die warten jedoch ungültig.

Es kam, wie es kommen musste: ich musste zwei Zugtickets für insgesamt über 160 € selbst kaufen. Ich flog nach Namibia, nach ein paar Wochen wieder zurück und schickte eine EMails mit den Scan der Rechnungen, Bildschirmfotos vom Automaten mit der Zurückweisung. Ich bat um die Begleitung meiner Unkosten. Eine simple EMail reicht Air Namibia nicht, ich musste das ganze in einen Brief verpacken.

Ein paar Tage später kommt die Antwort, ich hätte Rail & Fly nicht mitgebucht. (Das hätte man auch direkt in der EMail sagen können…) Aber ich hatte doch die IDs bekommen?! Ich rief an und es stellte sich heraus, das ich tatsächlich nicht das Zugticket gekauft habe — mein Fehler. Und es stimmt, denn eine Checkbox zum Dazubuchen gibt es Air Nambia nicht. Stattdessen – und vielleicht ist es einigen Lesern schon aufgefallen – ist eben nicht der Flughafen auszuwählen, sondern ein “magischer” “Ort bei “From:”.

FromAuswahl2

Auf diese Idee bin ich nie gekommen! Also kostete mich dieser Fehler 160 €. Ist Air Nambia an dieser miesen Webseite Schuld? Im Prinzip nicht, denn das habe ich mir selbst zuzuschreiben, dass ich gewisse Annahmen über grafische Oberflächen und Buchungen als Standard voraussetzte.

Kann Air Nambia ihr Produkt verbessern? Aber klar! An vier Dingen könnte Air Nambia in meinen Augen arbeiten:

  • Auf der “Hilfe”-Seite sollte klar vermerkt werden, dass man diesen “magischen” ersten Punkt für das inkludierte Zugticket auswählen muss. Die Hilfe kannte ich, und hätte ich den Hinweis dort gelesen, wäre mir der Fehler nicht unterlaufen.
  • Diesen “magischen” Punkt absetzen und durch eine Checkbox im Buchungsverlauf ersetzen. Das würde es Kunden auch ermöglichen von London abzufliegen und nach Frankfurt zurückzukommen und dann ein Zugticket zu haben. Aber vielleicht ist diese Gabelung sowieso nicht vorgesehen …
  • Mir auch nach mehrfacher Nachfrage immer wieder die falschen IDs zu geben, anstatt klar zu formulieren, ich hätte Rail & Fly nicht gebucht. Auch: Die EMail-Kommunikation verbessern und mich nicht im Glauben lassen “rail ticket has been booked accordingly“.
  • Kunden die Option anzubieten, Rail & Fly einfach später dazuzubuchen. Das geht aber nur indirekt, in dem man den “Flug” umbucht. Die Umbuchungsbebühr betragen 165 € — die könnte Air Nambia reduzieren, da man bei dieser “Umbuchung” überhaupt nichts am Flug ändern muss. Später beim Telefonat kam es zu der Aussage, das ich mit dem eigenen Zugtickets ja noch günstiger gekommen bin. Ja super.

Schlussendlich hat Air Namibia nach meinen Telefonat noch einmal reagiert:

Wir haben Ihren Fall noch einmal intern geprüft und müssen leider mitteilen, dass sich aufgrund der Online-Buchung, die über das Air Namibia IT-Buchungssystem in Windhoek verarbeitet wurde, eine exakte Konstruktion des Buchungsvorgangs nicht mehr möglich ist. Da ein Fehler von Seiten der Air Namibia trotzdem nicht ausgeschlossen werden kann, wird Ihnen Air Namibia aus Kulanz die zusätzlich gekauften Bahntickets erstatten, denn laut Buchung ist R&F mit den zugehörigen Nummern, die Ihnen telefonisch mitgeteilt wurden, zwar hinterlegt, wurde aber eben nicht bestätigt und ausgestellt.

Dafür musste ich “nur” eine Einverständniserklärung abgeben:

Ich, C. U., erkläre mit meiner Unterschrift keine weiteren Regressansprüche gegenüber der Airline Air Namibia, deren Vertragspartnern und Handlingsagenten sowie weiteren Fluggesellschaften geltend zu machen. Mit dem Beitrag […] verzichte ich auf jegliche Schadensersatzansprüche gleich welcher Art.

Nach dem das ein paar Tage nach Valentinstag zu Air Namibia ging, erstattete mir die Airline über die AVIAREPS AG das Geld am 24.02 zurück. Schön. Ende gut.

Apache Ant 1.8.3 freigegeben

Änderungen unter http://svn.apache.org/repos/asf/ant/core/trunk/WHATSNEW aufgeführt:

Changes from Ant 1.8.3 TO Ant 1.9.0
===================================

Changes that could break older environments:
-------------------------------------------

Fixed bugs:
-----------

 * External XML catalog resolver failed to use project basedir when given an
   unmentioned relative path like the internal resolver does.
   Bugzilla Report 52754.

 * Fixed some potential stream leaks.
   Bugzilla Reports 52738, 52740, 52742, 52743.

Other changes:
--------------

Changes from Ant 1.8.2 TO Ant 1.8.3
===================================

Changes that could break older environments:
-------------------------------------------

 * The Enumeration returned by AntClassLoader#getResources used to
   return null in nextElement after hasNextElement would return false.
   It has been changed to throw a NoSuchElementException instead so
   that it now adheres to the contract of java.util.Enumeration.
   Bugzilla Report 51579.

Fixed bugs:
-----------

 * Removed buggy duplicate JAR list in RPM mode.
   Bugzilla Report 52556.

 * Launcher fixed to pass the right class loader parent.
   Bugzilla Report 48633.

 * <junitreport> mishandled ${line.separator}.
   Bugzilla Report 51049.

 * <junitreport> did not work in embedded environments on JDK 7.
   Nor did <xslt> when using Xalan redirects.
   Bugzilla Report 51668, 52382.

 * Encoding of unicode escape sequences by the property file task
   Bugzilla Report 50515.

 * The code that implicitly sets the -source switch if only -target
   has been specified in <javac> was broken for Java 5 and 6.
   Bugzilla Report 50578.

 * MailLogger ignore the Maillogger.starttls.enable property.
   Bugzilla Report 50668.

 * Delete task example does not work
   Bugzilla Report 50816.

 * <splash>'s proxy handling has been delegated to <setproxy>
   internally so the two tasks are consistent.  <splash>'s way of not
   setting a proxy caused problems with other Java libraries.
   Bugzilla Report 50888.

 * Include task breaks dependencies or extension-points for multiple
   files.
   Bugzilla Report 50866.

 * Read on System.in hangs for forked java task.
   Bugzilla Report 50960.

 * FileResource specified using basedir/name attributes was non-functional.

 * Resource collection implementation of mapped PropertySet returned
   unusable resources.

 * The hasmethod condition failed with a NullPointerException when
   ignoresystemclasses is true and Ant tried to load a "restricted
   class" - i.e. a class that the Java VM will only accept when loaded
   via the bootclassloader (a java.* class).
   It will now fail with a more useful error message.
   Bugzilla Report 51035.

 * Exec task may mix the stderr and stdout output while logging it
   Bugzilla Report 50507.

 * Missing space between "finished" and timestamp in task/target 
   finish message from ProfileLogger.
   Bugzilla Report 51109.

 * Redirecting the output of a java, exec or apply task could print in the
   error output stream some "Pipe broken" errors.
   Bugzilla Report 48789.

 * ZipFile failed to clean up some resources which could lead to
   OutOfMemoryException while unzipping large archives.
   A similar problem in ZipArchiveOutputStream has been fixed as well.
   Bugzilla Report 42696.

 * quiet attribute added to the copy and move tasks, to be used together
   with failonerror=false, so warnings won't get logged 
   Bugzilla Report 48789.

 * System.in was closed and not readable anymore by the DefaultInputHandler 
   when Ant is used via its Java API.
   Bugzilla Report 51161

 * <sync> only supported a single non-fileset resource collection even
   though the manual said it could be multiple.

 * <sync> didn't work properly when working on resource collections.
   Bugzilla Report 51462.

 * <augment> cause a NullPointerException if it was used in a target
   that was invoked by multiple targets from the command line.
   Bugzilla Report 50894.

 * The ZipFile class could read past the start of the file if the
   given file is not a ZIP archive and it is smaller than the size of
   a ZIP "end of central directory record".

 * <javac> would create the empty package-info.class file in the wrong
   directory if no destdir was specified.  Note it may still pick the
   wrong directory if you specify more than one source directory but
   no destDir.  It is highly recommended that you always explicitly
   specify the destDir attribute.
   Bugzilla Report 51947.

 * packagemapper now honors the handleDirSep attribute.
   Bugzilla Report 51086.

 * the attributes of macrodef tasks had their values run through
   property expansion twice. Still true by default, but can be disabled.
   Bugzilla Report 42046.

 * jvc doesn't like it if source file names in argument files are
   quoted.
   Bugzilla Report 31667.

 * ZipFile didn't work properly for archives using unicode extra
   fields rather than UTF-8 filenames and the EFS-Flag.

 * Access to DirectoryScanner's default excludes wasn't synchronized.
   Bugzilla Report 52188.

 * When a Project instance was created by a custom tasks its
   createTask method didn't work.
   Bugzilla Report 50788.

Other changes:
--------------

 * -f/-file/-buildfile accepts a directory containing build.xml.

 * The <javacc>, <jjtree> and <jjdoc> now support a new maxmemory
   attribute.
   Bugzilla Report 50513.

 * the documented inputstring attribute of sshexec has been
   implemented and the actually existing attribute inputproperty
   documented.
   Bugzilla Report 50576.

 * The concat task now permits the name of its exposed resource
   by means of its 'resourcename' attribute.

 * The expandproperties filter now accepts a nested propertyset
   which, if specified, provides the properties for expansion.
   Bugzilla Report 51044.

 * <junit filtertrace="true"/> will no longer filter out the very
   first line of the stacktrace containing the original exception
   message even if it matches one of the filter expressions.

 * Upgraded to Apache AntUnit 1.2

 * Provide read access to Mkdir.dir.  Bugzilla Report 51684.

 * <delete> and <move> have a new attribute performGCOnFailedDelete
   that may - when set to true - help resolve some problems with
   deleting empty directories on NFS shares.
   Bugzilla Report 45786.

 * <loadfile> and <loadresource> used to log at level INFO to signal a
   property hasn't been set when the resource was empty even if the
   quiet attribute was set to true.  They will now use VERBOSE
   instead.
   Bugzilla Report 52107.

 * <javac> has a new attribute createMissingPackageInfoClass that can
   be set to false to prevent Ant from creating empty dummy classes
   used for up-to-date-ness checks.
   Bugzilla Report 52096.

 * URLResources#isExists has become less noisy.
   Bugzilla Report 51829.

 * The <retry> task has a new optional attribute retryDelay that can
   be used to make the task sleep between retry attempts.
   Bugzilla Report 52076.

 * <signjar> has new attributes that control the signature and digest
   algorithms.
   Bugzilla Report 52344.

 * Initial support for Java 8.

 * <sshexec> can optionally create a pseudo terminal (like ssh -t)
   Bugzilla Report 52554.

Erster Milestone von Jersey 2, implementiert JAX-RS 2

Weitere Details im Blog http://marek.potociar.net/2012/02/22/first-milestone-build-of-jersey-2-0/. Für Clients gibt es vielleicht die größte Änderung: Die Einführung der JAX-RS Client API. Die API ist allerdings noch nicht verabschiedet, kann sich daher also ändern. Die bisherige Spezi von JAX-RS liegt unter http://jcp.org/aboutJava/communityprocess/edr/jsr339/index.html.

Inselupdate: Gepoolte Datenbankverbindungen

Da der Auf- und Abbau von Datenbankverbindungen relativ teuer ist, soll eine Java-Applikation die Verbindung nur vordergründig schließen, ein spezieller pooling-fähiger Datenbanktreiber soll die Verbindung allerdings für die nächste Operation offen halten. Für gepoolte Datenbankverbindungen gibt es eine Reihe quelloffener Implementierungen; zu ihnen zählen Apache Commons DBCP (http://commons.apache.org/dbcp/), c3p0 (http://sourceforge.net/projects/c3p0/) und Proxool (http://proxool.sourceforge.net/).

In der Regel sind für den Programmierer gepoolete Datenbankverbindungen transparent, denn ein poolender Treiber verhält sich wie ein ganz normaler JDBC-Treiber. Jeder Java EE-Container nutzt standardmäßig gepoolte Verbindungen, sodass sich Enterprise-Entwickler damit nicht beschäftigen müssen – nur Administratoren müssen spezielle Eigenschaften wie die maximale Anzahl offener Verbindungen konfigurieren. In Client-Anwendungen ist die Nutzung anders, auch der Bezug einer Verbindung. Bei Proxool wird zum Beispiel statt der JDBC-Treiberklasse die Proxool-Treiberklasse genannt, und die der Verbindungs-URL kodiert dann die eigentlichen JDBC-Treiberklasse; das sieht etwa so aus: Class.forName("org.logicalcobwebs.proxool.ProxoolDriver"); con = DriverManager.getConnection("proxool.example:org.hsqldb.jdbcDriver:jdbc:hsqldb:file:TutegoDB");. Anders ist das bei c3po, hier wird eine spezielle Klasse ComboPooledDataSource eingesetzt, die vom Typ DataSource ist.[1]

Simple-JNDI (http://openbook.galileocomputing.de/javainsel9/javainsel_24_011.htm) unterstützt DBCP direkt, sodass wir es an dieser Stelle einsetzen wollen. Eine zusätzliche Zeile pool=true in der Konfigurationsdatei veranlasst Simple-JNDI dazu:

Listing 1.14: TutegoDS.properties

type=javax.sql.DataSource
driver=org.hsqldb.jdbcDriver
url=jdbc:hsqldb:file:TutegoDB;shutdown=true
user=sa
password=
pool=true

Dazu sind in den Klassenpfad das Haupt-Archiv commons-dbcp-1.4.jar (Download unter http://commons.apache.org/dbcp/download_dbcp.cgi) und zusätzlich das Java-Archiv commons-pool-1.3.jar (von Jakarta Commons Pool, Download unter http://commons.apache.org/pool/download_pool.cgi) aufzunehmen.


[1] Weitere Details unter http://www.mchange.com/projects/c3p0/index.html.

Thema der Woche: Besondere Methoden der Renderer

Der “Bug” http://bugs.sun.com/view_bug.do?bug_id=4706356 führte zu einer Änderung, die http://docs.oracle.com/javase/7/docs/technotes/guides/swing/1.5/index.html so beschreibt:

Swing’s cell rendenders override a handful of methods to do nothing as they are not needed for cell renderers. They should override a couple of methods that are now being called to do nothing.

The following methods were added to DefaultTableCellRenderer, DefaultListCellRenderer and DefaultTreeCellRenderer

    /**
     * Overridden for performance reasons.
     * See the <a href="#override">Implementation Note</a>
     * for more information.
     *
     * @since 1.5
     */
    public void invalidate();
    /**
     * Overridden for performance reasons.
     * See the <a href="#override">Implementation Note</a>
     * for more information.
     *
     * @since 1.5
     */
    public void repaint();

Erkläre die Arbeitsweise und warum die Methoden überschrieben wurden. (Ist das Listing oben überhaupt korrekt?) Wie sieht das bei Komponenten bei SwingX aus?

Thema der Woche: Statische Analysetools und eigene Regelwerke

  • FindBugs, PMD und Checkstyle sind drei statische Codeanalysetools. Sie nutzen unterschiedliche Eingaben für ihre Analyse. Wo liegt der Unterschied?
  • PMD, FindBugs und Checkstyle kann man um eigene Regeln erweitern. Lies, wie das geht und gib eine kurze Übersicht.
  • Im Quellcode von Java gibt es (immer noch) Stellen, in denen unsinnigerweise von java.lang.Object geerbt wird, etwa bei der java.lang.Character-Klasse (in Java 7 gefixt):
    public final class Character extends java.lang.Object
    implements java.io.Serializable, Comparable<Character>

    Schreibe eine Regel (in einem beliebigen Framework), um genau solche Klassen zu finden.

Erster Draft für “Annotations on Java Types” (JSR-308)

http://jcp.org/aboutJava/communityprocess/edr/jsr308/index2.html. Aus der Spezi:

JSR 308 extends Java to allow annotations on any use of a type, and on type parameter declarations.

Beispiele:

for generic type arguments to parameterized classes:
Map<@NonNull String, @NonEmpty List<@Readonly Document>> files;
for generic type arguments in a generic method or constructor invocation:
o.<@NonNull String>m("…");
for type parameter bounds, including wildcard bounds:
class Folder<F extends @Existing File> { … }
Collection<? super @Existing File>
for class inheritance:
class UnmodifiableList<T> implements @Readonly List<@Readonly T> { … }
for throws clauses:
void monitorTemperature() throws @Critical TemperatureException { … }
for typecasts:
myString = (@NonNull String) myObject;
It is not permitted to omit the Java type, as in myString = (@NonNull) myObject;.
for constructor invocation results (that is, for object creation):
new @Interned MyObject()
new @NonEmpty @Readonly List<String>(myNonEmptyStringSet)
myVar . new @Tainted NestedClass
For generic constructors (JLS §8.8.4), the annotation follows the explicit type arguments (JLS §15.9):
new <String> @Interned MyObject()
for type tests:
boolean isNonNull = myString instanceof @NonNull String;
It is not permitted to omit the Java type, as in myString instanceof @NonNull.

Damit einher geht eine krasse Änderung, das bei Objektmethoden einfach so ein this Übergeben werden kann.

It is permitted to explicitly declare the method receiver as the first formal parameter

As an example, here are the standard definitions for toString and equals:
class MyClass {

public String toString() { … }
public boolean equals(Object other) { … }
}
It is equivalent to write instead
class MyClass {

public String toString(MyClass this) { … }
public boolean equals(MyClass this, Object other) { … }
}
and then it would be possible to annotate the receiver’s type:
class MyClass {

public String toString(@Readonly MyClass this) { … }
public boolean equals(@Readonly MyClass this, @Readonly Object other) { … }
}

Interessant finde ich noch:

To ease the transition from standard Java SE 7 code to code with type annotations, the reference implementation
recognizes the type annotations when surrounded by comment markers:
List</*@Readonly*/ Object> myList;
This permits use of both standard Java SE 7 tools and the new annotations even before Java SE 8 is released

Thema der Woche: Java "Smart and Simple Web Crawler"

http://java.net/projects/crawler/ ist ein Web-Crawler in Java. Die API könnte zwar viel einfacher sein, aber dennoch ist mit Hilfe der beigefügten Beispiele (http://java.net/projects/crawler/downloads/directory/1.3.0) schnell ein Programm implementiert.

Aufgabe: Liste die ersten 5 Links auf, die von der Hauptseite spiegel.de in den den Bereich http://www.spiegel.de/thema/ führen. Überlege dazu ein Fragment wie

LinkFilterUtil.and( new ServerFilter( “..” ),  new BeginningPathFilter( "/…/" ) )

zu nutzen.

Offtopic: Schöll AG und die Kopie der Seminarbeschreibungen, Teil 2

Nachdem ich 2009 im Beitrag http://www.tutego.de/blog/javainsel/2009/05/offtopic-content-klau-der-scholl-ag/ von dem “Entlehnen” meiner Semianarbeschreibungen berichtet habe, ist mir ganz entgangen, von dem Ausgang zu berichten.

Genau einen Tag vor dem Ablauf meiner gesetzten Zweiwochenfrist kommt ein Fax vom einer Anwalts-Sozietät in Darmstadt. (Über die Qualität der Web-Seite und der Rechtschreibung (“Angiffen”, “Umstrukturierunvon”) kann man streiten. Und “in englisch und französisch” schreibt man eigentlich “in Englisch und Französisch”, da als Substantive gebrauchte Adjektive und Partizipien großgeschrieben werden.)

Anstatt das ein Verantwortlicher der Schöll AG sagt; “Sory, dummer Fehler, kommt nicht wieder vor” gibt es kein Schuldeingeständnis. Schlimmer ist die Erklärung, mit der sich Schöll rauswinden will. Der Rechtsanwalt schreibt: “Unser Mandantin war aufgrund der zuvor geführten Gespräche zudem der Auffassung, Sie seien mit den Inhalten einverstanden. Wir werten Ihre E-Mail insoweit als Kündigung einer bestehenden Nutzungsberechtigung […]”. Ohne Frage gab es keine “zuvor geführten Gespräche” und von einer “bestehenden Nutzungsberechtigung” auszugehen ist falsch.

Daher habe ich nach dem Faxempfang am Freitag (29.05.2009) eine E-Mail an Schöll gesendet mit den Fragen

  1. wie viele Gespräche wir geführt haben,
  2. mit wem ich welches Gespräch geführt habe,
  3. zu welchem Zeitpunkt die Gespräche stattfanden und
  4. welchen Inhalt die Gespräche hatten.

Auf eine Antwort warte ich bis heute.

Rechtsanwalt Dr. Becker vertritt die Meinung, dass mein Inhaltsverzeichnis nicht “die für einen Urheberrechtsschutz erforderliche Schöpfungshöhe erreicht”. Die gängigen Urteile beziehen sich jedoch auf Inhaltsverzeichnisse von Büchern, nicht aber auf die Inhalte von Seminarbeschreibungen. Die Frage der Schöpfungshöhe und damit die des Urheberrechts müsste ein Gericht erst klären. Gibt es mangelnde Schöpfungshöhe, also das, was Dr. Becker hier durchscheinen lässt, gilt die Gemeinfreiheit. Das heißt, es gilt kein Urheberrecht und jeder könnte von jedem den Seminarinhalte übernehmen. Darüber wäre Schöll sicherlich auch nicht glücklich, wenn ich deren Seminareinhalte auf meine Webseite setze. Und das Problem der unerlaubten Leistungsübernahme ist hier noch nicht einmal angesprochen.

In der Summe halte ich die Öffentlichkeitsarbeit der Schöll AG für ein Desaster. Es zeigt sich immer, wie wenig Eier Unternehmen in der Hose habe um kurz und knapp “Sorry” zu sagen. Stattdessen ignorieren Unternehmen wie die Schöll AG Anfragen und schicken feige einen Anwalt vor. Naja, seit 3 Jahre ist die Sache abgeschlossen und Schöll hat fix eigene Seminarbeschreibungen aufgebaut. Die sind auch immer noch auf dem Stand von 2009 …

Es ist niemals schwieriger, das rechte Wort zu finden, als wenn man sich schämt.
– François de La Rochefoucauld (1613 – 1680)

Nützliches GWT-Wissen

  1. GWT.isScript() liefert false, wenn die Anwendung im Entwicklungsmodus läuft. isScript() liefert dann true, wenn die GWT-Anwendung in JavaScript übersetzt wurde. Die Funktion ist nützlich, wenn in der der lokalen Umgebung Dinge anders sind (etwa Pfade), als in der übersetzten Produktivversion.
  2. GWT.getModuleBaseURL() liefert die URL zum Wurzelverzeichnis der GWT-Applikation. Siehe dazu auch http://code.google.com/support/bin/answer.py?answer=60560&topic=10211.
  3. GWT.setUncaughtExceptionHandler() setzt einen Handler, der immer dann aufgerufen wird, wenn die Applikation eine RuntimeException sieht. Debuggen kann man etwa mit http://www.asquare.net/gwttk/apps/demo/Demo.html#debug.
  4. GWT 1.6 bringt einen neuen Eventing-Mechanismus mit (erinnert an EventBus). http://www.itsolut.com/chrismusings/2009/04/28/business-events-with-gwt-16/ stellt ihn vor.
  5. Neben dem Paket server und client gibt es das Paket public (etwa src/com/example/cal/public/), in das alles kopiert wird, das die Client als statische Ressourcen verwenden möchte. Es kommt zu den anderen compilierten Dokumenten. Siehe http://code.google.com/webtoolkit/doc/1.6/DevGuideOrganizingProjects.html#DevGuideDirectoriesPackageConventions.
  6. Eine eigene CSS-Datei für das Styling (etwa lala.css) setzt man zunächst in den in den public-Ordner. In der Bla.gwt.xml bei den <inherits> fügt man dann die Zeile <stylesheet src="lala.css"/> hinzu.
  7. panel.setHorizontalAlignment() setzt nicht den Panel selbst nach rechts/links, sondern alle Elemente, die folgen.
  8. Soll in einer Zeile ein Element rechts, das andere Links angeordnet sein, so kann man ein HorizontalPanel aufbauen, das auf 100% setzen, zwei Elemente rechts und links setzen und dann die Zellen jeweils mit setCellHorizontalAlignment(w1, HorizontalPanel.ALIGN_LEFT) und setCellHorizontalAlignment(w2, HorizontalPanel.ALIGN_RIGHT) ausrichten.