package org.qi4j.library.struts2;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import org.qi4j.api.injection.scope.Structure;
import org.qi4j.api.unitofwork.UnitOfWork;
import org.qi4j.api.unitofwork.UnitOfWorkFactory;
/**
* <p>An interceptor to be used to start a UnitOfWork if one has not yet been started. If this interceptor creates a
* new UnitOfWork it will also add a PreResultListener to make sure the unit of work is completed or discarded before
* the result is executed. This is important so that the rendering of the result does not make any changes to the
* entities it is dealing with (we can maybe make this an option, to keep the UnitOfWork open until the invocation stack
* returns to this interceptor or if it should use the PreResultListener, but for now I like the PreResultListener
* better as it is safer).</p>
*
* <p>When a new UnitOfWork is created by this interceptor a decision must be made when closing it whether to discard
* the UnitOfWork or complete it. For now, if the resultCode is "success", we complete the UnitOfWork, otherwise we
* discard it. There are many things we can do here to make it more flexible, e.g. allow the user to specify result
* codes to complete or, conversely, codes that should result in the UnitOfWork being discarded. Since we have access
* to the action invocation we could also do something with annotations on the method to be executed to allow user to
* specify more specifically for that method what results should result in discards or completions.</p>
*/
public class UnitOfWorkInterceptor
extends AbstractInterceptor
{
private static final long serialVersionUID = 1L;
@Structure
private UnitOfWorkFactory uowf;
@Override
public String intercept( ActionInvocation invocation )
throws Exception
{
boolean createdUnitOfWork = false;
UnitOfWork uow;
if (!uowf.isUnitOfWorkActive())
{
uow = uowf.newUnitOfWork();
createdUnitOfWork = true;
} else
{
uow = uowf.currentUnitOfWork();
}
String resultCode = null;
try
{
resultCode = invocation.invoke();
}
finally
{
if( createdUnitOfWork && uow.isOpen() )
{
if( shouldComplete( invocation, resultCode ) )
{
uow.complete();
}
else
{
uow.discard();
}
}
}
return resultCode;
}
protected boolean shouldComplete( ActionInvocation invocation, String resultCode )
{
return Action.SUCCESS.equals( resultCode );
}
}