AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen
-
Upload
atlassian -
Category
Technology
-
view
3.205 -
download
3
Transcript of AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen
![Page 1: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/1.jpg)
Understanding the Atlassian Platform
Tim Pettersen, Atlassian
![Page 2: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/2.jpg)
![Page 3: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/3.jpg)
AtlassianPluginDevelopmentPlatform
Targeted at You!FeaturesDedicated TeamDocumentationFocus on Backwards Compatibility
![Page 4: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/4.jpg)
Overview...
![Page 5: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/5.jpg)
Atlassian
Plugin
DEMO
src - http://bit.ly/hovers-svn
![Page 6: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/6.jpg)
Have you ever?
... needed to communicate with a remote application?
... wanted an easy way to provide JSON data for an AJAXy UI?
... wanted to expose your plugin's data via web services?
![Page 7: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/7.jpg)
REST Atlassian
Plugin
![Page 8: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/8.jpg)
Depending on REST ...
<dependency> <groupId>com.atlassian.plugins.rest</groupId> <artifactId>atlassian-rest-common</artifactId> <version>${rest.version}</version> <scope>provided</scope></dependency><dependency> <groupId>com.atlassian.plugins.rest</groupId> <artifactId>atlassian-rest-module</artifactId> <version>${rest.version}</version> <scope>provided</scope></dependency><dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> <version>2.1</version> <scope>provided</scope></dependency>
Atlassian annotations & utilities
JAX-RS annotations & jersey
JAXB annotations
![Page 9: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/9.jpg)
Quick departure - versioning
Easy - Dependency Management POM
Custom - Specify versions per module
more info: http://bit.ly/platform-versions
![Page 10: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/10.jpg)
Depending on REST ...
<atlassian-plugin>
<rest key="some-key" path="/some-path" version="1.0" description="Initialise REST resources for my plugin" />
<component-import key="restUrlBuilder" interface="com.atlassian.plugins.rest.common.util.RestUrlBuilder" />
</atlassian-plugin>
http://jira.atlassian.com/REST/some-path/1.0/
![Page 11: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/11.jpg)
Using REST ... creating a resource
@Path("/hello/")@Consumes(APPLICATION_XML, APPLICATION_JSON)@Produces(APPLICATION_XML, APPLICATION_JSON)public class MyResource {
@Path("/my-name-is/{name}") @GET @AnonymousAllowed public Response hello(@PathParam("name") String name) { return ok( new MessageEntity("Hello, " + name + "!") ); }}
http://.../REST/some-path/1.0/hello
http://.../REST/some-path/1.0/hello/my-name-is/tim
![Page 12: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/12.jpg)
Using REST ... creating an entity
@XmlAccessorType(FIELD)@XmlRootElement(name = "message")public class MessageEntity { private String body; public MessageEntity(String body) { this.body = body; }}
http://.../REST/some-path/1.0/hello/my-name-is/Tim.xml<message> <body>Hello, Tim!</body></message>
http://.../REST/some-path/1.0/hello/my-name-is/Tim.json{body:"Hello, world!"}
Poster: http://bit.ly/poster-ff
![Page 13: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/13.jpg)
Using REST ... generating a resource URL
public class MyClient {
public void doGet() { String baseUrl = "http://jira.atlassian.com"; String restUrl = restUrlBuilder .getUrlFor(baseUrl, MyResource.class) .hello("Tim") .toString(); ... }}
// generated restUrl = "http://.../REST/some-path/1.0/hello/my-name-is/Tim"
![Page 14: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/14.jpg)
Using REST ... unmarshalling an entity Request request = requestFactory .createRequest(MethodType.GET, restUrl);
request.execute(new ResponseHandler<Response>() { public void handle(Response response) { if (response.isSuccessful()) {
} } });
// unmarshall the entityMessageEntity m = response.getEntity(MessageEntity.class);
![Page 15: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/15.jpg)
Using REST ... marshalling an entity
Request request = requestFactory.createRequest(PUT, restUrl); MessageEntity entity = new MessageEntity("some-value"); request.setEntity(entity); request.execute();
@PUT public Response submit(MessageEntity message) { System.out.println("Received: " + message.getBody()); }
Client
Server
![Page 16: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/16.jpg)
![Page 17: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/17.jpg)
Have you ever?
... wanted to launch a modal dialog from your plugin?
... wanted to add rich tooltips to your content?
... wished someone else would write your CSS and javascript for you?
... wanted your plugin to look and behave a little bit more like the host application?
![Page 18: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/18.jpg)
User Interface Atlassian
Plugin
![Page 19: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/19.jpg)
Depending on AUI ...
public class MyServlet extends HttpServlet { public void doGet() { webResourceManager .requireResource("com.atlassian.auiplugin:ajs"); } }
<html> <head> #webResourceManager.getRequiredResources() </head> <body ... /></html>
![Page 20: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/20.jpg)
Depending on AUI ...
<atlassian-plugin> <web-resource key="some-web-resource"> <resource name="my-script.js" ... /> <resource name="my-styles.css" ... /> <dependency>com.atlassian.auiplugin:ajs</dependency> </web-resource></atlassian-plugin>
public class MyServlet extends HttpServlet { public void doGet() { webResourceManager .requireResource("com.my.plugin:some-web-resource"); } }
![Page 21: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/21.jpg)
Using AUI ... dropdowns
![Page 22: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/22.jpg)
Using AUI ... dropdowns
<script type="text/javascript"> // create drop-down AJS.$("#my-dropdown") .dropDown("standard", {alignment: "right"});</script>
<!-- the list to display as a dropdown --><ul id="my-dropdown"> <li class="paper-clip">Item One</li> <li class="clock">Item Two</li> <li class="envelope">Item Three</li> </ul>
![Page 23: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/23.jpg)
Using AUI ... tooltips
![Page 24: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/24.jpg)
Using AUI ... tooltips
<script type="text/javascript"> // assign URL for retrieving AJAX content var contentUrl = AJS.params.baseUrl + "/rest/myplugin/1.0/tooltip"; // bind hovers to DOM elements AJS.InlineDialog(".tooltip-link", "tooltip", contentUrl, { onHover: true, width: 300, cacheContent: true });</script>
<!-- an anchor that the tooltip will be applied to --><a class='.hover-link'>Hover over me!</a>
![Page 25: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/25.jpg)
Using AUI ... more!
![Page 26: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/26.jpg)
![Page 27: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/27.jpg)
Have you ever?
... wanted to include a piece of javascript or CSS on every page in Confluence?
... wanted to make your plugin, pluggable?
... wanted to build a single plugin that can be deployed in multiple applications?
![Page 28: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/28.jpg)
Plugins Framework Atlassian
![Page 29: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/29.jpg)
Depending on plugins ...
<dependency> <groupId>com.atlassian.plugins</groupId> <artifactId>atlassian-plugins-webresource</artifactId> <version>${atlassian.plugins.version}</version> <scope>provided</scope></dependency>
<dependency> <groupId>com.atlassian.plugins</groupId> <artifactId>atlassian-plugins-core</artifactId> <version>${atlassian.plugins.version}</version> <scope>provided</scope></dependency>
<atlassian-plugin> <!-- Unnecessary! --> <component-import ... /></atlassian-plugin>
![Page 30: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/30.jpg)
Using plugins ... web-resource contexts
<atlassian-plugin> <web-resource key="some-web-resource"> <context>atl.general</context> <resource name="my-script.js" ... /> <resource name="my-styles.css" ... /> </web-resource></atlassian-plugin>
atl.general
atl.admin
atl.userprofile
![Page 31: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/31.jpg)
Custom Plugin Modules
![Page 32: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/32.jpg)
Using plugins ... custom module types
public class MyDescriptor extends AbstractModuleDescriptor<MyModule> {
public void init(Plugin plugin, Element element);
public MyModule getModule() { // initialize the module specified by the descriptor's class attribute return moduleFactory.createModule(moduleClassName, this); }
}<atlassian-plugin> <module-type key="my-descriptor" class="com.myplugin.MyDescriptor" /> <my-descriptor class="com.myplugin.ModuleOne" /> <my-descriptor class="com.myplugin.ModuleTwo" />
</atlassian-plugin>
![Page 33: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/33.jpg)
Using plugins ... custom module types
public class MyService {
private PluginAccessor pluginAccessor;
public MyService(PluginAccessor pluginAccessor) { this.pluginAccessor = pluginAccessor; } public void executeInstalledModules() { for (MyModule module : pluginAccessor.getEnabledModulesByClass(MyModule.class)) { module.execute(); } }
}
![Page 34: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/34.jpg)
Using plugins ... descriptor application scopes<atlassian-plugin>
<web-resource key="some-web-resource" application="confluence"> <context>atl.general</context> <resource name="page-integration.js" ... /> </web-resource> <web-resource key="some-web-resource" application="jira"> <context>atl.general</context> <resource name="issue-integration.js" ... /> </web-resource>
<!-- depends on Confluence's API --> <component key="some-component" application="confluence" class="com.myplugin.PageHandler" /> <!-- depends on JIRA's API --> <component key="some-component" application="jira" class="com.myplugin.IssueHandler" /> </atlassian-plugin>
![Page 35: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/35.jpg)
![Page 36: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/36.jpg)
![Page 37: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/37.jpg)
![Page 38: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/38.jpg)
![Page 39: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/39.jpg)
Have you ever?
... needed to render HTML outside of a JIRA or Confluence action?
... needed to pass back rendered HTML to use in an AJAX UI?
... wished you could use something a little more modern than Velocity 1.4 in JIRA?
![Page 40: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/40.jpg)
Template Renderer Atlassian
![Page 41: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/41.jpg)
Depending on ATR ...
<dependency> <groupId>com.atlassian.templaterenderer</groupId> <artifactId>atlassian-template-renderer-api</artifactId> <version>${template.renderer.version}</version> <scope>provided</scope></dependency>
<atlassian-plugin> <component-import key="templateRenderer" interface="com.atlassian.templaterenderer.TemplateRenderer" /></atlassian-plugin>
![Page 42: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/42.jpg)
Using ATR ...
public class MyServlet extends HttpServlet {
private TemplateRenderer templateRenderer; // constructor-injected
public void doGet(HttpServletRequest req, HttpServletResponse resp) { Map<String, Object> context = createContext(); templateRenderer.render("templates/view.vm", context, resp.getWriter() ); } }
![Page 43: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/43.jpg)
![Page 44: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/44.jpg)
Have you ever?
... needed to persist some simple data for your plugin?
... wanted to i18n your plugin?
... needed to write an upgrade task?
... wanted to schedule a recurring job?
![Page 45: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/45.jpg)
Shared Application Layer Atlassian
Plugin
![Page 46: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/46.jpg)
Depending on SAL ...
<dependency> <groupId>com.atlassian.sal</groupId> <artifactId>sal-api</artifactId> <version>${sal.version}</version> <scope>provided</scope></dependency>
![Page 47: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/47.jpg)
Depending on SAL ...
<atlassian-plugin>
<component-import key="[someSalComponent]" interface="com.atlassian.sal.api.[someSalComponent]" />
</atlassian-plugin>
AuthenticationControllerLoginUriProviderComponentLocatorI18nResolverLocaleResolverRequestFactorySearchProvider
PluginUpgradeManagerUserManagerApplicationPropertiesPluginSettingsFactoryProjectManagerPluginSchedulerMore!
![Page 48: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/48.jpg)
Using SAL ... upgrade tasks
public interface PluginUpgradeTask { int getNumber(); String getShortDescription(); Collection<Message> doUpgrade(); String getPluginKey();}
<atlassian-plugin> <component key="my-upgrade-task" public="true" class="com.myplugin.MyUpgradeTask"> <interface>com.atlassian.sal.api.upgrade.PluginUpgradeTask</interface> </component></atlassian-plugin>
![Page 49: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/49.jpg)
Using SAL ... i18n
<atlassian-plugin>
<component-import key="i18nResolver" interface="com.atlassian.sal.api.message.I18nResolver" />
<resource key="my-i18n" type="i18n" location="i18n" />
</atlassian-plugin>
hello.world = Hello World! (i18n.properties)
hello.world: Hola a todos! (i18n_es.properties)
hello.world Hallo Welt! (i18n_de.properties)
![Page 50: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/50.jpg)
Using SAL ... i18n
Map<String, Object> context = new HashMap<String, Object>();context.put("i18n", i18nResolver);templateRenderer.render("templates/view.vm", context, writer);
<html> <head> <title>#i18n.getText('hello.world')</title> </head> <body ... /></html>
![Page 51: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/51.jpg)
Using SAL ... job scheduling
// simple very-contrived jobpublic class MyPluginJob implements PluginJob {
public void execute(Map<String, Object> data) { int count = data.get("jobExecutionCount"); count++; data.put("jobExecutionCount", count); }
}
![Page 52: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/52.jpg)
Using SAL ... job scheduling
public class MyComponent implements LifecycleAware { private PluginScheduler scheduler; // autowired
public void onStart() { scheduler.scheduleJob( "my-plugin-job", MyPluginJob.class, new HashMap<String, Object>(), new Date(), 10000 // milliseconds );
}}
![Page 53: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/53.jpg)
Targeted at You!FeaturesDedicated TeamDocumentationBackwards Compatibility
Open Source :D
![Page 54: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/54.jpg)
Go use it!
Shared Application Layer
Unified Application Links Template Renderer
Plugins Framework
Atlassian User Interface REST
![Page 55: AtlasCamp 2010: Understanding the Atlassian Platform - Tim Pettersen](https://reader034.fdocuments.us/reader034/viewer/2022052505/555ad349d8b42a024a8b4976/html5/thumbnails/55.jpg)