Organization Sync is Broken

    Problem

    When syncing the Organization field between two Service Desk projects in Jira on-premise, the following error occurs:

    Error detail:
    Exalate has problems while trying to create an issue in this Jira. 
    Details: Error occurred while creating issue. This could be due to a plugin being incompatible with this version of JIRA. For more details please consult the logs, and see: http://confluence.atlassian.com/x/3McB - com.exalate.basic.domain.hubobject.v1.BasicHubOrganization cannot be cast to com.atlassian.servicedesk.api.organization.CustomerOrganization

    Cause

    The issue is caused by the fact that Exalate does not convert its own class to the Atlassian class.

    Solution

    To sync the Organization names between the Service Desk projects, you can add the following Sync rules to the Outgoing and Incoming sync:

    Outgoing Sync Rules

    def getCustomerOrganizations = { _proxyUser, serviceDeskId ->
        com.atlassian.servicedesk.api.organization.OrganizationService orgServ = com.atlassian.jira.component.ComponentAccessor
                .getOSGiComponentInstanceOfType(com.atlassian.servicedesk.api.organization.OrganizationService.class);
    
        com.atlassian.servicedesk.api.organization.OrganizationsQuery organizationsQuery =
                orgServ.newOrganizationsQueryBuilder()
                        .pagedRequest(com.atlassian.servicedesk.api.util.paging.SimplePagedRequest.paged(0, 50))
                        .serviceDeskId(serviceDeskId)
                        .build();
    
        Object either = orgServ
                .getOrganizations(_proxyUser, organizationsQuery)
        com.atlassian.servicedesk.api.util.paging.PagedResponse<com.atlassian.servicedesk.api.organization.CustomerOrganization> orgPage = either
                .right()
                .getOrThrow(new com.google.common.base.Supplier<com.exalate.api.exception.IssueTrackerException>() { public com.exalate.api.exception.IssueTrackerException get() { return new com.exalate.api.exception.IssueTrackerException("Something failed!")}});
    
        List<com.atlassian.servicedesk.api.organization.CustomerOrganization> results = com.google.common.collect.Lists.newArrayList();
        results.addAll(orgPage.getResults())
    
        int limitToKeepTrack = 0;
        while (orgPage.hasNextPage()) {
            limitToKeepTrack += 50;
            organizationsQuery = orgServ.newOrganizationsQueryBuilder()
                    .pagedRequest(com.atlassian.servicedesk.api.util.paging.SimplePagedRequest.paged(limitToKeepTrack, limitToKeepTrack + 50))
                    .serviceDeskId(serviceDeskId)
                    .build();
    
            orgPage = orgServ.getOrganizations(_proxyUser, organizationsQuery);
    
            results.addAll(orgPage.getResults())
        }
    
        return results;
    }
    def getLocalOrgs = { jIssue ->
        def serviceDeskManagerAdapter = com.atlassian.jira.component.ComponentAccessor.getOSGiComponentInstanceOfType(com.exalate.compatibility.api.IServiceDeskManagerAdapter.class)
        Integer serviceDeskId = serviceDeskManagerAdapter.getServiceDeskIdForProject(jIssue.getProjectObject());
        def proxyUser = com.atlassian.jira.component.ComponentAccessor.getOSGiComponentInstanceOfType(com.exalate.api.node.INodeService.class)
                .proxyUser
        if (serviceDeskId == null) {
            log.error("Service desk in not available for project with id " + jIssue.getProjectId());
            return null;
        }
    
        return getCustomerOrganizations(proxyUser, serviceDeskId);
    }
    def toHubOrg = { com.atlassian.servicedesk.api.organization.CustomerOrganization org ->
        new com.exalate.basic.domain.hubobject.v1.BasicHubOrganization(org.name, [])
    }
    def getOrgs = {
        def customFieldManager = com.atlassian.jira.component.ComponentAccessor.customFieldManager
        def cf = customFieldManager.getCustomFieldObject(issue.customFields.Organizations.id as Long)
        def issueManager = com.atlassian.jira.component.ComponentAccessor.issueManager
        def jIssue = issueManager.getIssueObject(issue.id as Long)
        def localOrgs = getLocalOrgs(jIssue)
        def orgs = localOrgs.collect(toHubOrg)
        orgs
    }
    
    
    replica.customFields.Organizations = issue.customFields.Organizations
    replica.customFields.Organizations.value = getOrgs()

    Incoming Sync Rules

    def proxyUser = com.atlassian.jira.component.ComponentAccessor.getOSGiComponentInstanceOfType(com.exalate.api.node.INodeService.class)
            .proxyUser
    def toCustomerOrganizations = { _proxyUser, serviceDeskId, List<String> valueOrgNames ->
        com.atlassian.servicedesk.api.organization.OrganizationService orgServ = com.atlassian.jira.component.ComponentAccessor
                .getOSGiComponentInstanceOfType(com.atlassian.servicedesk.api.organization.OrganizationService.class);
    
        com.atlassian.servicedesk.api.organization.OrganizationsQuery organizationsQuery =
                orgServ.newOrganizationsQueryBuilder()
                        .pagedRequest(com.atlassian.servicedesk.api.util.paging.SimplePagedRequest.paged(0, 50))
                        .serviceDeskId(serviceDeskId)
                        .build();
    
        Object either = orgServ
                .getOrganizations(proxyUser, organizationsQuery)
        com.atlassian.servicedesk.api.util.paging.PagedResponse<com.atlassian.servicedesk.api.organization.CustomerOrganization> orgPage = either
                .right()
                .getOrThrow(new com.google.common.base.Supplier<com.exalate.api.exception.IssueTrackerException>() { public com.exalate.api.exception.IssueTrackerException get() { return new com.exalate.api.exception.IssueTrackerException("Something failed!")}});
    
        List<com.atlassian.servicedesk.api.organization.CustomerOrganization> results = com.google.common.collect.Lists.newArrayList();
        for (com.atlassian.servicedesk.api.organization.CustomerOrganization org : orgPage.getResults()) {
            if (valueOrgNames.contains(org.getName())) {
                results.add(org);
            }
        }
    
        int limitToKeepTrack = 0;
        while (orgPage.hasNextPage()) {
            limitToKeepTrack += 50;
            organizationsQuery = orgServ.newOrganizationsQueryBuilder()
                    .pagedRequest(com.atlassian.servicedesk.api.util.paging.SimplePagedRequest.paged(limitToKeepTrack, limitToKeepTrack + 50))
                    .serviceDeskId(serviceDeskId)
                    .build();
    
            orgPage = orgServ.getOrganizations(proxyUser, organizationsQuery);
    
            for (com.atlassian.servicedesk.api.organization.CustomerOrganization org : orgPage.getResults()) {
                if (valueOrgNames.contains(org.getName())) {
                    results.add(org);
                }
            }
        }
    
        return results;
    }
    def getLocalOrganizations = { jIssue, value ->
        def serviceDeskManagerAdapter = com.atlassian.jira.component.ComponentAccessor.getOSGiComponentInstanceOfType(com.exalate.compatibility.api.IServiceDeskManagerAdapter.class)
        Integer serviceDeskId = serviceDeskManagerAdapter.getServiceDeskIdForProject(jIssue.getProjectObject());
        if (serviceDeskId == null) {
            log.error("Service desk in not available for project with id " + jIssue.getProjectId());
            return null;
        }
    
        List<String> valueOrgNames = com.google.common.collect.Lists.newArrayList();
        if (value instanceof List && ((List) value).size() > 0 && ((List) value).get(0) instanceof com.atlassian.servicedesk.api.organization.CustomerOrganization) {
            return value;
        }
    
        if(value instanceof com.atlassian.servicedesk.api.organization.CustomerOrganization){
            return com.google.common.collect.Lists.newArrayList(value);
        }
    
        if (value instanceof List && ((List) value).size() > 0 && ((List) value).get(0) instanceof String) {
            valueOrgNames = (List<String>)value;
        }
    
        if (value instanceof List && ((List) value).size() > 0 && ((List) value).get(0) instanceof com.exalate.api.domain.hubobject.IHubOrganization) {
            List<com.exalate.api.domain.hubobject.IHubOrganization> organizations = (List<com.exalate.api.domain.hubobject.IHubOrganization>) value;
            valueOrgNames = com.google.common.collect.Lists.newArrayList(com.google.common.collect.Iterables.transform(organizations, new com.google.common.base.Function<com.exalate.api.domain.hubobject.IHubOrganization, String>() {
                public String apply(com.exalate.api.domain.hubobject.IHubOrganization org) {
                    return org.getOrganizationName();
                }
            }));
        }
    
        if(value instanceof String){
            valueOrgNames = com.google.common.collect.Lists.newArrayList(value.toString());
        }
    
        if(value instanceof com.exalate.api.domain.hubobject.IHubOrganization){
            valueOrgNames = com.google.common.collect.Lists.newArrayList(((com.exalate.api.domain.hubobject.IHubOrganization)value).getOrganizationName());
        }
        return toCustomerOrganizations(proxyUser, serviceDeskId, valueOrgNames);
    }
    def setOrganizations = { remoteCf ->
        def remoteOrgs = remoteCf.value
        def customFieldManager = com.atlassian.jira.component.ComponentAccessor.customFieldManager
        def cf = customFieldManager.getCustomFieldObject(issue.customFields.Organizations.id as Long)
        def issueManager = com.atlassian.jira.component.ComponentAccessor.issueManager
        def jIssue = issueManager.getIssueObject(issue.id as Long)
        def localOrgs = getLocalOrganizations(jIssue, remoteOrgs)
        if (cf.getValue(jIssue) == null)    cf.customFieldType.createValue(cf, jIssue, localOrgs)
        else {
            cf.customFieldType.updateValue(cf, jIssue, localOrgs)
        }
    }
    if(firstSync){
        Epic.CreateIssue.create(
                replica,
                issue,
                syncRequest,
                nodeHelper,
                issueBeforeScript,
                remoteReplica,
                traces,
                blobMetadataList) {
    
            setOrganizations(replica.customFields.Organizations)
            return null
        }
    } else {
        setOrganizations(replica.customFields.Organizations)