Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

How to make an RPC call from JIRA plugin to Confluence using Application Links

ClémentC January 12, 2012

Hi,

I'm working on JIRA 4.4.4 & Confluence 3.5.13

Until now, I used to make an RPC call to Confluence from my JIRA plugin using TrustedApps (with TrustedApplicationsManager) in order to retrieve a Confluence spaces list (the JIRA application was trusted from Confluence), like this :

XmlRpcHandler rpcClient = remoteQueryFactory.getXmlRpcHandler(xmlrpcUrl, user, trustedApplicationsManager);

result = rpcClient.execute(service + "." + method, parameters);

I'm currently trying to update this one in order to use Application Links, but I can't find out how to do it, and none documentation I found is helping me.

Does anyone could help me on this ?

Thank you in advance,

Regards,

--

Clément Capiaux

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
ClémentC January 17, 2012

I found the problem !

I was creating the ApplicationLinkRequest object omitting the base URL before "/rpc/xmlrpc/" and adding the service path. That's not correct, it has to be done as below :

ApplicationLinkRequest request = requestFactory.createRequest(MethodType.POST, aAppLink.getRpcUrl() + "/rpc/xmlrpc");

The method/parameters call are written in a XML message computed in the requestBody attribute of the ApplicationLinkRequest object (I give the complete class code at the bottom of this comment)

Besides, I managed to make my RPC call through ApplicationLinks, without no effort because the "execute" method of ApplicationLinkRequest object is returning a String, and through this, my Vector object returned from my Confluence RPC service is serialized in a XML String.

So I had to develop some bean classes in order to unmarshall the serialized XML in an appropriate object, in order to rewrite it as a Vector like the output of my RPC service method.

All these informations could be very helpful for anyone who would make a RPC call through ApplicationLinks in the future !

This is the code of my Java class realizing all this mechanism (the bean classes for XML unmarshalling are not shown but if needed, simply ask me :

package com.valiantys.jira.plugins.confluence.entitypicker.trustedapps;

import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;

import org.apache.log4j.Logger;

import com.atlassian.applinks.api.ApplicationLink;
import com.atlassian.applinks.api.ApplicationLinkRequest;
import com.atlassian.applinks.api.ApplicationLinkRequestFactory;
import com.atlassian.applinks.api.ApplicationLinkService;
import com.atlassian.sal.api.net.Request.MethodType;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.Dom4JDriver;

public class RemoteQueryLauncher {

    /**
     * class Logger.
     */
    private static final Logger LOG = Logger.getLogger(RemoteQueryLauncher.class);

    private final ApplicationLinkService appLinkService;

    private static XStream xstream;

    public RemoteQueryLauncher(final ApplicationLinkService aAppLinkService) {
        this.appLinkService = aAppLinkService;
    }

    public Object doLaunchQuery(final String service, final String method, final Vector parameters) throws Exception {

        Object result = null;

        if (this.xstream == null) {
            xstreamInit();
        }

        Iterable<ApplicationLink> appLinks = appLinkService.getApplicationLinks();
        if (appLinks != null) {
            for (Iterator<ApplicationLink> it = appLinks.iterator(); it.hasNext();) {
                ApplicationLink aAppLink = it.next();
                LOG.debug("Application link found : " + aAppLink.getName());

                ApplicationLinkRequestFactory requestFactory = aAppLink.createAuthenticatedRequestFactory();

                String url = aAppLink.getRpcUrl() + "/rpc/xmlrpc";
                LOG.debug("RPC service about to be called : " + url);

                // building Application Link request
                ApplicationLinkRequest request = requestFactory.createRequest(MethodType.POST, url);

                // setting request headers (as it was done before by XmlRpcHandler class, with call method through the TrustedAppsManager)
                request.addHeader("Accept", "text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2");
                request.setRequestContentType("text/xml");
                request.addHeader("Pragma", "no-cache");
                request.addHeader("Cache-Control", "no-cache");

                // building XML RPC message from the service path, the method name, and parameters values
                request.setRequestBody(computeRequestBody(service, method, parameters));

                String xml = request.execute();
                ConfluenceRpcResponse unmarshalledResponse = (ConfluenceRpcResponse) xstream.fromXML(xml, new ConfluenceRpcResponse());
                result = computeObjectFromResponse(unmarshalledResponse);

            }
        } else {
            LOG.debug("None application link has been found");
        }

        return result;

    }

    private String computeRequestBody(final String aService, final String aMethod, final Vector aParameters) {
        StringBuilder strBuilder = new StringBuilder();

        strBuilder.append("<?xml version=\"1.0\"?>");

        strBuilder.append("<methodCall>");
        strBuilder.append("<methodName>");
        strBuilder.append(aService + "." + aMethod);
        strBuilder.append("</methodName>");

        strBuilder.append("<params>");
        for (int i = 0; i < aParameters.size(); i++) {
            strBuilder.append("<param><value>");
            strBuilder.append(aParameters.get(i));
            strBuilder.append("</value></param>");
        }
        strBuilder.append("</params>");

        strBuilder.append("</methodCall>");

        return strBuilder.toString();
    }

    private Object computeObjectFromResponse(final ConfluenceRpcResponse unmarshalledResponse) {

        if (unmarshalledResponse != null && unmarshalledResponse.getParams() != null) {
            ResponseValue responseValue = unmarshalledResponse.getParams().get(0).getValue();

            if (responseValue.getArray() != null) {

                Vector<Hashtable<String, String>> vectorResponse = new Vector<Hashtable<String, String>>();

                for (DataValue aDataValue : responseValue.getArray().getData()) {
                    Hashtable<String, String> aComputedValue = new Hashtable<String, String>();
                    for (ResponseMember aMember : aDataValue.getStruct()) {
                        aComputedValue.put(aMember.getName(), aMember.getValue());
                    }
                    vectorResponse.add(aComputedValue);
                }
                return vectorResponse;

            } else if (responseValue.getStruct() != null) {
                Hashtable<String, String> hashtableResponse = new Hashtable<String, String>();

                for (ResponseMember aMember : responseValue.getStruct()) {
                    hashtableResponse.put(aMember.getName(), aMember.getValue());
                }
                return hashtableResponse;
            }

        }
        return null;
    }

    private static void xstreamInit() {
        xstream = new XStream(new Dom4JDriver());
        xstream = new XStream(new Dom4JDriver());
        xstream.autodetectAnnotations(true);

        xstream.alias("methodResponse", ConfluenceRpcResponse.class);
        xstream.alias("param", ResponseParam.class);
        xstream.alias("value", ResponseValue.class);
        xstream.alias("member", ResponseMember.class);
    }
}

Regards, and thank you Joseph for your help :)

Joe Clark
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
January 18, 2012

Great work solving the problem! :-)

1 vote
Joe Clark
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
January 15, 2012

This tutorial provides an example of how to Application Links to connection to Confluence from JIRA: https://developer.atlassian.com/display/JIRADEV/Plugin+Tutorial+-+Application+Links+in+JIRA

is it helpful?

ClémentC January 15, 2012

Hi Joseph,

Thank you for your answer ! I'm taking a look at it, and will tell you as soon as possible how it can helps.

Cheers

ClémentC January 15, 2012

I managed to prepare objects for my call, but I can't find how to build the URL (POST or GET), in order to make the RPC call I used to do like this :

XmlRpcHandler rpcClient = RemoteQueryFactory.getXmlRpcHandler(xmlrpcUrl, user, trustedApplicationsManager);

result = rpcClient.execute(service + "." + method, parameters);

Is there anyone who have done this yet ? Any help on how to build the Application Links query ?

For now, I tried to do it as below (I put the XML message built as it was done when I used the RPC client) :

ApplicationLinkRequest request = requestFactory.createRequest(MethodType.POST, "/rpc/xmlrpc/" + myRpcServicePath);
request.setRequestBody("<methodCall><methodName>myRpcServicePath.aMethodName</methodName><params><param><value>param1</value></param><param><value>param2</value></param></params></methodCall>");
result = request.execute();

, and I get a ResponseException like this :

com.atlassian.sal.api.net.ResponseException: Unexpected response received. Status code: 404

Any help will be appreciated :)

Joe Clark
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
January 16, 2012

Does the ApplicationLinkRequest type provide a way to see the full URL that will be used? The fact that the response you are getting is a 404 means that maybe the URL is not being constructed correctly?

Sachin Dhamale June 22, 2014

hi joseph;

https://developer.atlassian.com/display/JIRADEV/Plugin+Tutorial+-+Application+Links+in+JIRA

with this link i am able to get url of confluence page

i want to display whole page data instead of just url on jira issue tab panel

is this possible?

TAGS
AUG Leaders

Atlassian Community Events