PageManager Error when Copying Attachment

Hi all,

I’m trying to copy an attachment from one page to another with the onBlueprintCreateEvent however I keep seeing the error “Caused by: java.lang.NullPointerException” in the console.

I’m fairly certain it’s related to the PageManager but I’m not sure how to fix it. I’m setting the PageManager as described in Accessing Confluence Components.

Anyone have suggestions? Here’s my code:

import com.atlassian.confluence.plugins.createcontent.api.events.BlueprintPageCreateEvent;
import com.atlassian.event.api.EventListener;
import com.atlassian.event.api.EventPublisher;
import com.atlassian.confluence.pages.Page;
import com.atlassian.confluence.pages.PageManager;
import com.atlassian.confluence.pages.AbstractPage;
import com.atlassian.confluence.pages.Attachment;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class PiBlueprintListener {
	private static final Logger log = LoggerFactory.getLogger(PiBlueprintListener.class);

	public PiBlueprintListener(EventPublisher eventPublisher) {
		eventPublisher.register(this); //demonstration only
	}
	
	public PageManager pageManager;
    public void setPageManager(PageManager pageManager)
    {
        this.pageManager = pageManager;
    }
	
	@EventListener
	public void onBlueprintCreateEvent(BlueprintPageCreateEvent event){	

		Page targetPage = event.getPage();

    	String tempPageId = (String) event.getContext().get("tempPageId");
    	System.out.println("tempPageId: " + tempPageId);

		AbstractPage attachmentPage = this.pageManager.getAbstractPage(Long.parseLong(tempPageId));
       	Attachment attachment = attachmentPage.getAttachments().iterator().next();

       	targetPage.addAttachment(attachment);
       	}
}

FYI, the tempPageId is the id of the page where the attachment is stored and the targetPage is where I want the attachment to go.

you are trying to wire the pagemanager through setter, this is deprecated. Change the constructor to

public PiBlueprintListener(EventPublisher eventPublisher,PageManager pageManager) {
		eventPublisher.register(this); //demonstration only
        this.pageManager=pageManager;
	}

and remove the setter.

2 Likes

Thanks Panos, this worked but it’s only copying the attachment name, not the actual data so it appears to copy but when I click on the attachment it says there is no file. Any suggestions?

Use the copyAttachment from https://docs.atlassian.com/confluence/5.9.9/com/atlassian/confluence/pages/AttachmentManager.html

Thanks, but honestly, I can’t figure out how to use it. I don’t know java so I’ve spent hours trying to figure it out but I have no idea what I need to do. :frowning:

Change

AbstractPage attachmentPage = this.pageManager.getAbstractPage(Long.parseLong(tempPageId));
Attachment attachment = attachmentPage.getAttachments().iterator().next();

to

Page tempPage=pageManager.getPage(Long.parseLong(tempPageId));
attachmentManager.copyAttachments(tempPage, targetPage);

You make it look so easy :stuck_out_tongue: it caused a build failure so I tried passing the AttachmentManager into the listener but it also doesn’t work.

Here’s what I have:

public class PiBlueprintListener {

	private static final Logger log = LoggerFactory.getLogger(PiBlueprintListener.class);

	public PiBlueprintListener(EventPublisher eventPublisher, PageManager pageManager, AttachmentManager attachmentManager) {
		eventPublisher.register(this); 
		this.pageManager = pageManager;
		this.attachmentManager = attachmentManager;
	}

	public PageManager pageManager;
	public AttachmentManager attachmentManager;

	@EventListener
	public void onBlueprintCreateEvent(BlueprintPageCreateEvent event){

		Page targetPage = event.getPage();
		String tempPageId = (String) event.getContext().get("tempPageId");
		Page tempPage=pageManager.getPage(Long.parseLong(tempPageId));
		attachmentManager.copyAttachments(tempPage, targetPage);

	}
}

What is the error in this one and which import you sre using or attachment manager?

Hi @Panos,
I tried the same, but wanted to copy only 1 attachment

attachmentManager.copyAttachment(attachment, childPage);

and got this error:

Caused by: com.atlassian.confluence.pages.attachments.AttachmentDataStreamSizeMismatchException: Attachment data stream contains a different number of bytes to the declared size of the attachment. Expected: 0, actual: 33

Hi @sameer.v
I haven’t seen that error before. Is the attachment correctly saved in confluence and fetched? Because it expects 0 (???) bytes.
Post a little more of your code around the copyAttachment, e.g. how the attachment is fetched, how the page is fetched etc.
Also do some trivial debugging to see if that attachment is valid:
Compare size using getFileSize(), check if exists and displayed with getDownloadPath(), same with page.

I have an event listener listening to “AttachmentCreateEvent”. Once that event is fired, I need to be able to move / “copy to new - delete from old” the attachment (based on some conditions in its contents) to another Space’s page. That’s the code in my listener and its failing.
I also tried

Attachment copiedAttachment = uploadedAttachment.copyLatestVersion();
anotherSpacePage.addAttachment(copiedAttachment);

This does the copy. But the problem is copyLatestVersion does not make a copy of the attachment with all its contents and metadata. Seems like it does only so much:
> Attachment attachmentCopy = new Attachment();

    attachmentCopy.setImageDetailsDTO(new HashSet());
    attachmentCopy.setFileName(getFileName());
    attachmentCopy.setFileSize(getFileSize());
    attachmentCopy.setContentPropertiesFrom(this);
    attachmentCopy.setContentType(getContentType());

I ended up creating a new attachment and saving it to the new page. Code is something like:

attachmentCopy = new Attachment(attachment.getFileName(),attachment.getType(), attachment.getFileSize(), null);
InputStream inputStream = attachmentManager.getAttachmentData(attachment);
attachmentCopy.setFileSize(attachment.getFileSize());
attachmentCopy.setLastModificationDate(attachment.getCurrentDate());
attachmentCopy.setContent(childPage); // this is deprecated :frowning:

try {
attachmentManager.saveAttachment(attachmentCopy, null, inputStream);
} catch (IOException e) {
e.printStackTrace();
}

Any other better way ?