Drag&Drop aus MS Outlook nach jadice

In diesem Artikel illustrieren wir, wie die Integration von jadice mit Desktop-Komponenten es Anwendern erlaubt, auf einfache Weise Inhalte aus Anwendungen in Dokumente zu integrieren. Dieses Beispiel befasst sich mit MS Outlook. Die verwendeten Techniken sind jedoch auch auf andere Anwendungen übertragbar.

Dramatis personae

MS OutlookEine verbreitete Desktop-Anwendung. Geliebt und gehasst zugleich. Zunächst widerspenstig, wenn es darum geht, Daten herauszugeben. Handzahm, wenn die richtigen Worte gefunden werden.
Jadice Swing ViewerEine Anwendung mit viel Hunger auf Input.
Das Java Drag-and-Drop SubsystemHat immer etwas anzubieten, oft aber nicht das, was man haben will.
Jadice serverEs gibt (fast) nichts, was er nicht irgendwie hinbiegen kann.

Erster Akt: ein Brief erreicht seinen Empfänger

Um in jadice per Drag&Drop (oder Clipboard-Transfer) Daten entgegenzunehmen muss das Interface ImportHandler implementiert werden. Der Import Handler hat drei Aufgaben, die in verschiedenen Phasen des Transfers erfüllt werden müssen:

  1. Entscheiden, ob ein Transfer Daten enthält, mit denen der Handler etwas anfangen kann. Dazu muss in der Methode isDataFlavorSupported entschieden werden, ob das angebotene DataFlavor einen passenden Typ hat.
  2. Entscheiden, auf welche Art ein Transfer ausgeführt werden soll, d.h. welche Semantik der Transfer bekommt. Die Methode getImportActionForFlavor liefert dazu eine oder-Verknüpfung der in DnDConstants definierten Werte zurück. Dadurch kann signalisiert werden, ob der Transfer kopierenden, verschiebenden, verknüpfenden Charakter hat.
  3. Den eigentlichen Transfer ausführen, indem das transferierte Objekt entgegengenommen und verarbeitet wird. Worin das Objekt genau besteht, hängt von verwendeten DataFlavor ab.

Der Transfer von Outlook-Elementen stellt sich hier als besonders problematischer Fall heraus, denn das transferierte Objekt ist nicht direkt ein verarbeitbares Nachrichtenobjekt, sondern lediglich einige Werte aus den Kopfzeilen der Nachricht. Diese werden als einfache Zeichenkette transferiert. Grund für diese Einschränkung ist weniger Outlook als das Java DnD-Subsystem, denn Outlook offeriert die Transferdaten bevorzugt als COM-Referenz, die jedoch von Java nicht verarbeitet und an die Anwendung weitergereicht wird. Dadurch erfolgt der Rückfall auf einfache Textdaten, die uns das Leben schwer machen.

Die der Methode isDataFlavorSupported offerierten DataFlavors sind sehr vielfältig. Leider ist allen gemein, dass sie lediglich eine einfache Textrepräsentation der Nachricht umfasst, die z.B. so aussehen könnte:

An        Betreff         Gesendet    Größe    Kategorien   
tester    Nur ein Test    11:19       3 KB       

Daraus ergibt sich die unerfreuliche Einschränkung, dass ein ImportHandler für MS Outlook zunächst alle Transfers, die Plain-Text beinhalten "auf Verdacht" entgegennehmen muss, um anhand des transferierten Texts dann zu entscheiden, ob es sich um einen Outlook-Transfer handelt. Darüber hinaus führt uns diese Feststellung zu der Frage, wie genau wir denn nun an die Daten der Nachricht(en) herankommen.

Zweiter Akt: ein konspiratives Treffen auf halber Strecke

Wurde ein Transfer erkannt, der darauf hindeutet, dass er von Outlook stammt, müssen wir im nächsten Schritt Outlook etwas entgegenkommen, um an die Daten der Nachricht zu gelangen. Leider müssen wir uns dazu mit einer aus Java-Sicht unangenehmen Technologie auseinandersetzen: COM bzw. DCOM. Dabei handelt es sich um die Microsoft-spezifische Inkarnation einer objektorientierten RPC-Schnittstelle. Diese wird von Java nicht "out-of-the-box" unterstützt, aber alles Jammern hilft nicht, denn COM ist der Mechanismus, den Outlook anbietet.

Zum Glück wurde das prinzipielle Problem, COM zu sprechen, bereits gelöst: die Jacob-Bibliothek erlaubt es uns, von Java aus entsprechende Aufrufe durchzuführen. Der Ablauf gestaltet sich wie folgt:

  1. Wir verschaffen uns grundsätzlichen Zugriff auf Outlook indem das ActiveX-Objekt Outlook.Application angesprochen wird.
  2. Diese befragen wir nach der Nachrichtenliste in Form des aktiven Explorers.
  3. Dieser wiederum kennt die ausgewählten Nachrichten in Form der Selection.
  4. Die Nachrichten selbst sind Objekte vom Typ MailItem.
  5. Wir instruieren Ouklook uns die einzelnen MailItems in temporäre MSG-Dateien zu schreiben.

Der Ablauf klingt kompliziert, tatsächlich handelt es sich aber lediglich um wenige Zeilen Code, an deren Ende wir pro transferierter Nachricht eine MSG-Datei vorliegen haben.

Dritter Akt: eine Datei geht hinein, eine andere kommt heraus

Eine MSG-Datei ist schön und gut - wobei man über "schön" durchaus geteilter Meinung sein kann - aber in einem Dokumentenarchiv hat diese wenig zu suchen. Darüber hinaus fängt jadice Viewer mit einer MSG-Datei wenig an. Eine Konvertierung muss also her. Hier kommt uns jadice server gerade gelegen, da dieser MSG verarbeiten und inklusive aller Anhänge nach PDF konvertieren kann. Hierzu benötigen wir eine Pipeline in jadice server, die die folgenden Schritte umfasst:

Der Hauptteil der "Magie" des Konvertierungsvorgangs steckt dabei in dem Skript, das für den ScriptNode auf dem Server hinterlegt wurde. Im Lieferumfang findet sich dazu ein Skript, das die Konvertierung von E-Mail und Anhängen unterstützt. Dieses Skript kann anwendungsspezifisch angepasst werden.

Vierter Akt: was lange währt, wird endlich gut

Als Ergebnis des Konvertierungsvorgans via jadice server erhalten wir (hoffentlich) ein ansehnliches PDF. Es bleibt uns lediglich die Aufgabe, dieses PDF dem aktuellen Dokument hinzuzufügen. Dies fällt uns sehr leicht, denn der Importvorgang hat über die ImportParameter Zugriff auf das aktuelle Document. Wir können es uns nun sehr einfach machen, indem wir einen Reader erstellen, diesem das aktuelle Dokument und die gewünschte Seitenposition als Ziel des Lesevorgangs übergeben und ihm dann ohne viel Aufhebens den Datenstroms des konvertierten PDFs zum Einlesen übergeben. Damit ist unser ImportHandler grundsätzlich vollständig:

MSOutlookImportHandler.java

Letzter Akt: lose Enden fügen sich zusammen

Zwar haben wir nun einen ImportHandler implementiert, um diesen zu aktivieren ist jedoch noch ein kleiner weiterer Schritt notwendig: die Registrierung des ImportHandles in der View, in der er aktiv sein soll. Im Auslieferung des jadice Swing Viewers findet sich die BasicDemoApplication, die uns als Beispiel dienen soll, wie die Registrierung zu bewerkstelligen ist. Die Methode BasicDemoApplication.doConfigureImportExportHandlers(ThumbnailView) konfiguriert standardmäßig diejenigen ImportHandler, die von ImportExportHandlerFactory.createDefaultPageImportHandlers() bereitgestellt werden. Das folgende Beispiel ersetzt diese Konfiguration durch einen einzigen MSOutlookImportHandler. Dadurch wird nur noch von MS Outlook importiert, allerdings können über einen CompositeHandler auch andere Handler wieder mit eingebunden werden.

  protected void doConfigureImportExportHandlers(ThumbnailView thumbnailView) {
    thumbnailView.setImportHandler(
        new MSOutlookImportHandler("^(Von|An)\\s+Betreff\\s+(Erhalten|Gesendet)\\s+Größe\\s+Kategorien.*",
        new ActiveMQConnectionFactory("tcp://jadice-server:61616"), null));
    
    thumbnailView.setExportHandler(ImportExportHandlerFactory.createDefaultPageExportHandler());
  }

Der MSOutlookImportHandler enthält via Konstruktor einige notwendige Konfigurationsinformation:

  • Als notwendiges Übel zunächst das Regex-Pattern, mit dem erkannt wird, dass es sich um einen Transfer aus Outlook handelt. Das Pattern muss leider für verschiedene Sprachversionen von Outlook jeweils ergänzt werden. In oben stehenden Form funktioniert es natürlich nur für die deutsche Version.
  • Als nächstes die QueueConnectionFactory für jadice server. In oben stehendem Beispiel eine Factory, die für eine Kommunikation via ActiveMQ funktioniert. Die URL von jadice server muss selbstverständlich installationsspezifisch angepasst werden.
  • Als letztes kann optional ein oben nicht angegebener ImportHandler für Plain-Text angegeben werden, an den Imports delegiert werden, falls der übertragene Text als nicht aus Outlook stammend erkannt wird.

Damit ist unser Beispiel vollständig!

Ausblick

Es sei an dieser Stelle der Hinweis gestattet, dass das oben skizzierte Beispiel nur dazu gedacht ist, eine grobe Idee davon zu vermitteln, wie eigene ImportHandler in jadice integriert werden können. Es erhebt nicht den Anspruch produktionsreifer Code zu sein. Offene Punkte sind z.B. die folgenden:

  • es findet nur eine sehr eingeschränkte Fehlerbehandlung statt
  • es wurde lediglich mit dem aktuellen Office 2016 getestet
  • die D&D-Unterstützung funktioniert nur mit dem Desktop-Office - eine Unterstützung für Outlook Web Access ist nicht gegeben
  • die Unterstützung beschränkt sich auf Outlook-Objekte aus der Listenansicht. Anhänge aus der Nachrichten-Ansicht können auch unterstützt werden, erfordern aber eine andere Handhabung
  • der Import findet synchron statt, d.h. die Oberfläche wird während der Interaktion mit Outlook und der Konvertierung blockiert