Issue
I have an activity class that is annotated as a component that calls an action class:
@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = NonRetryableException.class)
public ExecuteTemplateResponse executeTemplate(ExecuteTemplateRequest request)
{
actionExecutionContext = action.execute(actionExecutionContext);
}
My action class is also annotated with @Component and has the following execute method:
@Transactional(propagation = Propagation.MANDATORY)
@Override
public ActionExecutionContext execute(ActionExecutionContext actionExecutionContext)
{
iogl = ioglDao.create(iogl);
return actionExecutionContext;
}
The ioglDao class is annotated as @Repository and has the following create method:
@Transactional(propagation = Propagation.MANDATORY)
@Override
public InventoryOwnerGroupLocation create(InventoryOwnerGroupLocation iogl)
{
// injected
Session session = sessionFactory.getCurrentSession();
session.save(iogl);
return iogl;
}
I believe that the Transaction should propagate from the Service Layer to the dao class, but it seems it's not. I get the No existing transaction found for transaction marked with propagation 'mandatory' Exception.
Why isn't the transaction propagating to my DAO classes?
EDIT: added all of the activity class
@Service("FASelfServiceMappingService")
@Component
public class ExecuteTemplateActivity extends Activity
{
private final static Logger logger = Logger.getLogger(ExecuteTemplateActivity.class);
// mapper framework to interact with DynamoDB database
private final DynamoDBMapper dynamoDBMapper;
// class to convert external models to internal models
private final InternalModelToDynamoDBModelConverter internalToDynamoDBConverter;
private final InternalModelToOracleModelConverter internalToOracleConverter;
private final CoralModelToInternalModelConverter coralToInternalConverter;
// class to generate list of actions
private final ActionGenerator actionGenerator;
// status constants
private static final String STATUS_COMPLETED = "COMPLETED";
private static final String STATUS_FAILED = "FAILED";
@Inject
public ExecuteTemplateActivity(InternalModelToDynamoDBModelConverter internalToDynamoDBConverter,
InternalModelToOracleModelConverter internalToOracleConverter,
CoralModelToInternalModelConverter coralToInternalConverter,
ActionGenerator actionGenerator,
DynamoDBMapper dynamoDBMapper)
{
this.internalToDynamoDBConverter = internalToDynamoDBConverter;
this.internalToOracleConverter = internalToOracleConverter;
this.coralToInternalConverter = coralToInternalConverter;
this.actionGenerator = actionGenerator;
this.dynamoDBMapper = dynamoDBMapper;
}
@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = NonRetryableException.class)
@Operation("ExecuteTemplate")
public ExecuteTemplateResponse executeTemplate(ExecuteTemplateRequest request) throws RetryableException, NonRetryableException
{
try
{
logger.info("Input given: " + request);
// convert request input to an internal request
Request internalRequest = coralToInternalConverter.coralRequestToInternal(request);
logger.info("Successfully converted External Request to internal Request.");
String templateName = getTemplateName(internalRequest);
logger.info("Template Name extracted from the request: " + templateName);
Template template = getTemplateFromDynamo(internalRequest, templateName);
logger.info("Template read from dynamoDB table: " + template);
// Generate a map from string to Action objects associated with the retrieved template
List<Action> listOfActions = actionGenerator.generateActions(template.getActions());
logger.info("Actions generated for template " + templateName + ": " + listOfActions);
// Generate the action context for actions to pass to each other to keep track of state
ActionExecutionContext actionExecutionContext = internalToOracleConverter.inputsToActionExecutionContext(internalRequest.getInputs());
logger.info("Built ActionExecutionContext:" + actionExecutionContext);
// execute the actions
for (Action action : listOfActions)
{
actionExecutionContext = action.execute(actionExecutionContext);
}
logger.info("All actions executed successfully.");
// request was completed successfully, create request in Request table
String requestId = createRequestInDynamo(internalRequest, STATUS_COMPLETED);
ExecuteTemplateResponse executeTemplateResponse = new ExecuteTemplateResponse();
executeTemplateResponse.setRequestId(requestId);
logger.info("Service call "+ this.getClass() +" succeeded.");
return executeTemplateResponse;
}
catch (RetryableException re)
{
logger.error("Retryable Exception occurred in activity.", re);
throw re;
}
catch (NonRetryableException nre)
{
logger.error("NonRetryable Exception occurred in activity.", nre);
throw nre;
}
catch (Exception e)
{
logger.error("Unknown Exception occurred in activity.", e);
throw new NonRetryableException("Unexpected error", e);
}
}
/**
* extracts the templateName from the internalRequest
* @param internalRequest internal model of the request
* @return templateName
*/
private String getTemplateName(Request internalRequest)
{
Validate.notNull(internalRequest, "internalRequest must not be null.");
String templateName;
try
{
// extract template name from request
templateName = internalRequest.getTemplateName();
Validate.notNull(templateName, "templateName must not be null.");
}
catch (IllegalArgumentException iae)
{
createRequestInDynamo(internalRequest, STATUS_FAILED);
logger.error("Invalid input: templateName is null.");
throw new NonRetryableException("Invalid input: templateName is null.", iae);
}
return templateName;
}
/**
* Retrieves the template object associated with given templateName
* @param internalRequest internal model of request
* @param templateName name of template to retrieve
* @return Template object
*/
private Template getTemplateFromDynamo(Request internalRequest, String templateName)
{
Validate.notNull(internalRequest, "internalRequest must not be null.");
Validate.notNull(templateName, "templateName must not be null.");
Template template;
try
{
// read the template with given template name from Templates table
template = dynamoDBMapper.load(Template.class, templateName);
}
catch (DynamoDBMappingException ddbme)
{
createRequestInDynamo(internalRequest, STATUS_FAILED);
logger.error("Reading template from dynamoDB table failed.", ddbme);
throw new NonRetryableException("Incorrect class annotation or incompatible with class", ddbme);
}
catch (AmazonClientException ace)
{
createRequestInDynamo(internalRequest, STATUS_FAILED);
logger.error("Reading template from dynamoDB table failed.", ace);
throw new RetryableException("Error when loading template from dynamoDB", ace);
}
return template;
}
EDIT:
Transaction Manager configuration:
<tx:annotation-driven transaction-manager="txManager"
mode="proxy" proxy-target-class='true' />
<bean id="txManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
Solution
It is maybe a problem related to your Spring configuration. Did you follow the guide at http://docs.spring.io/autorepo/docs/spring/4.2.x/spring-framework-reference/html/transaction.html? Can you show how you configure Spring transaction management ?
Answered By - Vladimiro Corsi
Answer Checked By - Cary Denson (JavaFixing Admin)