Forums

Articles
Create
cancel
Showing results for 
Search instead for 
Did you mean: 

Create Confluence page from JIRA

Erik Gotera
Contributor
February 14, 2019

Hello,

I'm trying from a JIRA addon communicate with Confluence and realize several actions like: create a page, attach files, etc.

I'm using the following code to do the above actions:

final ApplicationLink conflLink = applicationLinkService.getPrimaryApplicationLink(ConfluenceApplicationType.class); 

ApplicationLinkRequestFactory authenticatedRequestFactory = conflLink.createImpersonatingAuthenticatedRequestFactory();

....
public HashMap<String, String> createPage(ApplicationLinkRequestFactory authenticatedRequestFactory, Issue issue, JSONObject newPage) throws CredentialsRequiredException, ResponseException {
final HashMap<String, String> datosPage = new HashMap<String, String>();
final Issue issueFinal = issue;

authenticatedRequestFactory
.createRequest(Request.MethodType.POST, REQUEST_URL)
.addHeader("Content-Type", "application/json")
.setRequestBody(newPage.toString())
.execute(new ResponseHandler<Response>() {
@Override
public void handle(Response response) throws ResponseException {
if(response.getStatusCode() != HttpURLConnection.HTTP_OK) {
try {
throw new Exception(response.getResponseBodyAsString());
} catch (Exception e) {
log.error(e.getMessage());
String commentBody = i18nResolver.getText("val.error.create.page") + e.getMessage();
createComment(issueFinal, commentBody);
}
}
else {
HashMap<String, Object> responsePage = jsonToMap(response.getResponseBodyAsString());
datosPage.put("id",(String) responsePage.get("id"));
datosPage.put("title", (String) responsePage.get("title"));

HashMap<String, Object> dataLinks = stringMapToHashMap((StringMap) responsePage.get("_links"));

String url = dataLinks.get("base") + (String) dataLinks.get("webui");
datosPage.put("url", url);

}
}
});
return datosPage;
}

 And this code worked well but sometimes I get the exception:

ResponseException - java.net.SocketTimeoutException: Read timed out

 

I tried to increase the Socket timeout in Confluence but still happen.

 

There is another way to make communication between JIRA and Confluence?

How I can resolve that exception problem?

 

Thanks in advance!

 

3 answers

1 accepted

2 votes
Answer accepted
Erik Gotera
Contributor
February 21, 2019

I found the solution.

In the authenticatedRequestFactory parameter add the method setSoTimeout:

 

authenticatedRequestFactory
.createRequest(Request.MethodType.POST, REQUEST_URL)
.addHeader("Content-Type", "application/json")
.setRequestBody(newPage.toString())
.setSoTimeout(100000)
.execute(.....
0 votes
Najjar _Innovura_
Atlassian Partner
June 14, 2020

Hi Erik,

We launched a new app that allows you to create pages from templates through Jira Workflow post-function and store the Confluence page in a Jira customfield to apply more actions like:

Workflow postfuntions

  • Update page permissions
  • Update page content
  • Update page title

Workflow conditions

  • Check if page was modified after a certain status transition
  • Check if page still has a placeholder

And so much more.

Please give it a try, I believe it would streamline alot of repeated effort on your team

Jira Confluence Workflow Extensions (JCWE) 

Give it a try I am confident you'll love it.

If you have any inquires or requests please drop me an email at admin@innovura.io

0 votes
Marty
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
February 14, 2019

Hi Erik,

usually a java.net.SocketTimeoutException: Read timed out means that the server (or client) was listening but didn't receive anything during the specified time. 

If the server is the problem it could be under load when the problem occurs.  Do you see anything in the logs when you see the timeout?

If the client is the problem, can you try increasing the timeout on the client side?

I hope that helps!

Erik Gotera
Contributor
February 15, 2019

Hi Martyn,

Thanks for the answer.

The procedure I'm doing is the following:

1. Search for a page in a Space, is not exist I create the page and get the pageId, if exist I get the pageId.

2. With the pageId attach a file in the page.

 

In the test, the page is created but the file is not attached.

In the Confluence logs there is only one error:

ERROR [scheduler_Worker-7] [atlassian.core.task.AbstractErrorQueuedTaskQueue] handleException com.atlassian.mail.MailException: javax.mail.SendFailedException: Invalid Addresses; nested exception is: com.sun.mail.smtp.SMTPAddressFailedException: 501 5.1.3 Invalid address com.atlassian.mail.MailException: javax.mail.SendFailedException: Invalid Addresses; nested exception is: com.sun.mail.smtp.SMTPAddressFailedException: 501 5.1.3 Invalid address

Can be this the cause of the exception?

 

Thanks!

Like • Marty likes this
Marty
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
February 15, 2019

I think the email address is unlikely to be related since the stack trace looks like Confluence is trying to send an email but is unable to.

In the code above I can see where you are attempting to create a page but not where you are attempting to create the attachment?  You may need to make more API call(s) to upload an attachment and associate it with the page.

Erik Gotera
Contributor
February 15, 2019

Hi Martyn,

 

Here is all the code:

 

//Si está vacío lo creamos
if(existPageId.isEmpty())
{
String wikiPageContent = principalUtils.createWikiContent(issue);
JSONObject newPage = principalUtils.defineConfluencePage(finalNamePage,wikiPageContent,wikiSpace, parentPageId);

datosNewPage = principalUtils.createPage(authenticatedRequestFactory, issue, newPage);
if(!datosNewPage.isEmpty())
{
existPageId = datosNewPage.get("id");
}
}

//Enviamos el/los adjuntos a Confluence.
addAttachmentsToConfluence(authenticatedRequestFactory, issue, map, existPageId, nameNewAttachments);
private void addAttachmentsToConfluence(ApplicationLinkRequestFactory authenticatedRequestFactory, Issue issue, Map map, String existPageId, List<String> nameNewAttachments) throws RemoveException, CredentialsRequiredException, ResponseException, UnsupportedEncodingException {

List<ChangeItemBean> changes = (List<ChangeItemBean>) map.get("changeItems");

Collection<Attachment> attachmentList = issue.getAttachments();

List<File> fileList = new ArrayList<File>();

for(Attachment attachment : attachmentList)
{
if(nameNewAttachments.contains(attachment.getFilename()))
{
String filePath = PathUtils.joinPaths(ComponentAccessor.getAttachmentPathManager().getDefaultAttachmentPath(), issue.getProjectObject().getKey(), issue.getKey(), attachment.getId().toString());
File file = new File(filePath);
if (file.exists()) {
sendToConfluence(authenticatedRequestFactory, attachment, file, issue, existPageId);
fileList.add(file);
attachmentManager.deleteAttachment(attachment);
}
}
}
}


private void sendToConfluence(ApplicationLinkRequestFactory authenticatedRequestFactory, Attachment attachment, File file, Issue issue, String existPageId) throws CredentialsRequiredException, ResponseException, UnsupportedEncodingException {

final Issue issueFinal = issue;

RequestFilePart requestFilePart = new RequestFilePart(attachment.getMimetype(), attachment.getFilename(), file, "file");
List<RequestFilePart> fileParts = new ArrayList<RequestFilePart>();
fileParts.add(requestFilePart);


//COMPROBAMOS SI YA EXISTE EL ARCHIVO
String attachmentId = principalUtils.existAttachmentByName(authenticatedRequestFactory, existPageId, URLEncoder.encode(attachment.getFilename(), "UTF-8"));

//Si el archivo no existe lo incluimos en la página
if(attachmentId.isEmpty())
{
authenticatedRequestFactory
.createRequest(Request.MethodType.POST, "rest/api/content/" + existPageId + "/child/attachment")
.addHeader("X-Atlassian-Token", "no-check")
.setFiles(fileParts)
.execute(new ResponseHandler<Response>() {
@Override
public void handle(Response response) throws ResponseException {
if (response.getStatusCode() != HttpURLConnection.HTTP_OK) {
try {
throw new Exception(response.getResponseBodyAsString());
} catch (Exception e) {
log.error(e.getMessage());
String commentBody = i18nResolver.getText("val.error.add.attachment.confluence") + e.getMessage();
principalUtils.createComment(issueFinal, commentBody);
}
}
}
});
}
else
{
//En caso de existir lo actualizamos.
authenticatedRequestFactory
.createRequest(Request.MethodType.POST, "rest/api/content/" + existPageId + "/child/attachment/"+attachmentId+"/data")
.addHeader("X-Atlassian-Token", "no-check")
.setFiles(fileParts)
.execute(new ResponseHandler<Response>() {
@Override
public void handle(Response response) throws ResponseException {
if (response.getStatusCode() != HttpURLConnection.HTTP_OK) {
try {
throw new Exception(response.getResponseBodyAsString());
} catch (Exception e) {
log.error(e.getMessage());
String commentBody = i18nResolver.getText("val.error.update.attachment.confluence") + e.getMessage();
principalUtils.createComment(issueFinal, commentBody);
}
}
}
});
}
}
Marty
Atlassian Team
Atlassian Team members are employees working across the company in a wide variety of roles.
February 15, 2019

It looks like you're getting the attachments from a Jira Issue?  

Erik Gotera
Contributor
February 15, 2019 edited

Yes, the addon is a Post Function that gets the attachment added in the transition and sends it to Confluence.

Suggest an answer

Log in or Sign up to answer