[closed]How can i add my own SOAP API in JIRA?

xu zhijian March 21, 2012

Hi all,

I want to write some soap apis for jira in java . However, I can't find how to add/merge my own apis to jira's soap api. Thanks very much .

2 answers

1 accepted

Comments for this post are closed

Community moderators have prevented the ability to post new answers.

Post a new question

1 vote
Answer accepted
Radek Kantor
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 21, 2012

Write own SOAP service interface/implementation and corresponding remote beans as JIRA plugin. If you deploy plugin, there will be separated WSDL with your service extensions method.

In atlassian-plugin.xml use something like this:

<rpc-soap key="extension-soap-service" name="Extension SOAP Service" class="com.my.company.jira.plugin.rpc.soap.ExtensionSoapServiceImpl">
    	<description>Extension SOAP Service.</description>
    	<service-path>extensionsoapservice</service-path>
    	<published-interface>com.my.company.jira.plugin.rpc.soap.ExtensionSoapService</published-interface>
	</rpc-soap>

If you need more help, I can provide example code.

According me extend existing standard JIRA SOAP by adding/overwriting some methods is not good way, to have all functionality in one wsdl. You shoul implement it separable as plugin.

Nic Brough -Adaptavist-
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
March 21, 2012

Completely agree - that's exactly why I renamed my plugin.

The existing off-the-shelf SOAP plugin was provided as standard and I could point people at the standard documentation and tell them it was supported. My plugin then co-existed as a separate interface on a different url, so those who needed it could use it. I know it duplicated all the existing methods in the standard one, but that meant the people who did need the additional calls didn't have to use two interfaces.

xu zhijian March 22, 2012

To xrakan:

Actually what i want to do is write my own SOAP API to fetch the issue history or change history, and I find the api provided as Java API in com.atlassian.jira.issue.history/changehistory package, so could you give me some examples about extension soap service , or some related document for learning . Thank you very much .

Radek Kantor
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 22, 2012

bean RemoteCustomFieldOption

package com.my.company.jira.plugin.rpc.soap.beans;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

public class RemoteCustomFieldOption 
{
    private Long sequence;
    private String value;

    public RemoteCustomFieldOption()
    {
    }

	/** Construct a CustomField value proxy object.
	 * @param sequence of the CustomField option.
	 * @param value string representing the value of the CustomField option.
	 */
    public RemoteCustomFieldOption(Long sequence, String value)
    {
    	this.sequence = sequence;
    	this.value = value;
    }

    public Long getSequence()
    {
        return sequence;
    }

    public void setSequence(Long sequence) 
    {
        this.sequence = sequence;
    }
    
    public String getValue()
    {
        return value;
    }

    public void setValue(String value)
    {
        this.value = value;
    }

    public boolean equals(Object o)
    {
        if (!(o instanceof RemoteCustomFieldOption))
        {
            return false;
        }
        RemoteCustomFieldOption rcfo = (RemoteCustomFieldOption) o;
        return new EqualsBuilder()
                .append(getSequence(), rcfo.getSequence())
                .append(getValue(), rcfo.getValue())
                .isEquals();
    }

    public int hashCode()
    {
        return new HashCodeBuilder(755, 13)
                .append(getSequence())
                .append(getValue())
                .toHashCode();
    }

}

Radek Kantor
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 22, 2012

interface ExtensionSoapService

package com.my.company.jira.plugin.rpc.soap;

import com.atlassian.jira.rpc.exception.RemoteException;
import com.atlassian.jira.rpc.exception.RemoteAuthenticationException;
import com.atlassian.jira.rpc.exception.RemotePermissionException;

import com.my.company.jira.plugin.rpc.soap.beans.RemoteCustomFieldOption;

public interface ExtensionSoapService {

	/** Login method returns authentication token.
	 * @param username JIRA user name.
	 * @param password JIRA password.
	 * @return Authentication token.
	 * @throws RemoteException, RemoteAuthenticationException
	 */
	public String login(String username, String password) 
		throws RemoteException, RemoteAuthenticationException;

	/** Logout method.
	 * @param token JIRA user authentication token.
	 * @return Authentication token.
	 * @throws RemoteException
	 */
	public boolean logout(String token) 
		throws RemoteException;
	
	/** Method lists CustomField options.
	 * @param token The authentication token. 
	 * @param customfieldId The string ID of an existing custom field,
	 * of the form 'customfield_[id]' where [id] is the database ID of
	 * the custom field.  This ID can be determined from the database,
	 * or by viewing a custom field in the admin interface, and copying
	 * its ID from the URL.
	 * @param projectId Project ID to define context, use some value
	 * if CustomField is not scoped by project.
	 * @param issueTypeId IssueType ID to define context, use some value
	 * if CustomField is not scoped by issue type.
	 * @return Array of RemoteCustomFieldOption objects.
	 * @throws RemoteException, RemoteAuthenticationException, RemotePermissionException
	 */
	public RemoteCustomFieldOption[] getCustomFieldOptions(String token, 
			String customfieldId, Long projectId, String issueTypeId) 
		throws RemoteException, RemoteAuthenticationException, RemotePermissionException;

}
Radek Kantor
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 22, 2012

implementation ExtensionSoapServiceImpl

package com.my.company.jira.plugin.rpc.soap;

import java.util.ArrayList;
import java.util.List;

import com.atlassian.jira.issue.CustomFieldManager;
import com.atlassian.jira.issue.context.IssueContext;
import com.atlassian.jira.issue.context.IssueContextImpl;
import com.atlassian.jira.issue.customfields.option.Option;
import com.atlassian.jira.issue.customfields.option.Options;
import com.atlassian.jira.issue.fields.CustomField;
import com.atlassian.jira.issue.fields.config.FieldConfig;
import com.atlassian.jira.rpc.auth.TokenManager;
import com.atlassian.jira.rpc.exception.RemoteAuthenticationException;
import com.atlassian.jira.rpc.exception.RemotePermissionException;
import com.atlassian.jira.rpc.exception.RemoteException;
import com.atlassian.jira.rpc.soap.beans.RemoteIssue;

import com.ness.jira.plugin.rpc.soap.beans.RemoteCustomFieldOption;

public class ExtensionSoapServiceImpl implements ExtensionSoapService {

	private final CustomFieldManager customFieldManager;
	private final TokenManager tokenManager;
	
	public ExtensionSoapServiceImpl(CustomFieldManager customFieldManager, TokenManager tokenManager) {
		this.customFieldManager = customFieldManager;
		this.tokenManager = tokenManager;
	}
	
	public String login(String username, String password) 
		throws RemoteException, RemoteAuthenticationException {
		return tokenManager.login(username, password);
	}
	
	public boolean logout(String token) 
		throws RemoteException {
		return tokenManager.logout(token);
    }

Radek Kantor
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 22, 2012

Hi, below is example of SOAP extension. Implemented new method to list all custom field options, not only selected one (select, check box CF Type).

New service WSDL after plugin deploy will be available on address: http://localhost:8080/rpc/soap/extensionsoapservice?wsdl

Sorry for cut/paste the code, but Im unable attach java, xml files, only image formats are supported.

Radek Kantor
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 22, 2012

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 key="extension-soap-component" name="Extension SOAP Component" class="com.my.company.jira.plugin.rpc.soap.ExtensionSoapServiceImpl">
  		<interface>com.my.company.jira.plugin.rpc.soap.ExtensionSoapService</interface> 
  	</component>
    
    <rpc-soap key="extension-soap-service" name="Extension SOAP Service" class="com.my.company.jira.plugin.rpc.soap.ExtensionSoapServiceImpl">
    	<description>Extension SOAP Service.</description>
    	<service-path>extensionsoapservice</service-path>
    	<published-interface>com.my.company.jira.plugin.rpc.soap.ExtensionSoapService</published-interface>
	</rpc-soap>
    
</atlassian-plugin>

Radek Kantor
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 22, 2012

continue implementation

public RemoteCustomFieldOption[] getCustomFieldOptions(String token,
			String customfieldId, Long projectId, String issueTypeId) 
		throws RemoteException, RemoteAuthenticationException, RemotePermissionException { 
		
		// Token permission check
		tokenManager.retrieveUserNoPermissionCheck(token);
		
		if (customfieldId == null) throw new RemoteException("CustomField ID is required.");
		
		List<RemoteCustomFieldOption> remoteCustomFieldOptions = new ArrayList<RemoteCustomFieldOption>();
		CustomField customField = customFieldManager.getCustomFieldObject(customfieldId);
		if (customField != null) {
			// Create the CustomField context, issue context to find the relevant field config,
			// CustomField with global context for any project and issue type is determined by any values 
			IssueContext iContext = new IssueContextImpl(projectId, issueTypeId);
			// Relevant field config of the CustomField for the give issue context
			FieldConfig fieldConfig = customField.getRelevantConfig(iContext);
			if (fieldConfig == null) throw new RemoteException("Wrong context (Project ID, Issue Type ID) for CustomField with ID: '" + customfieldId + "'.");
			Options opts = customField.getOptions(null, fieldConfig, null);
			if (opts != null) {
				Option opt;
				for (int i=0; i<opts.size(); i++) {
					opt = (Option)opts.get(i);
					remoteCustomFieldOptions.add(new RemoteCustomFieldOption(opt.getSequence(), opt.getValue()));
				}
				return remoteCustomFieldOptions.toArray(new RemoteCustomFieldOption[remoteCustomFieldOptions.size()]);
			}
			else {
				throw new RemoteException("CustomField with ID: '" + customfieldId + "' is not MultipleCustomFieldType, no options available.");
			}
		}
		else {
			throw new RemoteException("CustomField with ID: '" + customfieldId + "' not found.");
		}
	}

}

Radek Kantor
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 22, 2012

pom.xml

<?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.my.company.jira.plugin</groupId>
    <artifactId>SoapExtension</artifactId>
    <version>0.1</version>
    <name>Extension SOAP Service</name>
    <packaging>atlassian-plugin</packaging>
    <dependencies>
        <dependency>
            <groupId>com.atlassian.jira</groupId>
            <artifactId>atlassian-jira</artifactId>
            <version>${jira.version}</version>
            <scope>provided</scope>
        </dependency>        
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.6</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.atlassian.jira</groupId>
            <artifactId>jira-func-tests</artifactId>
            <version>${jira.version}</version>
            <scope>test</scope>
        </dependency>
        <dependency>
  			<groupId>com.atlassian.jira.plugins</groupId> 
  			<artifactId>atlassian-jira-rpc-plugin</artifactId>
  			<version>4.4.1</version>
  			<scope>provided</scope> 
  		</dependency>
    </dependencies>
   ...
<description>SOAP Service extension for Atlassian JIRA.</description>
</project>

xu zhijian March 22, 2012

Thanks for your quick respone. Thank you very much , and one more question as below :Can i get your project catalog tree?Or do you put the java files just in folder com/my/company/jira/plugin/ ?

Radek Kantor
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
March 22, 2012

my.company is only example :) so use structure/packages as you want, generate own plugin skeleton

\SoapExtension\pom.xml

\SoapExtension\src\main\resources\atlassian-plugin.xml

\SoapExtension\src\main\java\com\my\company\jira\plugin\rpc\soap\ ... interfacre and implementation

\SoapExtension\src\main\java\com\my\company\jira\plugin\rpc\soap\beans\ ... bean

xu zhijian March 29, 2012

To xrakan, I've written a simple SOAP Service like what you told me , and my customized bean is RemoteHistory. However, i can't find "RemoteHistory" in ...jira/rpc/soap/extensionsoapservice?wsdl, only find the method ”getChangeHistory“ which is a method of the interface instead .

1 vote
Nic Brough -Adaptavist-
Community Leader
Community Leader
Community Leaders are connectors, ambassadors, and mentors. On the online community, they serve as thought leaders, product experts, and moderators.
March 21, 2012

I've done something like this in Jira 3.9 - all I did was took the code for the SOAP/RPC plugin, renamed it slightly and added the functions to expose the calls I needed. I don't know if it's like that in 5.x, but that trick should hold true for 4.x

TAGS
AUG Leaders

Atlassian Community Events