Commits

Cheryl Jerozal committed 7f39eae

initial commit in this repo

Comments (0)

Files changed (4)

+<?xml version="1.0" encoding="UTF-8"?>
+
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+    <groupId>com.example.tutorial.plugins</groupId>
+    <artifactId>new-listener-plugin</artifactId>
+    <version>1.0</version>
+
+    <organization>
+        <name>Example Company</name>
+        <url>http://www.example.com/</url>
+    </organization>
+
+    <name>Tutorial plugin for atlassian-event listeners</name>
+    <description>A simple plugin demonstrating JIRA event handling with the atlassian-event library.</description>
+    <packaging>atlassian-plugin</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.atlassian.jira</groupId>
+            <artifactId>jira-api</artifactId>
+            <version>${jira.version}</version>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>com.atlassian.maven.plugins</groupId>
+                <artifactId>maven-jira-plugin</artifactId>
+                <version>${amps.version}</version>
+                <extensions>true</extensions>
+                <configuration>
+                    <productVersion>${jira.version}</productVersion>
+                    <log4jProperties>src/aps/log4j.properties</log4jProperties>
+                </configuration>
+            </plugin>
+            <plugin>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>1.6</source>
+                    <target>1.6</target>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <properties>
+        <!-- TODO: Update to 5.0 after release of 5.0 final -->
+        <jira.version>5.0-beta3</jira.version>
+        <amps.version>3.7</amps.version>
+    </properties>
+
+</project>

src/aps/log4j.properties

+# JIRA logging configuration file.
+
+# Note that these log levels can be set in Admin -> System -> Logging &
+# Profiling without restarting JIRA, although the effects don't last
+# across restarts.
+
+# Note that if you have another properties file higher in
+# the application classloader, that this file will be ignored.
+
+# To see more information about how debugging is being loaded
+# start your server with the System property "log4j.debug=true".
+# ie: java -Dlog4j.debug=true -jar orion.jar
+
+#####################################################
+# LOGGING LEVELS
+#####################################################
+
+# To turn more verbose logging on - change "WARN" to "DEBUG"
+
+log4j.rootLogger=WARN, console, filelog
+
+#####################################################
+# LOG FILE LOCATIONS
+#####################################################
+
+log4j.appender.console=org.apache.log4j.ConsoleAppender
+log4j.appender.console.Threshold=DEBUG
+log4j.appender.console.layout=org.apache.log4j.PatternLayout
+log4j.appender.console.layout.ConversionPattern=%d %t %p %X{jira.username} %X{jira.request.id} %X{jira.request.assession.id} %X{jira.request.ipaddr} %X{jira.request.url} [%c{4}] %m%n
+
+
+log4j.appender.nowarnconsole=org.apache.log4j.ConsoleAppender
+log4j.appender.nowarnconsole.Threshold=DEBUG
+log4j.appender.nowarnconsole.layout=org.apache.log4j.PatternLayout
+log4j.appender.nowarnconsole.layout.ConversionPattern=%d %t %p %X{jira.username} %X{jira.request.id} %X{jira.request.assession.id} %X{jira.request.ipaddr} %X{jira.request.url} [%c{4}] %m%n
+
+
+log4j.appender.filelog=com.atlassian.jira.logging.MultiTenantJiraHomeAppender
+log4j.appender.filelog.File=atlassian-jira.log
+log4j.appender.filelog.MaxFileSize=20480KB
+log4j.appender.filelog.MaxBackupIndex=5
+log4j.appender.filelog.layout=org.apache.log4j.PatternLayout
+log4j.appender.filelog.layout.ConversionPattern=%d %t %p %X{jira.username} %X{jira.request.id} %X{jira.request.assession.id} %X{jira.request.ipaddr} %X{jira.request.url} [%c{4}] %m%n
+
+log4j.appender.soapaccesslog=com.atlassian.jira.logging.MultiTenantJiraHomeAppender
+log4j.appender.soapaccesslog.File=atlassian-jira-soap-access.log
+log4j.appender.soapaccesslog.MaxFileSize=20480KB
+log4j.appender.soapaccesslog.MaxBackupIndex=5
+log4j.appender.soapaccesslog.layout=org.apache.log4j.PatternLayout
+log4j.appender.soapaccesslog.layout.ConversionPattern=%m%n
+
+log4j.appender.soapdumplog=com.atlassian.jira.logging.MultiTenantJiraHomeAppender
+log4j.appender.soapdumplog.File=atlassian-jira-soap-dump.log
+log4j.appender.soapdumplog.MaxFileSize=20480KB
+log4j.appender.soapdumplog.MaxBackupIndex=5
+log4j.appender.soapdumplog.layout=org.apache.log4j.PatternLayout
+log4j.appender.soapdumplog.layout.ConversionPattern=%m%n
+
+log4j.appender.httpaccesslog=com.atlassian.jira.logging.MultiTenantJiraHomeAppender
+log4j.appender.httpaccesslog.File=atlassian-jira-http-access.log
+log4j.appender.httpaccesslog.MaxFileSize=20480KB
+log4j.appender.httpaccesslog.MaxBackupIndex=5
+log4j.appender.httpaccesslog.layout=org.apache.log4j.PatternLayout
+log4j.appender.httpaccesslog.layout.ConversionPattern=%m%n
+
+log4j.appender.httpdumplog=com.atlassian.jira.logging.MultiTenantJiraHomeAppender
+log4j.appender.httpdumplog.File=atlassian-jira-http-dump.log
+log4j.appender.httpdumplog.MaxFileSize=20480KB
+log4j.appender.httpdumplog.MaxBackupIndex=5
+log4j.appender.httpdumplog.layout=org.apache.log4j.PatternLayout
+log4j.appender.httpdumplog.layout.ConversionPattern=%m%n
+
+log4j.appender.sqllog=com.atlassian.jira.logging.MultiTenantJiraHomeAppender
+log4j.appender.sqllog.File=atlassian-jira-sql.log
+log4j.appender.sqllog.MaxFileSize=20480KB
+log4j.appender.sqllog.MaxBackupIndex=5
+log4j.appender.sqllog.layout=org.apache.log4j.PatternLayout
+log4j.appender.sqllog.layout.ConversionPattern=%d %t %X{jira.username} %X{jira.request.id} %X{jira.request.assession.id} %X{jira.request.url} %m%n
+
+log4j.appender.slowquerylog=com.atlassian.jira.logging.MultiTenantJiraHomeAppender
+log4j.appender.slowquerylog.File=atlassian-jira-slow-queries.log
+log4j.appender.slowquerylog.MaxFileSize=20480KB
+log4j.appender.slowquerylog.MaxBackupIndex=5
+log4j.appender.slowquerylog.layout=org.apache.log4j.PatternLayout
+log4j.appender.slowquerylog.layout.ConversionPattern=%d %t %p %X{jira.username} %X{jira.request.id} %X{jira.request.assession.id} %X{jira.request.url} [%c{4}] %m%n
+
+log4j.appender.xsrflog=com.atlassian.jira.logging.MultiTenantJiraHomeAppender
+log4j.appender.xsrflog.File=atlassian-jira-xsrf.log
+log4j.appender.xsrflog.MaxFileSize=20480KB
+log4j.appender.xsrflog.MaxBackupIndex=5
+log4j.appender.xsrflog.layout=org.apache.log4j.PatternLayout
+log4j.appender.xsrflog.layout.ConversionPattern=%d %t %X{jira.username} %X{jira.request.id} %X{jira.request.assession.id} %X{jira.request.url} %m%n
+
+log4j.appender.securitylog=com.atlassian.jira.logging.MultiTenantJiraHomeAppender
+log4j.appender.securitylog.File=atlassian-jira-security.log
+log4j.appender.securitylog.MaxFileSize=20480KB
+log4j.appender.securitylog.MaxBackupIndex=5
+log4j.appender.securitylog.layout=org.apache.log4j.PatternLayout
+log4j.appender.securitylog.layout.ConversionPattern=%d %t %X{jira.username} %X{jira.request.id} %X{jira.request.assession.id} %X{jira.request.ipaddr} %X{jira.request.url} %m%n
+
+#####################################################
+# Access logs
+#####################################################
+
+log4j.logger.com.atlassian.jira.soap.axis.JiraAxisSoapLog  = OFF, soapaccesslog
+log4j.additivity.com.atlassian.jira.soap.axis.JiraAxisSoapLog = false
+
+log4j.logger.com.atlassian.jira.soap.axis.JiraAxisSoapLogDump  = OFF, soapdumplog
+log4j.additivity.com.atlassian.jira.soap.axis.JiraAxisSoapLogDump = false
+
+log4j.logger.com.atlassian.jira.web.filters.accesslog.AccessLogFilter = OFF, httpaccesslog
+log4j.additivity.com.atlassian.jira.web.filters.accesslog.AccessLogFilter = false
+
+log4j.logger.com.atlassian.jira.web.filters.accesslog.AccessLogFilterIncludeImages = OFF, httpaccesslog
+log4j.additivity.com.atlassian.jira.web.filters.accesslog.AccessLogFilterIncludeImages = false
+
+log4j.logger.com.atlassian.jira.web.filters.accesslog.AccessLogFilterDump = OFF, httpdumplog
+log4j.additivity.com.atlassian.jira.web.filters.accesslog.AccessLogFilterDump = false
+
+#####################################################
+# SQL logs
+#####################################################
+#
+# Beware of turning this log level on.  At INFO level it will log every SQL statement
+# and at DEBUG level it will also log the calling stack trace.  Turning this on will DEGRADE your
+# JIRA database throughput.
+#
+log4j.logger.com.atlassian.jira.ofbiz.LoggingSQLInterceptor = OFF, sqllog
+log4j.additivity.com.atlassian.jira.ofbiz.LoggingSQLInterceptor = false
+
+log4j.logger.com.atlassian.jira.security.xsrf.XsrfVulnerabilityDetectionSQLInterceptor = OFF, xsrflog
+log4j.additivity.com.atlassian.jira.security.xsrf.XsrfVulnerabilityDetectionSQLInterceptor = false
+
+
+#####################################################
+# Security logs
+#####################################################
+
+log4j.logger.com.atlassian.jira.login.security = INFO, securitylog
+log4j.additivity.com.atlassian.jira.login.security = false
+
+#
+#
+# The following log levels can be useful to set when login problems occur within JIRA
+#
+log4j.logger.com.atlassian.jira.login = WARN, securitylog
+log4j.additivity.com.atlassian.jira.login = false
+
+log4j.logger.com.atlassian.jira.web.session.currentusers = WARN, securitylog
+log4j.additivity.com.atlassian.jira.web.session.currentusers = false
+
+#
+# BEWARE - Turning on Seraph debug logs will result in many logs lines per web request.
+#
+log4j.logger.com.atlassian.seraph = WARN, securitylog
+log4j.additivity.com.atlassian.seraph = false
+
+#
+#---------------
+
+#####################################################
+# CLASS-SPECIFIC LOGGING LEVELS
+#####################################################
+# This stuff you may wish to debug, but it produces a high volume of logs.
+# Uncomment only if you want to debug something particular
+
+log4j.logger.com.atlassian = WARN, console, filelog
+log4j.additivity.com.atlassian = false
+
+log4j.logger.com.atlassian.plugin = INFO, console, filelog
+log4j.additivity.com.atlassian.plugin = false
+
+log4j.logger.atlassian.plugin = INFO, console, filelog
+log4j.additivity.atlassian.plugin = false
+
+log4j.logger.org.twdata.pkgscanner = WARN, console, filelog
+log4j.additivity.org.twdata.pkgscanner = false
+
+log4j.logger.com.atlassian.plugin.osgi.factory = WARN, console, filelog
+log4j.additivity.com.atlassian.plugin.osgi.factory = false
+
+log4j.logger.com.atlassian.plugin.osgi.container = WARN, console, filelog
+log4j.additivity.com.atlassian.plugin.osgi.container = false
+
+log4j.logger.org.apache.shindig = ERROR, console, filelog
+log4j.additivity.org.apache.shindig = false
+
+log4j.logger.com.atlassian.gadgets = WARN, console, filelog
+log4j.additivity.com.atlassian.gadgets = false
+
+log4j.logger.com.atlassian.jira.gadgets.system.MarketingGadgetSpecProvider = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.gadgets.system.MarketingGadgetSpecProvider = false
+
+# The directory may produce errors of interest to admins when adding gadgets with features that aren't supported
+# (for example).
+log4j.logger.com.atlassian.gadgets.directory = INFO, console, filelog
+log4j.additivity.com.atlassian.gadgets.directory = false
+
+# Felix annoyingly dumps some pretty silly INFO level messages. So we have to set logging to WARN here.  Means
+# we miss out on some useful startup logging.  Should probably remove this if Felix ever fix this.
+log4j.logger.com.atlassian.plugin.osgi.container.felix.FelixOsgiContainerManager = WARN, console, filelog
+log4j.additivity.com.atlassian.plugin.osgi.container.felix.FelixOsgiContainerManager = false
+
+log4j.logger.com.atlassian.plugin.servlet = WARN, console, filelog
+log4j.additivity.com.atlassian.plugin.servlet = false
+
+log4j.logger.com.atlassian.plugin.classloader = WARN, console, filelog
+log4j.additivity.com.atlassian.plugin.classloader = false
+
+log4j.logger.com.atlassian.jira.util.system.JiraSystemRestarterImpl = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.util.system.JiraSystemRestarterImpl = false
+
+log4j.logger.com.atlassian.jira.upgrade = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.upgrade = false
+
+log4j.logger.com.atlassian.jira.startup = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.startup = false
+
+log4j.logger.com.atlassian.jira.util.BugzillaImportBean  = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.util.BugzillaImportBean = false
+
+log4j.logger.com.atlassian.jira.web.action.util.LDAPConfigurer = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.web.action.util.LDAPConfigurer = false
+
+log4j.logger.com.atlassian.jira.util.MantisImportBean  = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.util.MantisImportBean = false
+
+log4j.logger.com.atlassian.jira.imports  = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.imports = false
+
+log4j.logger.com.atlassian.jira.security = WARN, console, filelog
+log4j.additivity.com.atlassian.jira.security = false
+
+log4j.logger.com.atlassian.jira.issue.index = WARN, console, filelog
+log4j.additivity.com.atlassian.jira.issue.index = false
+
+# DefaultIndexManager should run at INFO level, because we want to see messages when we force an optimise etc.
+log4j.logger.com.atlassian.jira.issue.index.DefaultIndexManager = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.issue.index.DefaultIndexManager = false
+
+# Allow the optimise job to log at info level so that we can see the last time it ran
+log4j.logger.com.atlassian.jira.issue.index.job.OptimizeIndexJob = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.issue.index.job.OptimizeIndexJob = false
+
+# Allow the Composite IndexLifecycleManager to log info
+log4j.logger.com.atlassian.jira.util.index = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.util.index = false
+
+log4j.logger.com.atlassian.jira.project = WARN, console, filelog
+log4j.additivity.com.atlassian.jira.project = false
+
+log4j.logger.com.atlassian.jira.project.version = WARN, console, filelog
+log4j.additivity.com.atlassian.jira.project.version = false
+
+log4j.logger.com.atlassian.jira.user.job.RefreshActiveUserCountJob = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.user.job.RefreshActiveUserCountJob = false
+
+log4j.logger.com.atlassian.jira.issue.search.providers = WARN, console, filelog
+log4j.additivity.com.atlassian.jira.issue.search.providers = false
+
+log4j.logger.com.atlassian.jira.issue.search.providers.LuceneSearchProvider_SLOW = INFO, slowquerylog
+log4j.additivity.com.atlassian.jira.issue.search.providers.LuceneSearchProvider_SLOW = false
+
+log4j.logger.com.atlassian.jira.action.admin = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.action.admin = false
+
+log4j.logger.com.opensymphony = WARN, console, filelog
+log4j.additivity.com.opensymphony = false
+
+log4j.logger.com.atlassian.jira.workflow = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.workflow = false
+
+log4j.logger.com.atlassian.jira.service = WARN, console, filelog
+log4j.additivity.com.atlassian.jira.service = false
+
+log4j.logger.com.atlassian.jira.service.services.DebugService = DEBUG, console, filelog
+log4j.additivity.com.atlassian.jira.service.services.DebugService = false
+
+log4j.logger.com.atlassian.jira.web.dispatcher.JiraWebworkActionDispatcher = WARN, nowarnconsole, filelog
+log4j.additivity.com.atlassian.jira.web.dispatcher.JiraWebworkActionDispatcher = false
+log4j.logger.webwork = WARN, console, filelog
+log4j.additivity.webwork = false
+
+log4j.logger.webwork.util.ServletValueStack = WARN, console, filelog
+
+log4j.logger.org.ofbiz.core.entity.jdbc.DatabaseUtil = WARN, nowarnconsole, filelog
+log4j.additivity.org.ofbiz.core.entity.jdbc.DatabaseUtil = false
+log4j.logger.org.ofbiz = WARN, console, filelog
+log4j.additivity.org.ofbiz = false
+
+log4j.logger.com.atlassian.jira.web.servlet.rpc = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.web.servlet.rpc = false
+log4j.logger.com.atlassian.jira.soap = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.soap = false
+
+log4j.logger.com.atlassian.jira.plugin.ext.perforce = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.plugin.ext.perforce = false
+
+log4j.logger.jelly = INFO, console, filelog
+log4j.additivity.jelly = false
+
+log4j.logger.logMessage.jsp = INFO, console, filelog
+log4j.additivity.logMessage.jsp = false
+
+log4j.logger.com.atlassian.jira.issue.views = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.issue.views = false
+
+# Project Imports should be logged at INFO level so we can see the steps running.
+log4j.logger.com.atlassian.jira.imports.project = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.imports.project = false
+
+log4j.logger.com.atlassian.jira.plugin.profile.DefaultUserFormatMapper = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.plugin.profile.DefaultUserFormatMapper = false
+
+log4j.logger.com.atlassian.jira.scheduler.JiraSchedulerLauncher = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.scheduler.JiraSchedulerLauncher = false
+
+#####################################################
+# Crowd Embedded
+#####################################################
+
+# We want to get INFO level logs about Directory events
+log4j.logger.com.atlassian.crowd.directory = INFO, console, filelog
+log4j.additivity.com.atlassian.crowd.directory = false
+
+#####################################################
+# JQL
+#####################################################
+
+log4j.logger.com.atlassian.jira.jql  = WARN, console, filelog
+log4j.additivity.com.atlassian.jira.jql = false
+
+log4j.logger.com.atlassian.jira.jql.resolver = WARN, console, filelog
+log4j.additivity.com.atlassian.jira.jql.resolver = false
+
+#####################################################
+# Long Running Tasks
+#####################################################
+
+log4j.logger.com.atlassian.jira.workflow.migration  = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.workflow.migration = false
+
+log4j.logger.com.atlassian.jira.web.action.admin.index.IndexAdminImpl = INFO, console, filelog
+log4j.additivity.com.atlassian.jira.web.action.admin.index.IndexAdminImpl = false
+
+#####################################################
+# PROFILING
+#####################################################
+
+log4j.logger.com.atlassian.util.profiling.filters = INFO, console, filelog
+log4j.additivity.com.atlassian.util.profiling.filters = false
+
+log4j.logger.com.atlassian.util.profiling = DEBUG, console, filelog
+log4j.additivity.com.atlassian.util.profiling = false
+
+log4j.logger.com.atlassian.jira.web.filters.ThreadLocalQueryProfiler = DEBUG, console, filelog
+log4j.additivity.com.atlassian.jira.web.filters.ThreadLocalQueryProfiler = false
+
+#
+# By default we ignore some usually harmless exception such as Client Abort Exceptions.  However
+# if this proves problematic then we can turn this to DEBUG log on.
+#
+log4j.logger.com.atlassian.jira.web.exception.WebExceptionChecker = OFF, console, filelog
+log4j.additivity.com.atlassian.jira.web.exception.WebExceptionChecker = false
+
+log4j.logger.com.example.tutorial.plugins = DEBUG, console, filelog
+log4j.additivity.com.example.tutorial.plugins = false

src/main/java/com/example/tutorial/plugins/IssueCreatedResolvedListener.java

+package com.example.tutorial.plugins;
+
+import com.atlassian.event.api.EventListener;
+import com.atlassian.event.api.EventPublisher;
+import com.atlassian.jira.event.issue.IssueEvent;
+import com.atlassian.jira.event.type.EventType;
+import com.atlassian.jira.issue.Issue;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.beans.factory.InitializingBean;
+
+/**
+ * Simple JIRA listener using the atlassian-event library and demonstrating
+ * plugin lifecycle integration.
+ */
+public class IssueCreatedResolvedListener implements InitializingBean, DisposableBean {
+
+    private static final Logger log = LoggerFactory.getLogger(IssueCreatedResolvedListener.class);
+
+    private final EventPublisher eventPublisher;
+
+    /**
+     * Constructor.
+     * @param eventPublisher injected {@code EventPublisher} implementation.
+     */
+    public IssueCreatedResolvedListener(EventPublisher eventPublisher) {
+        this.eventPublisher = eventPublisher;
+    }
+
+    /**
+     * Called when the plugin has been enabled.
+     * @throws Exception
+     */
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        // register ourselves with the EventPublisher
+        eventPublisher.register(this);
+    }
+
+    /**
+     * Called when the plugin is being disabled or removed.
+     * @throws Exception
+     */
+    @Override
+    public void destroy() throws Exception {
+        // unregister ourselves with the EventPublisher
+        eventPublisher.unregister(this);
+    }
+
+    /**
+     * Receives any {@code IssueEvent}s sent by JIRA.
+     * @param issueEvent the IssueEvent passed to us
+     */
+    @EventListener
+    public void onIssueEvent(IssueEvent issueEvent) {
+        Long eventTypeId = issueEvent.getEventTypeId();
+        Issue issue = issueEvent.getIssue();
+
+        // if it's an event we're interested in, log it
+        if (eventTypeId.equals(EventType.ISSUE_CREATED_ID)) {
+            log.info("Issue {} has been created at {}.", issue.getKey(), issue.getCreated());
+        } else if (eventTypeId.equals(EventType.ISSUE_RESOLVED_ID)) {
+            log.info("Issue {} has been resolved at {}.", issue.getKey(), issue.getResolutionDate());
+        }
+    }
+
+//    @EventListener
+//    public void onEvent(DraftWorkflowCreatedEvent workflowDeletedEvent) {
+//
+//    }
+
+}

src/main/resources/atlassian-plugin.xml

+<atlassian-plugin key="${project.groupId}.${project.artifactId}" name="${project.name}" plugins-version="2">
+    <plugin-info>
+        <description>${project.description}</description>
+        <version>${project.version}</version>
+        <vendor name="${project.organization.name}" url="${project.organization.url}" />
+    </plugin-info>
+
+    <component-import key="eventPublisher" interface="com.atlassian.event.api.EventPublisher">
+        <description>atlassian-event EventPublisher imported from system bundle.</description>
+    </component-import>
+
+    <component key="eventListener" class="com.example.tutorial.plugins.IssueCreatedResolvedListener">
+        <description>Class that processes the incoming JIRA issue events.</description>
+    </component>
+
+</atlassian-plugin>