Probleme
Keine konfigurierbaren Module
Standardmäßig gibt es für Atlassian Crowd keine Möglichkeit Scheduler, Jobs oder Trigger Module über die Konfigurationsdatei atlassian-plugin.xml zu definieren.
In Atlassian Confluence können Jobs und die zugehörigen Trigger bequem über die atlassian-plugin.xml konfiguriert werden. siehe http://confluence.atlassian.com/display/CONFDEV/Job+Module und http://confluence.atlassian.com/display/CONFDEV/Trigger+Module |
Crowd Scheduler in Plugins nicht verfügbar
Atlassian Crowd verwendet einen Scheduler, welcher die Jobs TokenRepeaterJob und LicenseResourceJob verwaltet. Generell besteht die Möglichkeit Komponenten in der Datei atlassian-plugin.xml mittels component-import zu importieren. Dies ist allerdings nur möglich, wenn die Komponenten in Spring mit dem Attribut
plugin:available=<span>"<span>true</span>"</span>
versehen ist. Der Scheduler besitzt leider dieses Attribut nicht, sodass die Verwendung innerhalb eines Plugins nicht möglich ist.
Lösung
Zusammenfassung
Die Nutzung des ServiceAccessLayers, kurz SAL, ermöglicht es Jobs und Trigger zu implementieren. Die Entwickler von Atlassian stellen dafür eine Bibliothek sal-api-X.X.X.jar zur verfügung.
Schritt für Schritt
Die folgenden Schritte erläutern das Implementieren von Jobs und Triggern.
zusätzliche Dependency
Damit das Plugin die SAL-Klassen nutzen kann muss die Bibliothek als Abhängigkeit in die pom.xml ergänzt werden.
<dependency> <groupId>com.atlassian.sal</groupId> <artifactId>sal-api</artifactId> <version>2.0.17</version> <scope>provided</scope> </dependency>
Definition des Schedulers
Damit die Jobs auch nach den definierten Trigger-Zeiten ausgeführt werden, muss ein Scheduler verwendet werden. Diesen kann leicht in der atlassian-plugin.xml konfiguriert werden.
<component-<span>import</span> key=<span>"pluginScheduler"</span>> <description>SAL Scheduler</description> <<span>interface</span>>com.atlassian.sal.api.scheduling.PluginScheduler</<span>interface</span>> </component-<span>import</span>>
Job erstellen
Die neue Job-Klasse muss das Interface com.atlassian.sal.api.scheduling.PluginJob implementieren.
<span>public</span> class MyJob <span>implements</span> PluginJob { <span>public</span> void execute(Map<<span>String</span>, <span>Object</span>> jobDataMap) { TransactionTemplate tt = (TransactionTemplate) jobDataMap.get(<span>"transactionTemplate"</span>); tt.execute(<span>new</span> TransactionCallback() { <span>public</span> <span>Object</span> doInTransaction() { perform(); <span>return</span> 0; } }); } <span>protected</span> void perform() { } }
Innerhalb der Methode execute muss die Logik des Jobs definiert sein. Sollte es notwendig sein, dass Manager verwendet werden, die transaktionssichere Aufrufe beinhalten (wie z.B. Datenbank-Zugriffe via Hibernate), muss die Logik innerhalb der execute Methode der TransactionTemplate-Instanz liegen. (siehe obriges Code-Beispiele)
Manager Implementierung für Job-Registrierung
Als nächtes muss der Job für den Scheduler registriert werden, sodass er je nach Definition zyklisch ausgeführt werden kann. Dies wird durch eine neue Service-Klasse (oder Manager-Klasse) übernommen.
<span>public</span> class MyService <span>implements</span> IMyService, LifecycleAware { <span>private</span> <span>static</span> <span>final</span> Logger LOG = Logger.getLogger(MyService.class); <span>private</span> <span>static</span> <span>final</span> <span>String</span> JOB_NAME = MyTrigger.class.getName() + <span>":job"</span>; <span>// 24h in mili-seconds </span> <span>private</span> <span>static</span> <span>final</span> <span>long</span> INTERVAL = 86400000L; <span>private</span> PluginScheduler pluginScheduler; <span>// provided by SAL </span> <span>private</span> TransactionTemplate transactionTemplate; <span>// use a constructor <span>for</span> injection </span> <span>public</span> PasswordReminderTrigger(PluginScheduler pluginScheduler, TransactionTemplate transactionTemplate) { <span>this</span>.pluginScheduler = pluginScheduler; <span>this</span>.transactionTemplate = transactionTemplate; } <span>public</span> void onStart() { reschedule(INTERVAL); } @SuppressWarnings(<span>"serial"</span>) <span>public</span> void reschedule(<span>long</span> interval) { ... } }
Zusätzlich sind noch folgende Anpassungen in der atlassian-plugin.xml zu treffen.
<component key=<span>"schedulerComponent"</span> class=<span>"my.path.plugins.myproject.services.MyService"</span> system=<span>"<span>true</span>"</span> <span>public</span>=<span>"<span>true</span>"</span>> <<span>interface</span>>com.atlassian.sal.api.lifecycle.LifecycleAware</<span>interface</span>> <<span>interface</span>>my.path.plugins.myproject.services.IMyService</<span>interface</span>> </component>
Wichtig Das Interface LifecycleAware sorgt dafür, dass bei der Registrierung der Service-Klasse der Job im Scheduler registriert wird. |
Info Das Interface definiert lediglich die reschedule-Methode. <span>public</span> <span>interface</span> IMyService { <span>public</span> void reschedule(<span>long</span> interval); } |
Registrieren des Jobs für den Schedulers
In der Methode reschedule muss der folgende Quellcode eingetragen und an die eigenen Bedürfnisse angepasst werden.
pluginScheduler.scheduleJob(JOB_NAME, MyJob.class, <span>new</span> HashMap<<span>String</span>, <span>Object</span>>() { { put(<span>"transactionTemplate"</span>, transactionTemplate); ... } }, startDate, interval );
Der HashMap Parameter dient als Übergabeparameter für die execute-Methode des Jobs. Das startDate muss als java.util.Date festgelegt werden. Des Weiteren ist der Interval in Millisekunden anzugeben.
TransactionTemplate
Innerhalb eines Jobs ist es leider nicht möglich transaktionssichere Funktionen, wie Hibernate Zugriffe auszuführen. Es gibt allerdings einen Mechanismus, mit dem es trotzdem möglich. Zu diesem Zweck wird die Klasse TransactionTemplate verwendet.
Damit die Spring Injection auch hier greifen kann, muss das TransactionTemplate in der atlassian-plugin.xml konfiguriert werden.
<component-<span>import</span> name=<span>"SAL Transaction Template"</span> key=<span>"transactionTemplate"</span>> <<span>interface</span>>com.atlassian.sal.api.transaction.TransactionTemplate</<span>interface</span>> </component-<span>import</span>>
The post Jobs und Trigger in Crowd verwenden appeared first on Communardo Techblog.