Die JavaMail API (Teil 2)

Steht die Verbindung zum Server, kann der Client eine Mailbox öffnen. Wir deklarieren dazu eine openPop3InboxReadOnly() und closeInbox() Methode.

com/tutego/insel/mail/MailUtils.java, Teil 2

public static Folder openPop3InboxReadOnly( Session session )

throws MessagingException

{

Store store = session.getStore( "pop3" );

store.connect();

Folder folder = store.getFolder( "INBOX" );

folder.open( Folder.READ_ONLY );

return folder;

}

public static void closeInbox( Folder folder ) throws MessagingException

{

folder.close( false );

folder.getStore().close();

}

Die Rückgabe von openPop3InboxRealOnly() ist ein Folder-Objekt und mit diesem lassen sich letztendlich die E-Mails abrufen:

com/tutego/insel/mail/MailUtils.java, Teil 3

public static void printAllTextPlainMessages( Folder folder )

throws MessagingException, IOException

{

for ( Message m : folder.getMessages() )

{

System.out.println( "\nNachricht:" );

System.out.println( "Von: " + Arrays.toString(m.getFrom()) );

System.out.println( "Betreff: " + m.getSubject() );

System.out.println( "Gesendet am: " + m.getSentDate() );

System.out.println( "Content-Type: " +

new ContentType( m.getContentType() ) );

if ( m.isMimeType( "text/plain" ) )

System.out.println( m.getContent() );

}

}

Die Implementierung holt sich mit getContent() den kompletten Inhalt, aber natürlich lässt sich der auch über einen Eingabestrom holen.

Ein kleines Demo dazu, was erst Verbindung mit dem Google Mail Server herstellt, dann sich den INPUT-Ordner öffnet und alle E-Mails abläuft. Die Nachrichten werden nicht vom Server gelöscht.

com/tutego/insel/mail/PrintAllMailsWithMailUtils.java, main()

Session session = MailUtils.getGMailSession(

JOptionPane.showInputDialog( "user" ),

JOptionPane.showInputDialog( "pass" ) );

Folder inbox = MailUtils.openPop3InboxReadOnly( session );

MailUtils.printAllTextPlainMessages( inbox );

MailUtils.closeInbox( inbox );

Das Programm öffnet zwei Dialoge, einen für den Benutzernamen und einen für das Passwort, es ist jedem selbst überlassen, hier feste Strings einzukodieren.

Hinweis

Um herauszufinden, ob überhaupt Nachrichten auf dem Server vorliegen, können wir auf dem aktuellen folder-Objekt die Methode getMessageCount() nutzen.

Nachricht löschen

Um eine Nachricht vom Server zu löschen, darf der Ordner nicht mit READ_ONLY geöffnet werden, sondern mit Folder.READ_WRITE. Anschließend lässt sich einer Nachricht, repräsentiert durch ein Message-Objekt, mit setFlag() ein Lösch-Hinweis geben:

message.setFlag( Flags.Flag.DELETED, true );

Die Daten werden jedoch nur dann vom Server gelöscht, wenn zum Schluss folder.close(true) aufgerufen wird. Ohne den Aufruf von close() mit dem Argument true bleiben die Nachrichten erhalten.

Guice 3.0 ist raus

Nach laaaanger Wartezeit ist DI-Framework Guice 3.0 veröffentlicht worden. Von http://code.google.com/p/google-guice/wiki/Guice30 die Neuerungen:

  • JSR 330 support
  • New Persist extension
  • ToConstructor Bindings
  • Better OSGi support (and generally improved support for multiple classloaders)
  • New methods in Binder: requireExplicitBindings & disableCircularProxies
  • Much simpler stack traces when AOP is involved
  • Exact duplicate bindings are ignored (instead of an exception being thrown)
  • Repackaged cglib, asm & guava classes are now hidden from IDE auto-imports
  • Source can be built with Maven
  • General extension & SPI improvements:
  • Scope improvements:
    • Scopes.isSingleton
    • toInstance bindings are considered eager singletons in the Scope SPI
    • Singleton providers that return null are now scoped properly.
    • Fail when circularly dependent singletons cannot be proxied (previously two instances may have been created)
  • Provider Method (@Provides) improvements:
    • Logger dependencies now use named instead of anonymous loggers
    • Exceptions produce a simpler stack
  • Private Modules improvements:
    • If a single PrivateModule is passed to Modules.override, private elements can be overridden.
    • If many modules are passed to Modules.override, exposed keys can be overridden.
  • Multibinder & MapBinder extension improvements:
    • permitDuplicates — allows MapBinder to inject a Map<K, Set<V>> and a Map<K, Set<Provider<V>> and Multibinder to silently ignore duplicate entries
    • Expose dependencies in Stage.TOOL, and return a dependency on Injector (instead of null) when working with Elements.
    • Co-exist nicely with Modules.override
    • Work properly with marker (parameterless) annotations
    • Expose details through the new extensions SPI
  • Servlet extension improvements:
    • Added with(instance) for servlet bindings.
    • Support multiple injectors using ServletModule in the same JVM.
    • Support thread-continuations (allow background threads to process an HttpRequest)
    • Support manually seeding a @RequestScope
    • Expose details through new extensions SPI
    • Fix request forwarding
    • Performance improvements for the filter & servlet pipelines
    • Expose the servlet context (ServletModule.getServletContext)
    • Fixed so a single ServletModule instance can be used twice (in, say Element.getElements & creating an Injector)
    • Fix to work with context paths
  • AssistedInject extension improvements
    • New FactoryModuleBuilder for building assisted factories
    • Injection is done through child injectors and can participate in AOP
    • Performance improvements
    • Multiple different implementations can be created from a single factory
    • Incorrect implementations or factories are detected in Stage.TOOL, and more error-checking with better error messages
    • Work better with parameterized types
    • Expose details through new extensions SPI
  • ThrowingProviders extension improvements
    • Added a new CheckedProviders interface that allows more than one exception to be thrown.
    • Added @CheckedProvides allowing @Provides-like syntax for CheckedProviders.
    • Dependencies are checked at Injector-creation time and during Stage.TOOL, so they can fail early
    • Bindings created by ThrowingProviderBinder now return proper dependencies instead of Injector.
  • Struts2
    • The Struts2 extension now works again! (It worked in Guice 1.0 and was somewhat broken in Guice 2.0)
  • Added to Injector: getAllBindings, getExistingBinding, getScopeBindings, getTypeConverterBindings.
  • Added to Key: hasAttributes, ofType, withoutAttributes
  • Various bug fixes / improvements:
    • Prevent child injectors from rebinding a parent just-in-time binding.
    • Non-intercepted methods in a class with other intercepted methods no longer go through cglib (reducing total stack frames).
    • Allow Guice to work on generated classes.
    • Fix calling Provider.get() of an unrelated Provider in a scoping method.
    • MoreTypes.getRawTypes returns the proper types for arrays (instead of Object.class)
    • JIT bindings left in a parent injector when child injectors fail creating a JIT binding are now removed
    • Overriding an @Inject method (if the subclass also annotates the method with @Inject) no longer injects the method twice
    • You can now bind byte constants (using ConstantBindingBuilder.to(byte))
    • Better exceptions when trying to intercept final classes, using keys already bound in child or private module, and many other cases.
    • ConvertedConstantBinding now exposes the TypeConverterBinding used to convert the constant.

Inselupdate: Primitive Elemente in Datenstrukturen verwalten

Jede Datenstruktur der Collection-API akzeptiert, auch wenn sie generisch verwendet wird, nur Objekte. Primitive Datentypen nehmen die Sammlungen nicht auf, was zur Konsequenz hat, dass Wrapper-Objekte nötig sind (über das Boxing fügt Java 5 scheinbar primitive Elemente ein, doch in Wahrheit sind es Wrapper-Objekte). Auch wenn es also heißt:

List<Double> list = new ArrayList<Double>();

list.add( 1.1 );

list.add( 2.2 );

sind es zwei neue Double-Objekte, die aufgebaut werden, und in die Liste wandern. Anders und klarer geschrieben, was wirklich passiert:

List<Double> list = new ArrayList<Double>();

list.add( Double.valueOf(1.1) );

list.add( new Double(2.2) );

Dem Double.valueOf() ist der new-Operator nicht abzulesen, doch die Methode ist implementiert als: Double valueOf(double d){ return new Double(d); }.

Spezialbibliotheken

Für performante Anwendungen und großer Menge von primtiven Elemente ist es sinnvoll, eine Klasse für den speziellen Datentyp einzusetzen. Anstatt so etwas selbst zu programmieren, kann der Entwickler auf drei Implementierungen zurückgreifen:

  • fastutil (http://fastutil.dsi.unimi.it/). Erweiterung um Datenstrukturen für (sehr viele) primitive Elemente und hochperformante Ein-/Ausgabe-Klassen.
  • GNU Trove (http://trove.starlight-systems.com/). Stabil und Entwicklung ist aktiv. Neue Datenstrukturen aus Java 5 oder 6 wie Queues zählen jedoch nicht dazu.
  • Apache Commons Primitives (http://jakarta.apache.org/commons/primitives/). Stabil in der Version 1.0, aber seit Ende 2003 nicht mehr aktualisiert.
  • JSR 334 (Project Coin) ist im Public Review

    Details unter http://blogs.sun.com/darcy/entry/project_coin_jsr_334_pr (Download des Drafts unter http://jcp.org/aboutJava/communityprocess/pr/jsr334/index.html).

    Allerdings gibt es Unmut, weil zwar alle so schön “Oracle-open” sein soll, aber nichts dokumentiert ist. Daher ist völlig offen, ob seit dem letzten Pre-Release Vorschläge von der Community angenommen wurden, und wenn ja, welche, und wenn nein, warum nicht.

    Inselupdate: Blockierende Warteschlangen

    Die Schnittstelle BlockingQueue steht für besondere Queues, die blockieren können. Das kann aus zwei Gründen geschehen: entweder sind keine Daten zu entnehmen da die Queue leer ist, oder eine maximale Anzahl von zu haltenden Elementen ist erreicht. Besonders in Produzenten/Konsumenten-Szenarien sind blockierende Warteschlangen sehr nützlich.

    Eine performante thread-sichere Implementierung ist in der Praxis sehr wichtig und die Java SE Bibliothek hat zwei besondere Realisierungen auf Lager:

    • ArrayBlockingQueue: Queue immer mit einer maximalen Kapazität, realisiert intern mit einem Feld
    • LinkedBlockingQueue: Queue unbeschränkt oder mit maximaler Kapazität, intern realisiert durch eine verkettete Liste
    • PriorityBlockingQueue: Eine blockierende PriorityQueue

    Die anderen Realisierungen wie DelayQueue sind für uns jetzt nicht relevant.

    Das schöne an blockierenden Warteschlangen ist ihr Verhalten in Produzenten/Konsumenten-Verhältnissen; ein Thread (oder beliebig viele Threads) setzt (viele setzen) Daten in die Queue, ein Thread (oder beliebig viele Threads) holt (viele Threads holen) die Daten wieder raus. Bei einer Queue ist es ja so, dass sie nach dem FIFO-Verfahren arbeitet, das heißt, die Daten, die zuerst reingelegt wurden, werden auch zuerst verarbeitet. Bei einer Prioritätswarteschlage ist das etwas anders, aber dazu gleich mehr.

    Java SE 7 Developer Preview Release verfügbar

    Oracle schreibt im Blog http://blogs.oracle.com/java/2011/02/java_se_7_developer_preview_release_now_available.html , dass die Java SE 7 Developer Preview Release verfügbar ist. Download unter http://jdk7.java.net/preview/.

    Interessant ist, dass JSR 308 nicht Teil von Java 7 sein wird und gemachte Änderungen wieder rausfliegen: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7015156.

    Eine echtere Änderung ist auch http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7012540, hier muss ich in der Insel etwas umbenennen.

    Weiterhin sind NIO2 Methoden hinzugekommen, auch etwas, was ich für die kommende Version aktualisieren muss: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7006126. Die neue Files-Klasse geht in Richtung Google Guava.

    Auch http://hg.openjdk.java.net/jdk7/jdk7/jdk/rev/82c8c54ac1d5 ist gefixt.

    Thema der Woche: Kindle-HTML auf Korrektheit prüfen

    Der eBook-Reader Kindle kann HTML-Seiten anzeigen, ist allerdings mit dem HTML etwas eingeschränkt. So sind nur ganz bestimmte HTML-Tag und dann auch nicht alle Attribute erlaubt. Der Anhang “Appendix. Supported HTML tags" in der PDF “Amazon Kindle Publishing Guidelines. How to make books available for the Kindle platform” erklärt welche.

    Aufgabe: Schreibe ein Java-Programm, welches eine HTML-Datei (wir können vereinfacht annehmen XHTML) analysiert, ob nur unterstützte HTML-Tags und Attribute vorkommen und andernfalls eine Fehlermeldung ausgibt. Hinweis: Natürlich soll das Programm nicht aus 100 Fallunterscheidungen bestehen, sondern das ganze soll etwas clever programmiert werden. Könnte ein Guava Typ wie com.google.common.collect.Mulimap vielleicht helfen?

    Java taucht nix für Enterprise? Meine Gedanken

    Nach dem Eintrag im Blog (http://www.tutego.de/blog/javainsel/2011/02/forrester-untersuchung-sagt-java-taugt-nix-fr-enterprise/) über die Forrster Studie fragte ein Kommentator nach meiner Einschätzung. Also, taucht Java ab oder taugt es?

    Es ist schwer einen Anfang zu finden, denn verschiedene Sachen laufen immer durcheinander. Zunächst ist Java eine Vereinigung:

    Java = JVM + Java als Programmiersprache + Java SE Lib + Java EE Lib (wenn man Enterprise hinzunehmen möchte)

    Man könnte noch “Great Communitiy” oder große Anzahl Open-Source Libs dazu nehmen, aber darauf kommt es jetzt nicht an.

    An den Gliedern kann man anfangen unter verschiedenen Bewertungskriterien rumzunörgeln. Es steht außer Frage das die JVM unglaublich leistungsfähig ist. Bei der Programmiersprache Java fängt aber die Kritik schon an – bei der Java SE geht es weiter. Java EE kann man auch kritisieren, jedoch für einen anderen Grund.

    • Die Sprache Java hat sich die letzten Jahre nicht gewandelt, aber Skriptsprachen zeigen zum Beispiel deutlich den Trend auf, Collection-Unterstützung in den Sprachkern aufzunehmen und Closures sowie funktionale Aspekte zu unterstützen desweiteren Nebenläufig besser anzugehen.
    • Die Bibliotheken haben deutliches Potenzial. Einmal horizontal (unterschiedlichen Technologien) wie vertikal (in der Tiefe). Wenn Java SE schon fertig wäre, wäre Apache Commons * oder Google Collections/Guava gar nicht nötig. Wenn Java EE auch den Web-Technologie-Teil abdecken soll, OOOHA, da ist noch viel zu tun.

    Der Autor der Studie ist nicht gegen Java: die Folien zeigen, das Java in vielen Bereichen perfekt passt. Er macht aber klar, dass Java eben nicht für jedes Problem die Antwort ist. Da hat der Mann natürlich Recht! Mit der Banane einen Nagel in die Wand zu schlagen wird auch kompliziert. Java ist explizit als General Purpose Sprache entworfen worden. Das heißt: Für alles und nichts! Während man außer Frage stellt, Java im Bereich Treiberprogrammierung einzusetzen, versuchen viele Java (also die Sprache + Java SE + Java EE) dort einzubringen, wo es bessere Lösungen gibt. Java ist im Gui-Bereich einfach schwach. Punkt. Gui ohne Databinding? Nicht gut. (Es geht immer noch darum, dass es kein Teil der Standard-Bibliotheken ist. Natürlich gibt es Databinding am Open-Source-Himmel … sogar gaaaanz viele Lösungen.) Es steht außer Frage, dass man mit Swing und JSF absolut geile Lösungen bauen kann. Doch Softwareentwicklung besteht nicht daraus, mit ein paar Experten ein System zu bauen; gibt Experten FORTRAN oder COBOL und auch dann wird das Design super sein.

    Die zentralen Schwachpunkte im Gui-Bereich sind:

    • Zu kompliziert mit den STANDARD-Frameworks für den Durchschnitts-Joe. In einer Tabelle eine Fließkommazahl mit zwei Nachkommastellen zu formatieren muss einfacher gehen als extra einen Cell-Renderer zu programmieren.
    • Für echte Oberflächen muss man zukaufen, OS-Libs nehmen, oder stark in Eigenentwicklung investieren. Databinding gibt es, klar, aber eben nicht im Java SE. Man schaue nur auf Eclipse RCP und dann sieht man, was in Swing alles fehlt.
    • Agil mal eben schnell eine Änderungen umzusetzen geht nicht.

    WENN man also Gui-Entwicklung zur Enterprise-Entwicklung zählt – und das tut der Autor der Studie, das ist aber auch Diskussionssache – hat er mit seiner Kritik recht. Mich wundert, was es an dem Punkt zu diskutieren gibt. Die Diskussion gleitet schnell in die Richtung das man sagt: Ja, aber in Ruby, mit Eclipse RCP, mit Vaadin, mit bla, … geht das alles! Stimmt, es geht aber hier um pures Java und um das, was in Java SE/Java EE von Oracle kommt. Hier hat eben Java nichts zu bieten. Ich finde Swing toll und mag es, aber für heutige Richclient-Anwendungen ist das nichts. Auch JSF ist nichts für moderne RIA-Anwendungen. Viel zu HTML-lasting.

    Java EE ist im Kern ausgereift und für Geschäftslogik und Persistierung nahezu perfekt. Container wie GlassFish machen es rund. Hier liegt nicht das Problem. Entwickler großer Anwendungen müssen lernen das richtige Tool für den Job zu finden. Im Enterprise Bereich ist Java EE 6 ein guter Anfang für das Backend. Den Gui-Bereich können wir aufgeben. Klar, das es mit Swing und JSF “irgendwie geht”, aber wie gesagt: es darf keine Technologie für Experten sein. Es wird natürlich immer Softwareentwickler geben die sich wünschen, das eine Technologie für Experten ist, aber es geht um Wirtschaftlichkeit, ob wir das wollen oder nicht. Und wenn eben ein Swing-Entwickler für einen neuen Button 20 Minuten im Quellcode braucht, der Silverlight-Entwickler aber nur 5 Minuten, ist klar, wie die Rechnung aussieht. Und selbst das ist noch viel zu low-level gedacht.

    Selbst wenn man Java aufbohrt und pimpt bis zum Abwinken mit Business-Rules-Engine, alles in dynamischen Programmiersprachen auf der JVM entwickelt, usw. usw., es wird immer noch zu viel selbst gebaut. Entwickler müssen lernen, sich in komplexe existierende Systeme einzuarbeiten, und auf deren Basis eigene Lösungen entwickeln. Im Web-Bereich sei einmal der JBoss-Stack oder Alfresco in den Raum geworfen, aber auch richtig fette Sachen wie SAP, auch wenn vielen das nicht gefallen dürfte. Oder Talend zur Konvertierung. Der Autor der Studie lässt Alternativen vielleicht bewusst offen (RoR wird genannt im Web-Bereich) und ich vermute einfach deswegen weil es keine Alternativen gibt! Oracle bietet eine wunderbare Basis aber es liegt an uns, mächtigere Framworks, und dann auch DSL für spezifische Probleme zu nutzen. Java hat seinen Platz und ist eben nicht für alles zu gebrauchen. Ich erinnere mich gut an dBASE, das zeigt schon vor über 10 Jahren die Richtung auf: Eine Entwicklungsumgebung mit Programmiersprache. Das ist Rapid Application Development von datatenbankgetriebenen Anwendungen. Eigenentwicklung wird es immer geben, aber für gewisse Probleme funktionieren wunderbar 4GL-Lösungen.

    JBoss jBPM in der Version 5

    Die Hauptseite http://www.jboss.org/jbpm zählt als Neuerungen auf:

    jBPM5 is the latest community version of the jBPM project.  It is based on the BPMN 2.0 specification and supports the entire life cycle of the business process (from authoring through execution to monitoring and management).

    The current jBPM5 snapshot offers open-source business process execution and management, including

    • embeddable, lightweight Java process engine, supporting native BPMN 2.0 execution
    • BPMN 2.0 process modeling in Eclipse (developers) and the web (business users)
    • process collaboration, monitoring and management through the Guvnor repository and the web console
    • human interaction using an independent WS-HT task service
    • tight, powerful integration with business rules and event processing

    Contracts für Java

    Ein neues Projekt eines Google-Mitarbeiter verspricht Zusicherungen zur Laufzeit zu prüfen. Ankündigung: http://google-opensource.blogspot.com/2011/02/contracts-for-java.html, Projekt unter http://code.google.com/p/cofoja/. Mal sehen wie sich das entwickelt, im .NET Umfeld ist da einiges im Gange. In Java 7 waren mal einige Annotationen geplant, die sind aber gestorben. @NotNull und so weiter hat sich als sehr nützlich erwiesen, das funktioniert in der Praxis.