Issue with attachment upload to new page and removal from old page

Scenario:
Upon upload attachment event listener trigger, I have a logic to remove the attachment from the page and upload the same attachment to a new page in another space.

Below is the code to copy the attachment to the new page:

        attachmentCopy = new Attachment(attachment.getFileName()+"-QUARANTINE",attachment.getType(), attachment.getFileSize(), null);
		InputStream inputStream = attachmentManager.getAttachmentData(attachment);
		attachmentCopy.setFileSize(attachment.getFileSize());
		attachmentCopy.setLastModificationDate(attachment.getCurrentDate());
		attachmentCopy.setContent(childPage);
		
		try {
			attachmentManager.saveAttachment(attachmentCopy, null, inputStream);
		} catch (IOException e) {
			log.error("attachment save failed!!!");
			e.printStackTrace();
		}		

and now I have to delete attachment from the old page.

		if(attachment.getVersion() > 1){
			log.debug("version > 1 removing version");
			attachmentManager.removeAttachmentVersionFromServer(attachment);	
		} else {
			log.debug("version = 1 removing attachment");
			attachmentManager.removeAttachmentFromServer(attachment);	
		}

Deleting a version of the attachment works fine, but removing the whole attachment gives an error.
This is the error which throws up when all the transactions are over:

WARN [http-nio-8090-exec-10] [confluence.impl.hibernate.ConfluenceHibernateTransactionManager] doRollback Performing rollback. Transactions:
->[null]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT (Session #1192470252)
– url: /pages/doattachfile.action | traceId: 4d49bc4bc00068d6 | userName: admin | referer: http://:8090/pages/viewpageattachments.action?pageId=4227&sortBy=date&highlight=file.txt&
ERROR [http-nio-8090-exec-10] [atlassian.confluence.servlet.ConfluenceServletDispatcher] sendError Could not execute action
– url: /pages/doattachfile.action | traceId: 4d49bc4bc00068d6 | userName: admin | referer: http://:8090/pages/viewpageattachments.action?pageId=4227&sortBy=date&highlight=file.txt&
java.lang.NullPointerException: Attachments must have a container ContentEntityObject
at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:226)
at com.atlassian.confluence.event.events.content.attachment.AttachmentEvent.(AttachmentEvent.java:41)
at com.atlassian.confluence.event.events.content.attachment.GeneralAttachmentBatchUploadCompletedEvent.(GeneralAttachmentBatchUploadCompletedEvent.java:22)
at com.atlassian.confluence.event.events.content.attachment.AttachmentBatchUploadCompletedEvent.(AttachmentBatchUploadCompletedEvent.java:21)
at com.atlassian.confluence.pages.DefaultAttachmentManager.saveAttachments(DefaultAttachmentManager.java:197)
at com.atlassian.confluence.pages.DefaultAttachmentManager.saveAttachments(DefaultAttachmentManager.java:161)
at com.atlassian.confluence.pages.DelegatorAttachmentManager.saveAttachments(DelegatorAttachmentManager.java:156)
at com.atlassian.confluence.pages.CachingAttachmentManager.saveAttachments(CachingAttachmentManager.java:209)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:302)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)

Can someone please let me know what’s wrong with this?

In what context is this running?
Try wrapping the whole in a transaction callback:

@Autowired
private TransactionTemplate transactionTemplate;
.......
transactionTemplate.execute(new TransactionCallback<Void>() {
    @Override
    public Void doInTransaction() {
        //your code
    }
});

Depending on confluence version you might need to use @ComponentImport or in atlassian-plugin.xml

Thanks for the response @Panos.

In what context is this running?

I have an event listener for attachment upload and i’m doing this from there.

@autowired did not work for transactionTemplate. Also tried,

@ComponentImport
protected TransactionTemplate transactionTemplate;

public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}

getting a null pointer here:

transactionTemplate.execute(new TransactionCallback() {…

Event listener runs in separate thread. You need that transaction template. Do you use scanned and component import?

Do you use scanned and component import?

Yes the class is Scanned.

@Scanned
public class EventsListener implements DisposableBean{

Are you injecting the template? Post the constructor along with all class variables

I’m injecting using the setter. Constructor is default no args.

@ComponentImport
protected TransactionTemplate transactionTemplate;

public void setTransactionTemplate(TransactionTemplate transactionTemplate) {
this.transactionTemplate = transactionTemplate;
}

Thought this would have the same effect.

Setter injection is way too old. I don’t think it works. Use constructor injection