Index: lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/dao/hibernate/McUsrAttemptDAO.java =================================================================== diff -u -r45dc9d53a03937ef25d6a8fa6c383c046f5df9f3 -r3fec05d7118aa084eb47e46dddba34b472ff775d --- lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/dao/hibernate/McUsrAttemptDAO.java (.../McUsrAttemptDAO.java) (revision 45dc9d53a03937ef25d6a8fa6c383c046f5df9f3) +++ lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/dao/hibernate/McUsrAttemptDAO.java (.../McUsrAttemptDAO.java) (revision 3fec05d7118aa084eb47e46dddba34b472ff775d) @@ -66,7 +66,7 @@ @Override public void saveMcUsrAttempt(McUsrAttempt mcUsrAttempt) { - this.getHibernateTemplate().save(mcUsrAttempt); + this.getHibernateTemplate().saveOrUpdate(mcUsrAttempt); } @Override Index: lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/McLearningAction.java =================================================================== diff -u -rc369c0326857e08851d03a29d39d4337091f5253 -r3fec05d7118aa084eb47e46dddba34b472ff775d --- lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/McLearningAction.java (.../McLearningAction.java) (revision c369c0326857e08851d03a29d39d4337091f5253) +++ lams_tool_lamc/src/java/org/lamsfoundation/lams/tool/mc/web/McLearningAction.java (.../McLearningAction.java) (revision 3fec05d7118aa084eb47e46dddba34b472ff775d) @@ -29,6 +29,7 @@ import java.util.Map; import java.util.Set; import java.util.TreeMap; +import java.util.regex.Pattern; import javax.servlet.ServletContext; import javax.servlet.ServletException; @@ -64,7 +65,10 @@ import org.lamsfoundation.lams.web.session.SessionManager; import org.lamsfoundation.lams.web.util.AttributeNames; import org.lamsfoundation.lams.web.util.SessionMap; +import org.springframework.dao.DataIntegrityViolationException; +import com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException; + /** * @author Ozgur Demirtas */ @@ -326,7 +330,7 @@ mcGeneralLearnerFlowDTO.setUserOverPassMark(new Boolean(passed).toString()); mcGeneralLearnerFlowDTO.setPassMarkApplicable(new Boolean(mcContent.getPassMark() != null).toString()); - mcService.saveUserAttempt(mcQueUsr, selectedQuestionAndCandidateAnswersDTO); + McLearningAction.saveUserAttempt(mcQueUsr, selectedQuestionAndCandidateAnswersDTO); Integer numberOfAttempts = mcQueUsr.getNumberOfAttempts() + 1; mcQueUsr.setNumberOfAttempts(numberOfAttempts); @@ -393,7 +397,7 @@ //save user attempt List selectedQuestionAndCandidateAnswersDTO = buildSelectedQuestionAndCandidateAnswersDTO( learnerInput, new McTempDataHolderDTO(), mcContent); - mcService.saveUserAttempt(user, selectedQuestionAndCandidateAnswersDTO); + McLearningAction.saveUserAttempt(user, selectedQuestionAndCandidateAnswersDTO); McQueUsr mcQueUsr = getCurrentUser(toolSessionID); List learnerAnswersDTOList = mcService.buildLearnerAnswersDTOList(mcContent, mcQueUsr); @@ -725,11 +729,36 @@ List selectedQuestionAndCandidateAnswersDTO = buildSelectedQuestionAndCandidateAnswersDTO( learnerInput, new McTempDataHolderDTO(), mcContent); - mcService.saveUserAttempt(user, selectedQuestionAndCandidateAnswersDTO); + McLearningAction.saveUserAttempt(user, selectedQuestionAndCandidateAnswersDTO); return null; } + /** + * Makes a call to mcService.saveUserAttempt(). This method is designed purely for exception handling purposes. It + * needs to be performed inside Action class as otherwise Hibernate tries to flush the session which leads to another exception. + */ + private static void saveUserAttempt(McQueUsr user, List selectedQuestionAndCandidateAnswersDTO) { + try { + mcService.saveUserAttempt(user, selectedQuestionAndCandidateAnswersDTO); + + } catch (DataIntegrityViolationException e) { + + // log DB exceptions occurred due to creating non-unique McUsrAttempt. And propagate all the other exceptions + if (e.getRootCause() instanceof MySQLIntegrityConstraintViolationException) { + String rootCauseMessage = e.getRootCause().getMessage(); + + Pattern pattern = Pattern.compile("Duplicate entry.*attempt_unique_index"); + if ((rootCauseMessage != null) && pattern.matcher(rootCauseMessage).find()) { + logger.error("Prevented creation of McUsrAttempt which was not unique for user and question: " + rootCauseMessage); + return; + } + } + + throw e; + } + } + private static List parseLearnerAnswers(McLearningForm mcLearningForm, HttpServletRequest request) { String httpSessionID = mcLearningForm.getHttpSessionID(); SessionMap sessionMap = (SessionMap) request.getSession().getAttribute(httpSessionID);