Bei der Entwicklung von mehreren Plugins kann es vorkommen, dass Texte mehrfach übersetzt werden müssen, wodurch somit Redundanzen entstehen. Der Ursprung liegt dann bei Atlassian Confluence, welches das Sharen von i18n-keys über die verschiedenen Plugins hinweg nicht ermöglicht.
Angenommen man hat ein Plugin X entwickelt und in ihm den i18n-key manager.user.email definiert. Zusätzlich existiert ein Plugin Y, dass Plugin X um weitere Funktionalität ergänzt und eine neue vm anlegt, die eben auch den i18n-key manager.user.email verwenden soll. Nun gibt es das Plugin-Konzept von Confluence nicht her auf die in den properties definierten Texte von Plugin X zuzugreifen. Dies bedeutet, dass der Key auch im Plugin Y hinterlegt werden muss. Folglich ergibt sich ein erhöhter Pflegeaufwand.
Damit Redundanzen beseitigt werden können, müssen die i18n-keys zentral abgelegt werden. Dazu kann man einen bestimmten Plugintyp von Confluence – das Sprachplugin – nutzen.
Diese Erkenntnis ist wichtig, da für die Lösung des oben genannten Problems, es notwendig ist, die Standard Sprachplugins von Confluence zu deinstallieren und die darin enthaltenen property Dateien in das neue SprachPlugin zu überführen.
Außerdem muss die atlassian-plugin.xml des Sprachplugins, wie folgt angepasst werden.
<language name="German" key="de_DE" language="de" country="DE">
<resource name="de_DE.png" type="download"
location="templates/languages/de_DE/de_DE.png">
<property key="content-type" value="image/png"/>
</resource>
</language>
<language name="Spain" key="es_ES" language="es" country="ES">
<resource name="es_ES.png" type="download"
location="templates/languages/es_ES/es_ES.png">
<property key="content-type" value="image/png"/>
</resource>
</language>
<resource name="i18n" name="i18n_my_plugin" type="i18n" location="/my_plugin"/>
<!-- Important entry, because you have to add the default
i18n files to this new plugin -->
<resource name="i18n" name="i18n_default" type="i18n"
location="/ConfluenceActionSupport"/>
Diese Lösungsansatz beseitigt nicht nur Redundanzen, sondern bietet auch in Kombination mit Maven, eine Möglichkeit mehrere Varianten einer Pluginlösung textuell abzugrenzen.
Für diesen Fall kann man mittels Maven tricksen. Wichtig hierbei ist eine eindeutige Namenskonvention für die Unterteilung der properties vorzunehmen. Beispielsweise kann man die properties wie folgt namentlich abgrenzen:
Ist das geschehen, definiert man in der atlassian-plugin.xml des LanguagePool-Plugins folgende Zeilen:
<resource name="i18n" name="i18n_my_plugin_general" type="i18n"
location="/my_plugin"/>
<resource name="i18n" name="i18n_my_plugin_specific" type="i18n"
location="/my_plugin_${TYPE}"/>
Letztlich müssen im Eclipse zwei neue Maven Run-Configurations erstellt werden, die das entsprechende Goal (Bsp.: package, install oder atlassian-pdk:install) verwendet und im Environment-Tab die Variable TYPE auf typex oder auf typey setzt.
Mit einem Webinar (Registrieren) in der Reihe “Plugin of the Month” von Atlassian veröffentlichen wir am 18.2.2010 das Content Import Plugin 1.1.
Das Plugin unterstützt den Import verschiedenster Inhalte nach Confluence. Die Daten müssen in einem Austauschformat, das Confluence Datenstrukturen in XML abbildet, zur Verfügung gestellt werden. Das Austauschformat unterstützt fast alle Inhaltstypen von Confluence (Bereiche, Seiten, Blogeinträge, Kommentare und Anhänge) sowie die zugehörigen Metadaten (Ersteller, Bearbeiter, Schlagworte, Datum). So können ohne vertiefte Confluence Kenntnisse Daten aus verschiedensten Quellsystemen, wie Wikisystemen, Blogs, Foren, nach Confluence importiert werden. Weiterhin bietet Communardo einen Migrationsservice an, der den kompletten Export der Daten aus dem Quellsystem nach XML und den anschließenden Import umfasst.
Im Webinar (Registrieren) demonstrieren wir das Plugin, weitere Informationen stehen nach dem Release auch auf der Communardo Homepage und im Atlassian Plugin Exchange zur Verfügung.
Auch bei der Pluginentwicklung für Confluence kommt irgendwann der Zeitpunkt, an dem man sich mit komplexeren Abläufen bei der Persistierung von Daten beschäftigen muss. Um die Integrität dieser Daten sicherstellen zu können, ist man dann auf den Einsatz von Transactions angewiesen. Da Confluence das Spring Framework verwendet, bietet sich hierfür die Nutzung des TransactionTemplate an. Dieses ermöglicht es, wie in der Spring Dokumentation beschrieben, auf einfache Weise kritischen Code unter Verwendung eines Callbacks in eine Transaction zu verpacken. Dazu benötigt man jedoch noch einen PlatformTransactionManager. Dieser implementiert die Strategie für die Transaktionsbehandlung, die im Fall von Confluence auf Hibernate basiert. Auch hierzu können weitere Informationen und ein Codebeispiel auf den Seiten von Spring gefunden werden. Der PlatformTransactionManager ist als Bean im Application Context von Confluence vorhanden und kann über den ComponentContainer referenziert werden:
public PlatformTransactionManager getTransactionManager(){
return (PlatformTransactionManager) ComponentContainer.get("transactionManager");
}
Allerdings funktioniert dieses Codebeispiel nach einer Umstellung auf V2-Plugins nicht mehr. Der Grund: Da diese Plugins in OSGI-Bundles umgewandelt werden, welche eine andere Spring Version verwenden als die Kern-Applikation, kommt es bei der Referenzierung der transactionManager-Bean über den ComponentContainer zu einer ClassCastException.
Bei der Suche nach einer Lösung für dieses Problem bin ich über ein Ticket im Issue Tracker von Atlassian gestolpert, in dessen Kommentaren eine Alternative beschrieben wird: Abhilfe schafft die Verwendung der Shared Access Layer (SAL), einer einheitlichen Service-Schicht für alle Atlassian Anwendungen. Sie stellt neben verschieden anderen Services auch ein TransactionTemplate bereit, das für Confluence bereits den auf Hibernate basierenden PlatformTransactionManager gesetzt hat und auf folgende Weise referenziert werden kann.
Zunächst muss das Template als Komponente (Spring-Bean) im Plugin-Descriptor (atlassian-plugin.xml) importiert werden:
<component-import name="SAL Transaction Template" key="salTransactionTemplate">
<interface>com.atlassian.sal.api.transaction.TransactionTemplate</interface>
</component-import>
Dann kann man sich die Komponente per Spring Autowiring in fast alle Plugin Modultypen (z. B. Actions und Components ) injizieren lassen. Der Name der zu injizierenden Bean entspricht dem Key des component-import Elementes im Plugin-Descriptor (in diesem Beispiel also “salTransactionTemplate” ):
public void setSalTransactionTemplate(TransactionTemplate template){
this.transactionTemplate = template;
}
Nun kann das Template wie oben beschrieben verwendet werden.
Noch ein Hinweis: SAL wird erst ab Confluence 3.0 mit ausgeliefert. Für Confluence 2.10 muss man also eine andere Lösung finden.
<
Christoph Rauhut von T-Systems Multimedia Solutions gab mit seiner Präsentation zum Confluence Community Day insbesondere für Confluence Neulinge eine Übersicht zu Makros, mit denen Confluence für den Einsatz als Projektwiki optimiert werden kann. Einen Fokus legte er bei der Auswahl der präsentierten Makros auf die Kommunikation, Zusammenarbeit, Aufgabenverwaltung, sowie Inhaltserstellung und -strukturierung im Projekt.
Die Makros demonstrierte Christoph Rauhut live und damit sehr plastisch im Wiki für ein gedachtes „Projekt“ Confluence Community Day. Die Vortragsdokumentation enthält Screenshots der Macros in Aktion und den zugehörigen Macroaufruf.
Artikel vollständig lesen »
Communardo is submitting a Confluence plugin to this years Codegeist competition, powerded by Atlassian.
The Notify&Tag Plugin adds twitter-like functionality to Confluence. It allows to add labels to pages and news by using #hashtags. Additionally users can be notified about interesting content (pages, news and comments) by using the @username notation.
To create a label from a term in the content of a page or news item just precede it with “#” while writing the text. There is no need to provide it again in the according form field: Press “Save” and it will be added to the list of labels.
To notify a user about the page, news or comment you are creating, simply add his username to the text and put “@” in front of it. After saving he will recieve an email containing an excerpt and a link to content. This is a nice feature to attract the attention to relevant information, like the minutes of a missed meeting. You are not requiring to track the activity of the whole site using RSS feeds or the recently-updated macro. Thus, the danger of missing important information is reduced (provided emails are checked on a regular basis
).
The presentation below gives some additional information. For more exhaustive usage dokumentation you can visit the plugin homepage.
Needless to say, we are eager to get your feedback. So feel free to add a comment to this blog or any of the plugin pages and tell us about your opinion or the feature you are missing.
Die Confluence API bietet über das Bandana-Framework eine einfache Möglichkeit zum Speichern beliebiger Java Objekte an. Im Prinzip muss man zu dem Objekt nur einen einen Kontext (bezieht sich auf einen bestimmten Confluence Space oder ist global) und einen bezüglich dieses Kontextes eindeutigen Key angeben und der BandanaManager kümmert sich um den Rest. Der Vorteil liegt auf der Hand: Man muss sich nicht mit dem Persistenzmodell von Confluence (basiert auf Hibernate) auseinander setzen. Davon rät Atlassian ohnehin ab, Zitat:
Unless you really understand our code, something weird will happen.
Das Speichern von Daten über Bandana geschieht im Wesentlichen in zwei Schritten
Diese Form der Persistenz hat allerdings auch ihre Tücken. Als ich vor Kurzem bei der Entwicklung eines Plugins mal wieder Bandana verwendete bin ich über das folgende Verhalten gestolpert:
Ich hatte zwei Container-Datenstrukturen gespeichert, eine Map und eine List. Nachdem einige kurze Tests positiv verliefen, wendete ich mich einer anderen Komponente des Plugins zu. Um diese zu testen baute ich mein Plugin neu und installierte es über die Weboberfläche (ohne etwas an meiner “Persistenzschicht” zu ändern). Allerdings musste ich nun feststellen, dass eine der Datenstrukturen (die Map) nicht mehr geladen werden konnte. Ein weiterer Test offenbahrte noch wunderlicheres Verhalten: Nachdem ich die Map erneut gespeichert hatte, konnte ich sie wieder auslesen, allerdings nur bis zum nächsten Deploy des Plugins.
Was war passiert? An einem falschen Kontext oder Key konnte es nicht liegen, da diese bereits zuvor das Laden der Map verhindert hätten. Der Verdacht viel schnell auf irgendeinen Cache. Und tatsächlich, nach kurzer Recherche bin ich auf diese Seite bei Atlassian gestoßen. Dort wird beschrieben, dass es eigens für Bandana einen Cache gibt. Meine erste Vermutung war nun, dass die Map aus irgend einem Grund nie den Weg durch den Cache in die Datenbank geschafft hatte, der dann bei der Neuinstallation des Plugins verfiehl. Ein kurzer Blick in die Datenbank und ein wenig Debugging überzeugten mich dann aber vom Gegenteil: Die Daten waren in der Datenbank, schafften es von da aber nicht mehr in den Cache (kurzer Hinweis: die Tabelle für die Bandana-Daten heißt treffender Weise BANDANA). Nach weiterem Debugging stand fest, dass die Daten zwar noch aus der Datenbank geholt wurden, im Anschluss aber die Deserialisierung fehl schlug. Nach einem erneuten Blick in die Datenbank war schnell klar warum. Ich hatte Enums als Schlüssel für die Map verwendet. Diese waren fehlerhaft serialisiert wurden, so dass sie (und mit ihnen die Map) nicht wiederhergestellt werden konnten. Das liegt wohl daran, dass Confluence die XStream Version 1.1.1 verwendet aber Enums erst mit der Version 1.1.2 unterstützt werden. Da die Daten im Cache immer unserialisiert gespeichert werden, fiel dieses Problem erst auf, als der Cache verfallen war. Die Lösung war nun recht einfach: Nach dem Ersetzen der Enums durch Strings verhielt sich mein Plugin wie erwartet.
Enums sind nicht die einzigen Datenstrukturen, mit denen es Probleme gibt. So sollte man es auch vermeiden in einem Plugin definierte Typen mittels Bandana zu speichern, wenn diese keinen Default-Konstruktor haben. Der Grund: Diese Typen würden, wie in diesem Issue beschrieben, beim Deserialisieren mit dem ClassLoader der Web-Applikation gesucht werden. Der kann sie aber nur finden, wenn sie im Classpath der der Web-Applikation liegen, was bei über die Weboberfläche installierten Plugins nicht der Fall ist (dafür hat jedes Plugin seinen eigenen ClassLoader). Also dürften in diesem Fall ebenfalls die oben beschriebenen Probleme auftreten.
Häufig habe ich schon erlebt, dass Nutzer nach der Einführung von Confluence die Dokumentation bei Atlassian lesen, dabei viele neue Plugins entdecken und um die Installation der Plugins bitten. Administratoren sind dann oftmals unsicher, nach welchen Gesichtspunkten über die Installation der Plugins entschieden werden soll.
Auf der einen Seite erweitern Plugins die Funktionalität von Confluence und können damit die Benutzerakzeptanz steigern und eine effizientere Arbeit mit dem Wiki erlauben. Auf der anderen Seite können Plugins die Stabilität, Sicherheit und Performance eines Confluence-Systems entschieden beeinträchtigen. Mit Hilfe von Plugins können alle Teile des Wikis und sogar die Datenbank verändert werden.
Wie soll da über die Installation eines Plugins entschieden werden?
Die folgende Checkliste, unterteilt in Fragen zur fachlichen und zur technischen Bewertung, will Anhaltspunkte geben – wenn auch in die letztendliche Entscheidung über die Installation eine Plugins die Erfahrung des Administrators oder vielleicht das Knowhow eines Confluence-Consultants einfließen.
Fragen zur fachlichen Bewertung:
Fragen zur technischen Bewertung:
Fazit: Bei der Entscheidung zur Installation eines Plugins gilt der allgemeine Leitsatz
“So viel nötig, so wenig wie möglich” auch!
(das Nennen von Plugins in diesem Artikel enthält keinerlei Bewertung für die Auswahl des Plugins. Die genannten Plugins dienen nur als Beispiele, die die Fragen der Checkliste verdeutlichen sollen)
Bei der Entwicklung von Confluence Plugins kommt häufig die auf Java basierende Buildmanagement-Software Maven zum Einsatz. Ziel dabei ist es, die Entwickler vom Anlegen des Projektes bis hin zum Kompilieren und Testen zu unterstützen und möglichst viele Schritte des Softwaremanagements automatisiert ablaufen zu lassen. Ein Tutorial für die Entwicklung von Confluence Plugins mit Hilfe von Maven findet sich auf den Seiten der Confluence Community.
Wenn eine solche Entwicklungsumgebung eingerichtet wurde, kann der Buildprozess eines Plugins noch weiter vereinfacht werden. Dafür stellt Atlassian das Plugin Developer Kit for Maven2 (kurz PDK) zur Verfügung. Dabei handelt es sich um ein Maven-Plugin, welches einfach in der POM des eigenen Projektes eingebunden werden muss und dann automatisch beim Buildprozess heruntergeladen und installiert wird. Ein solcher Aufruf kann z.B. so aussehen:
<plugin>
<groupId>com.atlassian.maven.plugins</groupId>
<artifactId>atlassian-pdk</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>uninstall</goal>
<goal>install</goal>
<goal>rescan</goal>
</goals>
</execution>
</executions>
</plugin>
Dabei können verschiedene Goals angegeben werden, welche hintereinander ausgeführt werden und z.B. das Plugin direkt nach dem kompilieren in einem laufenden Confluence deinstallieren und die neue Version installieren. Eine sinnvolle Reihenfolge wäre z.B. Uninstall – Install – Rescan.
Vorsicht ist allerdings bei der Benutzung des Confluence Trigger Plugin Moduls geboten. Hat man einen Trigger in seiner atlassian-config.xml eingebunden und installiert das Plugin über das PDK direkt in ein laufendes Confluence, sollte nach einem Install kein explizites Enable des Plugins ausgeführt werden. Der Grund dafür ist: der Job wird bereits beim Install angelegt. Bei einem folgenden Enable wird dann erneut versucht, dieser Job anzulegen – was natürlich fehlschlägt und mit einer ObjectAlreadyExistsException quittiert wird. Ein Install und ggf. Rescan ist in diesem Fall also ausreichend.
Releaseparty at Atlassian? Confluence 3.2 BETA and 3.1.2 with soms bugfixes were released yesterday. [...]
Tino Schmidt's Vortrag zu Enterprise Mashups auf der webciety, 4.3 Remix the Web http://bit.ly/d26rtA [...]
neuer Blogpost: February Cumulative Update (2010) http://bit.ly/cwxZGE [...]
Webinar am 16.03.: „Communote Enterprise Microblogging - Funktionen und Einsatzbereiche im Unternehmen“ http://bit.ly/96eexF [...]