AtlasCamp 2015: Connect everywhere - Cloud and Server

43
Connect Add-ons for Cloud & Server PATRICK STREULE ARCHITECT ATLASSIAN @PSTREULE

Transcript of AtlasCamp 2015: Connect everywhere - Cloud and Server

Page 1: AtlasCamp 2015: Connect everywhere - Cloud and Server

Connect Add-ons for Cloud & Server

PATRICK STREULE • ARCHITECT • ATLASSIAN • @PSTREULE

Page 2: AtlasCamp 2015: Connect everywhere - Cloud and Server
Page 3: AtlasCamp 2015: Connect everywhere - Cloud and Server

Connect

Page 4: AtlasCamp 2015: Connect everywhere - Cloud and Server
Page 5: AtlasCamp 2015: Connect everywhere - Cloud and Server

Overview

Page 6: AtlasCamp 2015: Connect everywhere - Cloud and Server

Cloud

Browser

Product – Cloud Add-On Service

Connect Plugin

Connect JS

Add-On UIAdd-On JS

AssetsAPI

Page 7: AtlasCamp 2015: Connect everywhere - Cloud and Server

Browser

Product – Cloud Add-On Service

Connect Plugin

Connect JS

Add-On UIAdd-On JS

AssetsAPI

Cloud Create iFrame, XDM bridge

Page 8: AtlasCamp 2015: Connect everywhere - Cloud and Server

Browser

Product – Cloud Add-On Service

Connect Plugin

Connect JS

Add-On UIAdd-On JS

AssetsAPI

CloudExpose

Host API

Page 9: AtlasCamp 2015: Connect everywhere - Cloud and Server

Browser

Product – Cloud Add-On Service

Connect Plugin

Connect JS

Add-On UIAdd-On JS

AssetsAPI

CloudLifecycle, Webhooks

Page 10: AtlasCamp 2015: Connect everywhere - Cloud and Server

Browser

Product – Cloud Add-On Service

Connect Plugin

Connect JS

Add-On UIAdd-On JS

AssetsAPI

Cloud

REST API

Page 11: AtlasCamp 2015: Connect everywhere - Cloud and Server

Browser

Product – Cloud Add-On Service

Connect Plugin

Connect JS

Add-On UIAdd-On JS

AssetsAPI

REST API Bridge

Cloud

Page 12: AtlasCamp 2015: Connect everywhere - Cloud and Server

Now in Server

Page 13: AtlasCamp 2015: Connect everywhere - Cloud and Server

Server

Product – Server v1Product – Server v2

Browser

Add-On Service

?

Add-On UIAdd-On JS

AssetsAPI

Product – Server v3

?

Page 14: AtlasCamp 2015: Connect everywhere - Cloud and Server

Server

Product – Server v1Product – Server v2

Browser

Add-On Service

?

Add-On UIAdd-On JS

AssetsAPI

Product – Server v3

?

iFrame setup? XDM?

API Version?

Page 15: AtlasCamp 2015: Connect everywhere - Cloud and Server

Server

Product – Server v1Product – Server v2

Browser

Add-On Service

?

Add-On UIAdd-On JS

AssetsAPI

Product – Server v3

?

Auth?Privacy?

Connectivity?

Page 16: AtlasCamp 2015: Connect everywhere - Cloud and Server

Server

Product – Server v1Product – Server v2

Browser

Add-On Service

?

Add-On UIAdd-On JS

AssetsAPI

Product – Server v3

?

Connectivity? API Version?

Auth?

Page 17: AtlasCamp 2015: Connect everywhere - Cloud and Server

Example Sequence Diagram Add-On

Page 18: AtlasCamp 2015: Connect everywhere - Cloud and Server
Page 19: AtlasCamp 2015: Connect everywhere - Cloud and Server

• Purely client-side• No server-side rendering• Javascript & SVG

• No data stored by the add-on• Uses macro body for storage• Uses REST API to fetch the macro

body• However: The Connect version

stores the installation payload

Browser

Product – Cloud Add-On Service

Connect Plugin

Connect JSAdd-On UI

Add-On JS

Assets

Design Choices

Con

nect

P2

Browser

Product – ServerP2 Plugin

Add-On UIAdd-On JS

Assets

Connect JS Shim

Page 20: AtlasCamp 2015: Connect everywhere - Cloud and Server

Show me code

Page 21: AtlasCamp 2015: Connect everywhere - Cloud and Server

Plugin XML <web-resource key="sequence-diagram-resources" name="sequence-diagram Web Resources"> <resource type="download" name="blueprint.css" location="/css/blueprint.css"/> <resource type="download" name="confluence.css" location="/css/confluence.css"/> <resource type="download" name="napkin.css" location="/css/napkin.css"/> <resource type="download" name="plain.css" location="/css/plain.css"/> <resource type="download" name="sequence-diagrams.js" location="/js/sequence-diagrams.743cf0e5.js"/> <resource type="download" name="connect-api.js" location="/js/connect-api.js"/> <resource type="download" name="addon.js" location="/js/addon.js"/> </web-resource>

<servlet name="Diagram IFrame Servlet" key="sequence-diagram-servlet" class="com.pstreule.SequenceDiagramIFrame"> <url-pattern>/sequence-diagram</url-pattern> </servlet>

<xhtml-macro name="sequence-diagram" class="com.pstreule.SequenceDiagramMacro" key="sequence-diagram-macro"> <parameters> <parameter name="theme" type="enum" required="true"> <value name="Confluence"/> <value name="Blueprint"/> <value name="Napkin"/> <value name="Plain"/> </parameter> <parameter name="width" type="string"/> </parameters> </xhtml-macro>

Page 22: AtlasCamp 2015: Connect everywhere - Cloud and Server

Render the iFrame public SequenceDiagramMacro(TemplateRenderer renderer, ApplicationProperties applicationProperties) { this.renderer = renderer; this.applicationProperties = applicationProperties; }

@Override public String execute(Map<String, String> parameters, String storageFormatBody, ConversionContext conversionContext)

throws MacroExecutionException { ContentEntityObject entity = conversionContext.getEntity(); String baseUrl = applicationProperties.getBaseUrl();

URI uri = UriBuilder.fromPath(baseUrl + "/plugins/servlet/sequence-diagram") .queryParam("pid", entity.getIdAsString()) .queryParam("pv", entity.getVersion()) .queryParam("mh", DigestUtils.md5Hex(storageFormatBody)) .queryParam("theme", parameters.get("theme")) .build();

Map<String, Object> context = new HashMap<>(); context.put("url", uri.toString()); context.put("name", "preview".equals(conversionContext.getOutputType()) ? storageFormatBody : "");

return render("/templates/iframe.vm", context); }

<iframe src="$url" name="$name" frameborder="0" rel="nofollow" scrolling="no"></iframe>

Page 23: AtlasCamp 2015: Connect everywhere - Cloud and Server

Render the iFrame Contentpublic class SequenceDiagramIFrame extends HttpServlet { private final TemplateRenderer renderer; private final PageBuilderService pageBuilderService;

public SequenceDiagramIFrame(TemplateRenderer renderer, PageBuilderService pageBuilderService) { this.renderer = renderer; this.pageBuilderService = pageBuilderService; }

@Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { resp.setStatus(HttpServletResponse.SC_OK); resp.setContentType("text/html");

StringWriter writer = new StringWriter(); WebResourceAssembler assembler = pageBuilderService.assembler(); assembler.assembled().drainIncludedResources(); assembler.resources().requireWebResource("com.pstreule.sequence-diagram:sequence-diagram-resources"); WebResourceSet set = assembler.assembled().drainIncludedResources(); set.writeHtmlTags(writer, UrlMode.RELATIVE);

renderer.render("/templates/sequence-diagram.vm", Collections.singletonMap("resourcesWithHtml", writer.toString()), resp.getWriter()); } }

<html> <head> $resourcesWithHtml </head> <body> <div id="sequence-diagram"></div> <script type="application/javascript"> renderSequenceDiagram("sequence-diagram", window.name) </script> </body> </html>

Page 24: AtlasCamp 2015: Connect everywhere - Cloud and Server

Add-On JavaScript Codefunction renderSequenceDiagram(id, previewMacroBody) { function render(diagramCode) { function onRenderSuccess(dimensions) { AP.resize(dimensions.w + 10, dimensions.h + 10); } var themeName = Loader.getUrlParameter("theme"); var theme = SequenceDiagramThemes.byName(themeName); var controller = new SequenceDiagramController(id); controller.renderSequenceDiagram(diagramCode, theme, null, onRenderSuccess, onRenderError); }

function loadMacroAndRender() { function onLoadSuccess(responseBody) { var diagramCode = JSON.parse(responseBody).body; render(diagramCode); } AP.require(['request'], function (request) { var pageId = Loader.getUrlParameter("pid"); var pageVersion = Loader.getUrlParameter("pv"); var macroHash = Loader.getUrlParameter("mh"); request({ url: "/rest/api/content/" + pageId + "/history/" + pageVersion + "/macro/hash/" + macroHash, success: onLoadSuccess }); }); } loadMacroAndRender(); }

Page 25: AtlasCamp 2015: Connect everywhere - Cloud and Server

Connect JS Shimvar AP = {}; (function (AP) {

var AJS = window.parent.AJS; var $ = AJS.$;

_modules = { 'request': function (url, args) { … $.ajax({ url: url, … }).then(done, fail); } };

AP.require = function (modules, callback) { var requiredModules = Array.isArray(modules) ? modules : [modules]; var args = requiredModules.map(function (module) { return _modules[module]; }); callback.apply(window, args); };

AP.resize = function (width, height) { AJS.$(window.frameElement).css({width: width, height: height}); };

})(AP);

Page 26: AtlasCamp 2015: Connect everywhere - Cloud and Server

Best Practices

Page 27: AtlasCamp 2015: Connect everywhere - Cloud and Server

Make it Self-Contained

Page 28: AtlasCamp 2015: Connect everywhere - Cloud and Server

Run in Process

Browser

Product – ServerP2 Plugin

Add-On UIAdd-On JS

AssetsAPI

Connect JS Shim

Adapter

Page 29: AtlasCamp 2015: Connect everywhere - Cloud and Server

Run in Process

Browser

Product – ServerP2 Plugin

Add-On UIAdd-On JS

AssetsAPI

Connect JS Shim

Adapter

No cross-domain bridge needed

Page 30: AtlasCamp 2015: Connect everywhere - Cloud and Server

Run in Process

Browser

Product – ServerP2 Plugin

Add-On UIAdd-On JS

AssetsAPI

Connect JS Shim

AdapterEvent Handling, Storage

Page 31: AtlasCamp 2015: Connect everywhere - Cloud and Server

Run in Process

Browser

Product – ServerP2 Plugin

Add-On UIAdd-On JS

AssetsAPI

Connect JS Shim

Adapter

100% Reusable

100% Reusable

Page 32: AtlasCamp 2015: Connect everywhere - Cloud and Server

Run in Process

Browser

Product – ServerP2 Plugin

Add-On UIAdd-On JS

AssetsAPI

Connect JS Shim

Adapter

100% reusable (maybe)

Page 33: AtlasCamp 2015: Connect everywhere - Cloud and Server

Use Client-Side Rendering as much

as Possible

Page 34: AtlasCamp 2015: Connect everywhere - Cloud and Server

Shrink the server-side

Browser

Product – ServerP2 Plugin

Add-On UIAdd-On JS

AssetsAPI

Connect JS Shim

Page 35: AtlasCamp 2015: Connect everywhere - Cloud and Server

Use In-Product Data Storage

Page 36: AtlasCamp 2015: Connect everywhere - Cloud and Server

Use Entity Properties for Data Storage

POST /rest/api/content/{content_ID}/property Content-Type: application/json

{ "key" : "attachment", "value" : { "size": 234374, "description": "My description" ... } }

GET /rest/api/content/{content_ID}/propertyGET /rest/api/2/issue/{key}/properties/

PUT /rest/api/2/issue/{key}/properties/attachment Content-Type: application/json

{ "size": 234374, "description": "My description" ... }

Page 37: AtlasCamp 2015: Connect everywhere - Cloud and Server

Use Entity Properties for Data Storage{ "jiraEntityProperties": [ { "keyConfigurations": [ { "propertyKey": "attachment", "extractions": [ { "objectName": "attachment.size", "type": "number", "alias": "attachmentSize" } ] } ], "entityType": "issue", "name": { "value": "Attachment Index Document" } } ] }

{ "confluenceContentProperties": [ { "keyConfigurations": [ { "propertyKey": "attachment", "extractions": [ { "objectName": "attachment.size", "type": "number" } ] } ], "name": { "value": "Attachment Index Document" } } ] }

Page 38: AtlasCamp 2015: Connect everywhere - Cloud and Server

Use client-side REST Calls

// Get the content properties of an issue AP.require(['request'], function(request){ request({ url: '/rest/api/2/issue/' + issueKey + '/properties/', success: function(responseText){ var properties = JSON.parse(responseText); … } }); });

Page 39: AtlasCamp 2015: Connect everywhere - Cloud and Server

Expose REST API for Server-Side

Logic

Page 40: AtlasCamp 2015: Connect everywhere - Cloud and Server

JAX-RS/Jersey

@Path("my-resource") public class MyResource { @GET @Produces("application/json") public Response getSomething(@Context HttpServletRequest request) { // ... return Response.ok(); } }

Page 41: AtlasCamp 2015: Connect everywhere - Cloud and Server

Tools**currently in planning

Page 42: AtlasCamp 2015: Connect everywhere - Cloud and Server

Thank you!

PATRICK STREULE • ARCHITECT • ATLASSIAN • @PSTREULE

Page 43: AtlasCamp 2015: Connect everywhere - Cloud and Server

Connect everywhere - Cloud and Server

Submit your feedback: go.atlassian.com/acconnectcloud