com.codenvy.jira.IssueCreatedListener.java Source code

Java tutorial

Introduction

Here is the source code for com.codenvy.jira.IssueCreatedListener.java

Source

/*******************************************************************************
 * Copyright (c) 2012-2016 Codenvy
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *   Codenvy, S.A. - initial API and implementation
 *******************************************************************************/
package com.codenvy.jira;

import us.monoid.json.JSONArray;
import us.monoid.json.JSONException;
import us.monoid.json.JSONObject;
import us.monoid.web.Resty;

import com.atlassian.crowd.embedded.api.User;
import com.atlassian.event.api.EventListener;
import com.atlassian.event.api.EventPublisher;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.fields.FieldException;
import com.atlassian.jira.issue.fields.FieldManager;
import com.atlassian.jira.bc.issue.IssueService;
import com.atlassian.jira.event.issue.IssueEvent;
import com.atlassian.jira.event.type.EventType;
import com.atlassian.jira.issue.Issue;
import com.atlassian.jira.issue.IssueInputParameters;
import com.atlassian.jira.issue.MutableIssue;
import com.atlassian.jira.user.ApplicationUser;
import com.atlassian.jira.user.ApplicationUsers;
import com.atlassian.sal.api.pluginsettings.PluginSettings;
import com.atlassian.sal.api.pluginsettings.PluginSettingsFactory;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

import java.io.IOException;
import java.util.Locale;
import java.util.Set;

import static us.monoid.web.Resty.content;

/**
 * JIRA listener that generates Codenvy factories for factory activated issues.
 *
 */
public class IssueCreatedListener implements InitializingBean, DisposableBean {

    private static final Logger LOG = LoggerFactory.getLogger(IssueCreatedListener.class);

    private static final String CODENVY_DEVELOP_FIELD_TYPE_KEY = "com.codenvy.jira.codenvy-jira-plugin:developfield";
    private static final String CODENVY_REVIEW_FIELD_TYPE_KEY = "com.codenvy.jira.codenvy-jira-plugin:reviewfield";

    private final EventPublisher eventPublisher;
    private final PluginSettingsFactory pluginSettingsFactory;
    private final IssueService issueService;
    private final FieldManager fieldManager;

    /**
     * Constructor.
     * @param eventPublisher injected {@code EventPublisher} implementation.
     * @param pluginSettingsFactory factory to get globally saved settings.
     * @param issueService service to work with JIRA issues.
     * @param fieldManager service to work with JIRA issue fields.
     */
    public IssueCreatedListener(EventPublisher eventPublisher, PluginSettingsFactory pluginSettingsFactory,
            IssueService issueService, FieldManager fieldManager) {
        this.eventPublisher = eventPublisher;
        this.pluginSettingsFactory = pluginSettingsFactory;
        this.issueService = issueService;
        this.fieldManager = fieldManager;
    }

    /**
     * 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) {
        final Long eventTypeId = issueEvent.getEventTypeId();
        final Issue issue = issueEvent.getIssue();
        // if it's an event we're interested in, log it
        if (eventTypeId.equals(EventType.ISSUE_CREATED_ID)) {
            // Get plugin settings
            PluginSettings settings = pluginSettingsFactory.createGlobalSettings();
            final String codenvyUrl = (String) settings.get("codenvy.admin.instanceurl");
            final String codenvyUsername = (String) settings.get("codenvy.admin.username");
            final String codenvyPassword = (String) settings.get("codenvy.admin.password");

            if (codenvyUrl == null || codenvyUrl.isEmpty() || codenvyUsername == null || codenvyUsername.isEmpty()
                    || codenvyPassword == null || codenvyPassword.isEmpty()) {
                LOG.warn("At least one of codenvy URL (\'" + codenvyUrl + "\'), username (\'" + codenvyUsername
                        + "\') " + "or password (\'" + codenvyPassword + "\') is not set or empty.");
                return;
            }

            try {

                final String issueKey = issue.getKey();
                final String projectKey = issue.getProjectObject().getKey();
                final String projectName = issue.getProjectObject().getName();

                // Get current JIRA user
                final User eventUser = issueEvent.getUser();
                if (eventUser == null) {
                    LOG.warn("No user given in issue event.");
                    return;
                }

                // Get id of custom fields Develop & Review
                String developFieldId = null;
                String reviewFieldId = null;
                final Set<CustomField> customFields = fieldManager.getAvailableCustomFields(eventUser, issue);
                for (CustomField cf : customFields) {
                    String customFieldTypeKey = cf.getCustomFieldType().getKey();
                    if (CODENVY_DEVELOP_FIELD_TYPE_KEY.equals(customFieldTypeKey)) {
                        developFieldId = cf.getId();
                    }
                    if (CODENVY_REVIEW_FIELD_TYPE_KEY.equals(customFieldTypeKey)) {
                        reviewFieldId = cf.getId();
                    }
                }

                // Continue only if Develop and Review fields are available on the issue
                if (developFieldId == null || reviewFieldId == null) {
                    LOG.warn("Field Develop (" + developFieldId + ") and/or Review (" + reviewFieldId
                            + ") are not available for issue " + issueKey + ".");
                    return;
                }

                JSONObject token;
                final Resty resty = new Resty();

                // Authenticate on Codenvy as JIRA admin
                final JSONObject credentials = new JSONObject().put("username", codenvyUsername).put("password",
                        codenvyPassword);
                token = resty.json(codenvyUrl + "/api/auth/login", content(credentials)).object();

                if (token == null) {
                    LOG.warn("No Codenvy Token obtained (" + codenvyUsername + ").");
                    return;
                }

                // Get Codenvy user id
                final JSONObject user = resty.json(codenvyUrl + "/api/user").object();
                if (user == null) {
                    LOG.warn("No Codenvy user found (" + codenvyUsername + ").");
                    return;
                }

                // Get parent factory for project
                final String tokenValue = token.getString("value");
                final String userId = user.getString("id");
                final String projectKeyLower = projectKey.toLowerCase(Locale.getDefault());
                final JSONArray factories = resty.json(codenvyUrl + "/api/factory/find?name=" + projectKeyLower
                        + "&creator.userId=" + userId + "&token=" + tokenValue).array();

                if (factories.length() == 0) {
                    LOG.warn("No factory found with name: " + projectKeyLower + " and userId (owner): " + userId);
                    return;
                }

                JSONObject parentFactory = factories.getJSONObject(0);
                LOG.debug("Parent factory for project " + projectName + ": " + parentFactory);

                // Set perUser policy & correct name (Develop factory)
                final JSONObject developFactory = setCreatePolicy(parentFactory, "perUser");
                developFactory.remove("name");
                developFactory.put("name", issueKey + "-develop-factory");

                // Clean id and creator
                developFactory.remove("id");
                developFactory.remove("creator");

                // Set workspace.projects.source.parameters.branch = issue key
                final JSONObject project = developFactory.getJSONObject("workspace").getJSONArray("projects")
                        .getJSONObject(0);
                final JSONObject parameters = project.getJSONObject("source").getJSONObject("parameters");
                parameters.put("branch", issueKey);

                // Generate Develop factory
                final JSONObject generatedDevelopFactory = resty
                        .json(codenvyUrl + "/api/factory", content(developFactory)).object();
                LOG.debug("Generated DEVELOP factory for issue " + issueKey + ": " + generatedDevelopFactory);

                // Set perClick policy & correct name (Review factory)
                final JSONObject reviewFactory = setCreatePolicy(developFactory, "perClick");
                reviewFactory.remove("name");
                reviewFactory.put("name", issueKey + "-review-factory");

                // Generate Review factory
                final JSONObject generatedReviewFactory = resty
                        .json(codenvyUrl + "/api/factory", content(reviewFactory)).object();
                LOG.debug("Generated REVIEW factory for issue " + issueKey + ": " + generatedReviewFactory);

                // Set factory URLs in Develop & Review fields
                String developFactoryUrl = getNamedFactoryUrl(generatedDevelopFactory);
                String reviewFactoryUrl = getNamedFactoryUrl(generatedReviewFactory);

                if (developFactoryUrl == null || reviewFactoryUrl == null) {
                    LOG.warn("URL of factory Develop (" + developFactoryUrl + ") and/or Review (" + reviewFactoryUrl
                            + ") is null.");
                    return;
                }

                String developFieldValue = "<a id=\"codenvy_develop_field\" href=\"" + developFactoryUrl
                        + "\">Develop in Codenvy</a>";
                String reviewFieldValue = "<a id=\"codenvy_review_field\" href=\"" + reviewFactoryUrl
                        + "\">Review in Codenvy</a>";

                final ApplicationUser appUser = ApplicationUsers.from(eventUser);
                updateIssue(appUser, issueKey, developFieldId, developFieldValue, reviewFieldId, reviewFieldValue);

            } catch (JSONException | IOException | FieldException e) {
                LOG.error(e.getMessage());
            }
        }
    }

    /**
     * Update a JIRA issue with given value in fields Develop and Review
     *
     * @param appUser the user from current session
     * @param issueKey the key of the issue to update
     * @param developFieldId the id of custom field Develop
     * @param developValue the value to put in custom field Develop
     * @param reviewFieldId the id of custom field Review
     * @param reviewValue the value to put in custom field Review
     */
    private void updateIssue(ApplicationUser appUser, String issueKey, String developFieldId, String developValue,
            String reviewFieldId, String reviewValue) {
        // Get the issue from the key that's passed in
        IssueService.IssueResult issueResult = issueService.getIssue(appUser, issueKey);
        MutableIssue issue = issueResult.getIssue();
        // Next we need to validate the updated issue
        IssueInputParameters issueInputParameters = issueService.newIssueInputParameters();
        issueInputParameters.addCustomFieldValue(developFieldId, developValue);
        issueInputParameters.addCustomFieldValue(reviewFieldId, reviewValue);
        IssueService.UpdateValidationResult result = issueService.validateUpdate(appUser, issue.getId(),
                issueInputParameters);
        if (result.getErrorCollection().hasAnyErrors()) {
            LOG.warn("Issue " + issueKey + " not updated due to error(s): "
                    + result.getErrorCollection().getErrorMessages() + ".");
        } else {
            // Validation passes
            issueService.update(appUser, result);
            LOG.debug("Codenvy fields successfully updated on issue " + issueKey + ".");
        }
    }

    /**
     * Set a given createPolicy to a given factory
     * @param factory the factory to update
     * @param createPolicy the value of create policy
     * @return the updated factory
     * @throws JSONException
     */
    private JSONObject setCreatePolicy(JSONObject factory, String createPolicy) throws JSONException {
        JSONObject newFactory = factory;
        JSONObject policies = newFactory.optJSONObject("policies");
        if (policies == null) {
            newFactory.put("policies", new JSONObject().put("create", createPolicy));
        } else {
            policies.remove("create");
            policies.put("create", createPolicy);
        }
        return newFactory;
    }

    /**
     * Get factory link from a factory
     *
     * @param factory the factory to search into
     * @return the 'accept-named' URL of the factory
     * @throws JSONException
     */
    private String getNamedFactoryUrl(JSONObject factory) throws JSONException {
        String factoryUrl = null;
        JSONArray links = factory.getJSONArray("links");
        for (int i = 0; i < links.length(); i++) {
            JSONObject link = links.getJSONObject(i);
            String rel = link.getString("rel");
            if ("accept-named".equals(rel)) {
                factoryUrl = link.getString("href");
                break;
            }
        }
        return factoryUrl;
    }
}