Hands-on-Confluence-Cloud-Apps mit Spring Boot und Atlassian Connect (Teil 1)

Über Atlassian Connect

Um Integrationen für die On-demand-Varianten der Atlassian-Software-Produkte – also Confluence Cloud, Jira Cloud & Co. – zu ermöglichen, steht Entwicklern mit Atlassian Connect ein Framework zur Verfügung, das ihnen dabei hilft, Add-ons in unterschiedlichen Programmiersprachen zu implementieren.

Ein Atlassian-Connect-Add-on ist dabei im Grunde eine Web-Anwendung, die über das HTTP-Protokoll angebunden wird und die folgenden drei Hauptaspekte abdeckt:

  • Inhalte in vordefinierte Integrationspunkte in die Benutzeroberfläche des Atlassian-Anwendung integrieren
  • Die RESTful Webservices der Atlassian-Anwendung adressieren und verwenden
  • Über Webhooks Informationen über Zustandsänderungen in der angebundenen Atlassian-Anwendung erhalten

(Hier finden sich weiterführende Informationen zu Atlassian Connect.)

Im folgenden kurzen Tutorial wollen wir auf diese Aspekte nun näher eingehen.

Was implementieren wir?

Unser Cloud-Plugin integriert sich in Confluence-Cloud-Instanzen, indem es ...

  • per Webhook auf das Erstellen neuer Confluence-Seiten lauscht und reagiert.
  • sich in das Hilfemenü mit einem Menüpunkt integriert (Teil 2).
  • eine Seite in Confluence darstellt, die in unserer Cloud-Anwendung generiert wird (Teil 2).
  • per REST-Client OAuth2-authentifizierte Abfragen an ein verbundenes Confluence-Cloud-System durchführt (Teil 2).

Atlassian-Cloud-Entwicklungsumgebung

Atlassian bietet für Entwickler kostenlose Cloud-Instanzen mit den folgenden Benutzer/Agent-Beschränkungen an:

  • Jira Core: fünf Benutzer kostenlos
  • Jira Software: fünf Benutzer kostenlos
  • Confluence: fünf Benutzer kostenlos
  • Jira Service Desk: ein Agent kostenlos

Hier gibt es weitere Informationen.

Nach Hause telefonieren mit ngrok

Das Werkzeug ngrok erlaubt es uns, Verbindungen von unserer lokalen Entwicklungsmaschine aus zu tunneln und im Netz bereitzustellen - ideal zum schnellen Testen von Webhooks und Cloud-Plugins.

Von der Website https://ngrok.com/ können wir für alle gängigen Betriebssysteme ein Kommandozeilen-Tool beziehen, um diese Tunnel aufzubauen.

Um beispielsweise eine lokale HTTP-Verbindung auf Port 8080 laufend bereitzustellen, genügt der folgende Befehl:

ngrok http 8080

Dabei erhalten wir eine Zufalls-ID zugewiesen, über die wir nun auf diese Verbindung zugreifen können:

Tunnel Status online 
Version 2.0.19/prod 
Web Interface http://127.0.0.1:4040 
Forwarding http://12345678.ngrok.io -> localhost:8080 
Forwarding https://12345678.ngrok.io -> localhost:8080 
 
Connections ttl opn rt1 rt5 p50 p90 
 0 0 0.00 0.00 0.00 0.00

Neues Projekt mit Maven-Archetype generieren

Mittels eines Maven-Archetypes kann schnell ein neues Spring-Boot-Projekt samt Atlassian-Bibliotheken generiert werden:

mvn archetype:generate -DarchetypeGroupId=com.atlassian.connect -DarchetypeArtifactId=atlassian-connect-spring-boot-archetype -DarchetypeVersion=1.3.5

Nach Eingabe der GroupID/ArtifactID und Version unserer zu implementierenden Anwendung steht uns ein fertiges Projekt zur weiteren Bearbeitung zur Verfügung:

.
|-- pom.xml
--- src
    --- main
        |-- java
        |   --- net
        |       --- seibertmedia
        |           --- cloud
        |               --- AddonApplication.java
        --- resources
            |-- application.yml
            --- atlassian-connect.json

Neben der klassischen Maven-Projektstruktur erhalten wir ebenfalls:

  • Plugin-Descriptor (atlassian-connect.json)
  • Atlassian-Libs: atlassian-connect-spring-boot-starter und atlassian-connect-spring-boot-jpa-starter (inkl. Spring Data JPA und Liquibase-Datenbankmigrationen)
  • Spring Boot Application-Klasse und Spring-Konfiguration im YAML Format

Anwendung starten

Wir starten unsere Anwendung nun einfach mittels Maven in der Kommandozeile:

mvn spring-boot:run

Im Anschluss können wir unsere Anwendung unter http://localhost:8080 aufrufen; wir werden dann auf den Plugin-Descriptor weitergeleitet.

Anwendung mit ngrok starten

Damit unsere Anwendung nun auch mit entsprechender Basis-URL über den ngrok-Tunnel im Netz laufen kann, ergänzen wir hier einen Startparameter mit der entsprechenden ngrok-URL:

mvn spring-boot:run -Drun.arguments="--addon.base-url=https://12345678.ngrok.io"

Unsere Anwendung sollte nun unter der HTTPS-Variante über ngrok verfügbar sein (https://ID.ngrok.io). HTTPS ist notwendig, da Atlassian zurecht keine Add-ons akzeptiert, die über unverschlüsselte HTTP-only-Verbindungen kommunizieren.

Installation des Confluence-Cloud-Add-ons

Zunächst müssen wir in unserer Confluence-Cloud-Instanz den Entwicklermodus für Add-ons aktivieren, damit wir ohne Marketplace von einer URL den Add-on-Descriptor installieren können.

Dazu gehen wir im Confluence-Administrationsbereich in die Add-on-Verwaltung und setzen unter den Einstellungen das Häkchen für den Entwicklermodus.

Im Anschluss daran können wir unser Add-on über die Angabe unserer ngrok-URL installieren, wie der folgende Screenshot zeigt:

Installation des Cloud-Addons

Installation des Cloud-Add-ons

Danach signalisiert eine Erfolgsmeldung die erfolgreiche Integration unseres Add-ons. Diesen Schritt müssen wir künftig nur wiederholen, falls sich unsere URL geändert hat oder wir einen veränderten Plugin-Descriptor (beispielsweise mit Webhooks oder erweiterten Scopes) ausliefern.

Cloud Addon erfolgreich installiert

Cloud Add-on erfolgreich installiert

Mit Webhooks Systemveränderungen überwachen

Wir wollen nun per Webhook-API benachrichtigt werden, wenn in der Confluence-Cloud-Instanz neue Seiten erstellt werden.

Dazu ergänzen wir zunächst den folgenden Eintrag in unserem Deployment-Descriptor:

"modules": {
	"webhooks": [
	  {
		"event": "page_created",
		"url": "/pages/created"
	  }
]

Wird in Confluence Cloud eine neue Seite erstellt, ruft Confluence die definierte Adresse auf unserer Cloud-Anwendung auf und liefert Informationen zu diesem System-Event im JSON-Format.

Wir definieren folgendes POJO, in dem wir diese Informationen sammeln wollen:

public class PageCreatedEvent {

  private Page page;
  private String user;
  private String userKey;
  private String timestamp;
  private String userName;

  // getter, setter, toString ommitted
}

Wir ergänzen für die Confluence-Seiteninformationen noch ein POJO namens Page:

public class Page {

  private String spaceKey;
  private String modificationDate;
  private String creatorKey;
  private String creatorName;
  private Long id;
  private String title;
  private Long version;

  // getter, setter, tostring ommitted
}

Der folgende Endpunkt nimmt nun unter der definierten Adresse die Informationen entgegen und schreibt sie in die Log-Dateien:

@RestController
public class WebhookListenerResource {
  [..]
  
  @RequestMapping(name = "/pages/create", method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE)
  public void onPageCreate(@RequestBody PageCreatedEvent dto,
      @AuthenticationPrincipal AtlassianHostUser hostUser) {
    log.info("user on host {} with key {} created page: {}", hostUser.getHost().getBaseUrl(),
        hostUser.getUserKey(), dto);

  }
}

Weiterführende Dokumentationen

Ausblick: Teil 2

Im zweiten Teil werden wir dann die Integration der GUI von Confluence Cloud und die Darstellung Server-seitig gerenderter Inhalte in Confluence implementieren.


Mehr über die Creative-Commons-Lizenz erfahren