package ca.corefacility.bioinformatics.irida.events;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.Ordered;

import ca.corefacility.bioinformatics.irida.config.repository.IridaApiRepositoriesConfig;
import ca.corefacility.bioinformatics.irida.events.annotations.LaunchesProjectEvent;

/**
 * Aspect used to create project events for methods annotated with event
 * annotations
 * 
 *
 * @see LaunchesProjectEvent
 */
@Aspect
public class ProjectEventAspect implements Ordered {
	private static final Logger logger = LoggerFactory.getLogger(ProjectEventAspect.class);
	private ProjectEventHandler eventHandler;

	public ProjectEventAspect(ProjectEventHandler eventListener) {
		this.eventHandler = eventListener;
	}

	@AfterReturning(value = "execution(public (!void) *(..)) &&  @annotation(eventAnnotation)", returning = "returnValue")
	public void handleProjectEvent(JoinPoint jp, LaunchesProjectEvent eventAnnotation, Object returnValue) {
		logger.trace("Intercepted method annotated with LaunchesProjectEvent " + jp.toString());
		eventHandler.delegate(new MethodEvent(eventAnnotation.value(), returnValue, jp.getArgs()));
	}

	@AfterReturning(value = "execution(public void *(..)) && @annotation(eventAnnotation)")
	public void handleProjectEventWithoutReturn(JoinPoint jp, LaunchesProjectEvent eventAnnotation) {
		logger.trace("Intercepted void method annotated with LaunchesProjectEvent " + jp.toString());
		eventHandler.delegate(new MethodEvent(eventAnnotation.value(), null, jp.getArgs()));
	}

	@Override
	public int getOrder() {
		return IridaApiRepositoriesConfig.TRANSACTION_MANAGEMENT_ORDER - 1;
	}
}

@@ -1672,16 +1672,908 @@
 ));%0A%09%7D%0A%0A
+%09/**%0A%09 * This event **must** happen outside of a transaction so that multiple%0A%09 * events happening at the same time do not result in a deadlock exception.%0A%09 * Example: when multiple sequencers are uploading sample data%0A%09 * simultaneously, they are all creating samples on the server. When the%0A%09 * samples are being created the project event for updating the project%0A%09 * modified time is fired many times simultaneously, so multiple clients are%0A%09 * trying to update the project at the same time. If that update is within a%0A%09 * transaction, at least one of those simultaneous updates fails, so the%0A%09 * client gets a report that creating the sample failed. Since we don't care%0A%09 * which thread wins the update (they should be setting the same updated%0A%09 * time down to at least the second), just make sure that this aspect is%0A%09 * being applied *outside* of the transaction.%0A%09 * %0A%09 * @return%0A%09 */%0A
 %09@Overri

Add comment explaining the order.