PageRenderTime 43ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 0ms

/content/server/framework/atlassian-sdk/adding-activities-to-a-third-party-feed-with-the-java-api.md

https://bitbucket.org/zchristmas/atlassian-sdk-docs
Markdown | 203 lines | 160 code | 43 blank | 0 comment | 0 complexity | 24a5826577ef302cc872f3c6bdc612dd MD5 | raw file
Possible License(s): LGPL-2.0
  1. ---
  2. aliases:
  3. - /server/framework/atlassian-sdk/adding-activities-to-a-third-party-feed-with-the-java-api-5669691.html
  4. - /server/framework/atlassian-sdk/adding-activities-to-a-third-party-feed-with-the-java-api-5669691.md
  5. category: devguide
  6. confluence_id: 5669691
  7. dac_edit_link: https://developer.atlassian.com/pages/editpage.action?cjm=wozere&pageId=5669691
  8. dac_view_link: https://developer.atlassian.com/pages/viewpage.action?cjm=wozere&pageId=5669691
  9. date: '2017-12-08'
  10. guides: guides
  11. legacy_title: Adding Activities to a Third Party feed with the Java API
  12. platform: server
  13. product: atlassian-sdk
  14. subcategory: learning
  15. title: Adding Activities to a Third Party feed with the Java API
  16. ---
  17. # Adding Activities to a Third Party feed with the Java API
  18. <table>
  19. <colgroup>
  20. <col style="width: 50%" />
  21. <col style="width: 50%" />
  22. </colgroup>
  23. <tbody>
  24. <tr class="odd">
  25. <td><p>Available:</p></td>
  26. <td><p>Activity Streams 5.0 and later.<br />
  27. JIRA 5.0 and later.</p></td>
  28. </tr>
  29. </tbody>
  30. </table>
  31. ## Overview
  32. Activity Streams 5.0 includes a new, lightweight API that allows plugins to add activities to the Activity Stream. This API doesn't give you as much power as [building a full-fledged Activity Provider](https://developer.atlassian.com/display/STREAMS/Making+your+own+Activity+Streams+Provider), but it's extremely easy to use.
  33. We'll demonstrate the API by building a sample plugin that uses a JIRA issue event listener to add an activity whenever an issue is deleted.
  34. {{% note %}}
  35. Source code for the complete plugin is available on <a href="https://bitbucket.org/jkodumal/streams-jira-delete-issue-plugin/" class="external-link">Bitbucket</a>
  36. {{% /note %}}{{% warning %}}
  37. The sample code shown here assumes that Activity Streams 5.0 is already bundled with JIRA. The source code in the Bitbucket repository bundles Activity Streams 5 into an alpha version of JIRA 5.0. I'll clean up the discrepancy when Streams 5.0 final is bundled with JIRA
  38. {{% /warning %}}
  39. ## Create the plugin project
  40. First we need to set up our development environment and create our plugin project and source directories. Assuming you have the Atlassian Plugin SDK installed, execute the following:
  41. ``` bash
  42. $ atlas-create-jira-plugin
  43. ```
  44. Follow the prompts to complete the initial plugin setup. We've used `com.atlassian.labs` as our `groupId` and `streams-jira-delete-issue-plugin` as our `artifactId`.
  45. ## Add dependencies to the POM
  46. First, we need to add a dependency on the `streams-thirdparty-api` and `streams-api` artifacts to the `dependencies` section in our `pom.xml` file:
  47. ``` xml
  48. <dependency>
  49. <groupId>com.atlassian.streams</groupId>
  50. <artifactId>streams-thirdparty-api</artifactId>
  51. <version>5.0</version>
  52. <scope>provided</scope>
  53. </dependency>
  54. <dependency>
  55. <groupId>com.atlassian.streams</groupId>
  56. <artifactId>streams-api</artifactId>
  57. <version>5.0</version>
  58. <scope>provided</scope>
  59. </dependency>
  60. ```
  61. The scope should be `provided`, as the library is part of Activity Streams 5, which is already bundled in JIRA. To create an event listener, we also need to add a few other dependencies:
  62. ``` xml
  63. <dependency>
  64. <groupId>com.atlassian.event</groupId>
  65. <artifactId>atlassian-event</artifactId>
  66. <version>${atlassian.event.version}</version>
  67. <scope>provided</scope>
  68. </dependency>
  69. <dependency>
  70. <groupId>com.atlassian.sal</groupId>
  71. <artifactId>sal-api</artifactId>
  72. <scope>provided</scope>
  73. <version>${sal.api.version}</version>
  74. </dependency>
  75. ```
  76. ## Import the `ActivityService`
  77. We need to import the `ActivityService` component in our `atlassian-plugin.xml`:
  78. ``` xml
  79. <component-import key="activityService" interface="com.atlassian.streams.thirdparty.api.ActivityService"/>
  80. ```
  81. We can then use constructor injection whenever we need the `activityService`.
  82. ## Import other components
  83. To get our event listener example working, we'll also need to inject a few other components from JIRA. We'll add the following lines to our `atlassian-plugin.xml`:
  84. ``` xml
  85. <component-import key="eventPublisher" interface="com.atlassian.event.api.EventPublisher"/>
  86. <component-import key="applicationProperties" interface="com.atlassian.sal.api.ApplicationProperties"/>
  87. ```
  88. We're going to use `applicationProperties` to fetch the base URL of our JIRA application. We'll need the `eventPublisher` to subscribe to JIRA's issue events.
  89. ## Create the `DeleteIssueListener`
  90. We're going to create a new component that registers itself as an event listener, and responds to deletion events by posting an activity via the `ActivityService`. Let's first declare the component in our `atlassian-plugin.xml`:
  91. ``` xml
  92. <component key="userListener" class="com.atlassian.labs.streams.jira.DeleteIssueListener">
  93. <description>Class that processes JIRA delete issue events.</description>
  94. </component>
  95. ```
  96. As the xml snippet indicates, we'll also want to create a class called `DeleteIssueListener` in the `com.atlassian.labs.streams` package. Create that class, and add a constructor that injects the components that we need:
  97. ``` java
  98. public class DeleteIssueListener
  99. {
  100. private final EventPublisher eventPublisher;
  101. private final ActivityService activityService;
  102. private final ApplicationProperties applicationProperties;
  103. public DeleteIssueListener(EventPublisher eventPublisher,
  104. ActivityService activityService,
  105. ApplicationProperties applicationProperties)
  106. {
  107. this.eventPublisher = eventPublisher;
  108. this.activityService = activityService;
  109. this.applicationProperties = applicationProperties;
  110. }
  111. }
  112. ```
  113. As described in our <a href="http://confluence.atlassian.com/display/DEVNET/Plugin+Tutorial+-+Writing+event+listeners+with+the+atlassian-event+library#PluginTutorial-Writingeventlistenerswiththeatlassian-eventlibrary-Coordinateeventregistrationwiththepluginlifecycle" class="external-link">event listener plugin tutorial</a>, this component needs to tie its registration with the `eventPublisher` to our plugin's lifecycle. We can do that by implementing `DisposableBean` and `LifecycleAware`
  114. ``` java
  115. public class DeleteIssueListener implements DisposableBean, LifecycleAware
  116. {
  117. ...
  118. @Override
  119. public void destroy() throws Exception
  120. {
  121. eventPublisher.unregister(this);
  122. }
  123. @Override
  124. public void afterPropertiesSet() throws Exception
  125. {
  126. eventPublisher.register(this);
  127. }
  128. }
  129. ```
  130. ## Create the activity
  131. We'll create an activity whenever a JIRA issue is deleted, and post it using our `ActivityService`. The code is as follows:
  132. ``` java
  133. @EventListener
  134. public void onIssueDelete(IssueEvent issueEvent)
  135. {
  136. if (issueEvent.getEventTypeId().equals(EventType.ISSUE_DELETED_ID))
  137. {
  138. User user = issueEvent.getUser();
  139. Either<ValidationErrors, Activity> result = new Activity.Builder(application("JIRA Deleted Issues", URI.create(applicationProperties.getBaseUrl())),
  140. new DateTime(),
  141. new UserProfile.Builder(user.getName()).fullName(user.getDisplayName())
  142. .build())
  143. .content(some(html(issueEvent.getIssue().getDescription())))
  144. .title(some(html(user.getDisplayName() + " deleted " + issueEvent.getIssue().getKey() + " - " + issueEvent.getIssue().getSummary())))
  145. .url(some(URI.create(applicationProperties.getBaseUrl())))
  146. .build();
  147. for (Activity activity : result.right())
  148. {
  149. activityService.postActivity(activity);
  150. }
  151. for (ValidationErrors errors : result.left())
  152. log.error("Errors encountered attempting to post activity: " + errors.toString());
  153. }
  154. }
  155. }
  156. ```
  157. We create a new `Activity` by using the `Activity.Builder` helper class. `Activity.Builder.build()` returns `Either<ValidationErrors, Activity>`, which is a disjoint union : either we created a valid `Activity`, or we received a set of errors indicating the reasons why the `Activity` we tried to construct wasn't well formed. The two `for` loops are a clean way of handling the two cases : only one of them actually executes, so we're either going to log the errors, or post the valid activity. Hopefully, the latter is the case, and our nice new activity well appear in the feed!
  158. #### Activities for Deleted Issues
  159. <img src="/server/framework/atlassian-sdk/images/deleted-issue-filters.jpg" width="300" height="259" />
  160. <img src="/server/framework/atlassian-sdk/images/deleted-issue-activity.jpg" width="300" height="205" />