@Retryable(include = OptimisticLockingFailureException.class, maxAttempts = 10) private void refreshUserSessions(String mail) { List<Session> cleanables = sessionRepo.findByMail(mail).stream() .filter(session -> !isTokenInProxy(session.getToken())) .collect(Collectors.toList()); logger.debug("will remove {} sessions for mail {}", cleanables.size(), mail); sessionRepo.deleteAll(cleanables); }
@Retryable(include = OptimisticLockingFailureException.class, maxAttempts = 10) public void removeSkills(String username, String skillName) throws UserNotFoundException, SkillNotFoundException, EmptyArgumentException { if (StringUtils.isEmpty(username) || StringUtils.isEmpty(skillName)) { logger.debug("Failed to modify skills: username or skillName empty"); throw new EmptyArgumentException("arguments must not be empty or null"); } User user = UserRepository.findByIdIgnoreCase(username); if (user == null) { logger.debug("Failed to remove {}'s skills: user not found", username); throw new UserNotFoundException("user not found"); } if (skillRepository.findByName(skillName) == null) { logger.debug("Failed to remove {}'s skill {}: skill not found", username, skillName); throw new SkillNotFoundException("skill not found"); } user.removeSkill(skillName); UserRepository.save(user); }
public void registerSkillSearch(Collection<KnownSkill> searchedSkills) throws IllegalArgumentException { if (searchedSkills.size() < 2) { logger.debug("Searched for less than two skills, cannot update mutual suggestions"); return; } for (KnownSkill s : searchedSkills) { List<KnownSkill> ts = searchedSkills.stream().filter(x -> !x.equals(s)).collect(Collectors.toList()); for (KnownSkill t : ts) { s.incrementSuggestion(t.getName()); } } try { skillRepository.saveAll(searchedSkills); } catch (OptimisticLockingFailureException e) { logger.error("Failed to register search for {} - optimistic locking error; will ignore search", searchedSkills.stream().map(KnownSkill::getName).collect(Collectors.joining(", "))); } logger.info("Successfully registered search for {}", searchedSkills.stream().map(KnownSkill::getName).collect(Collectors.joining(", "))); }
@Around("retryOnOptFailure()") public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable { int numAttempts = 0; do { numAttempts++; try { return pjp.proceed(); } catch (OptimisticLockingFailureException ex) { if (numAttempts > maxRetries) { //log failure information, and throw exception throw ex; } else { //log failure information for audit/reference //will try recovery } } } while (numAttempts <= this.maxRetries); return null; }
@Test public void jtaTransactionManagerWithExistingTransactionAndCommitException() throws Exception { UserTransaction ut = mock(UserTransaction.class); given(ut.getStatus()).willReturn(Status.STATUS_ACTIVE); final TransactionSynchronization synch = mock(TransactionSynchronization.class); willThrow(new OptimisticLockingFailureException("")).given(synch).beforeCommit(false); JtaTransactionManager ptm = newJtaTransactionManager(ut); TransactionTemplate tt = new TransactionTemplate(ptm); assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); try { tt.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { assertTrue(TransactionSynchronizationManager.isSynchronizationActive()); TransactionSynchronizationManager.registerSynchronization(synch); } }); fail("Should have thrown OptimisticLockingFailureException"); } catch (OptimisticLockingFailureException ex) { // expected } assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); verify(ut).setRollbackOnly(); verify(synch).beforeCompletion(); verify(synch).afterCompletion(TransactionSynchronization.STATUS_UNKNOWN); }
@Test public void transactionExceptionPropagatedWithCallbackPreference() throws Throwable { TransactionAttribute txatt = new DefaultTransactionAttribute(); MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); tas.register(exceptionalMethod, txatt); MockCallbackPreferringTransactionManager ptm = new MockCallbackPreferringTransactionManager(); TestBean tb = new TestBean(); ITestBean itb = (ITestBean) advised(tb, ptm, tas); checkTransactionStatus(false); try { itb.exceptional(new OptimisticLockingFailureException("")); fail("Should have thrown OptimisticLockingFailureException"); } catch (OptimisticLockingFailureException ex) { // expected } checkTransactionStatus(false); assertSame(txatt, ptm.getDefinition()); assertFalse(ptm.getStatus().isRollbackOnly()); }
/** * Map the passed exception to an error message. * Any potential exception (such as business exception) requiring a special message should be mapped here as well. */ public void error(Throwable e) { if (ExceptionUtil.isCausedBy(e, DataIntegrityViolationException.class)) { this.error("error_unique_constraint_violation"); } else if (ExceptionUtil.isCausedBy(e, OptimisticLockingFailureException.class)) { this.error("error_concurrent_modification"); } else if (ExceptionUtil.isCausedBy(e, AccessDeniedException.class)) { // works only if the spring security filter is before the exception filter, // that is if the exception filter handles the exception first. this.error("error_access_denied"); } else { this.error("status_exception_ko", getMessage(e)); log.error("====> !!ATTENTION!! DEVELOPERS should provide a less generic error message for the cause of this exception <===="); } }
/** * Give it a number of tries to update the event/meeting object into DB * storage if this still satisfy the pre-condition regardless some changes * in DB storage * * @param meeting * a SignupMeeting object. * @param currentTimeslot * a SignupTimeslot object. * @param lockAction * a boolean value * @return a SignupMeeting object, which is a refreshed updat-to-date data. * @throws Exception * throw if anything goes wrong. */ private SignupMeeting handleVersion(SignupMeeting meeting, SignupTimeslot currentTimeslot, boolean lockAction) throws Exception { for (int i = 0; i < MAX_NUMBER_OF_RETRY; i++) { try { meeting = signupMeetingService.loadSignupMeeting(meeting.getId(), userId, siteId); currentTimeslot = meeting.getTimeslot(currentTimeslot.getId()); if (currentTimeslot.isLocked() == lockAction) throw new SignupUserActionException(Utilities.rb .getString("someone.already.changed.ts.lock_status")); currentTimeslot.setLocked(lockAction); signupMeetingService.updateSignupMeeting(meeting,isOrganizer); return meeting; } catch (OptimisticLockingFailureException oe) { // don't do any thing } } throw new SignupUserActionException(Utilities.rb.getString("failed.lock_or_unlock_ts")); }
/** * Give it a number of tries to update the event/meeting object into DB * storage if this still satisfy the pre-condition regardless some changes * in DB storage * * @param meeting * a SignupMeeting object. * @param currentTimeslot * a SignupTimeslot object. * @param cancelAction * a boolean value * @return a SignupMeeting object, which is a refreshed updat-to-date data. * @throws Exception * throw if anything goes wrong. */ private SignupMeeting handleVersion(SignupMeeting meeting, SignupTimeslot currentTimeslot, boolean cancelAction) throws Exception { for (int i = 0; i < MAX_NUMBER_OF_RETRY; i++) { try { meeting = signupMeetingService.loadSignupMeeting(meeting.getId(), userId, siteId); this.signupEventTrackingInfo = new SignupEventTrackingInfoImpl(); this.signupEventTrackingInfo.setMeeting(meeting); currentTimeslot = meeting.getTimeslot(currentTimeslot.getId()); if (currentTimeslot.isCanceled() == cancelAction) throw new SignupUserActionException(Utilities.rb .getString("someone.already.changed.ts.cancel_status")); cancel(currentTimeslot, cancelAction); signupMeetingService.updateSignupMeeting(meeting,isOrganizer); return meeting; } catch (OptimisticLockingFailureException oe) { // don't do any thing } } throw new SignupUserActionException(Utilities.rb.getString("failed.cancel_or_restore_ts")); }
/** * Give it a number of tries to update the event/meeting object into DB * storage if this still satisfy the pre-condition regardless some changes * in DB storage */ private void handleVersion(SignupMeeting meeting, SignupTimeslot timeslot, SignupAttendee waiter) throws Exception { boolean success = false; for (int i = 0; i < MAX_NUMBER_OF_RETRY; i++) { try { meeting = reloadMeeting(meeting.getId()); prepareRemoveFromWaitingList(meeting, timeslot, waiter); signupMeetingService.updateSignupMeeting(meeting, isOrganizer); success = true; break; // add attendee is successful } catch (OptimisticLockingFailureException oe) { // don't do any thing } } if (!success) throw new SignupUserActionException(Utilities.rb.getString("someone.already.updated.db")); }
/** * Give it a number of tries to update the event/meeting object into DB * storage if this still satisfy the pre-condition regardless some changes * in DB storage * * @param meeting * a SignupMeeting object. * @param currentTimeslot * a SignupTimeslot object. * @param selectedAttendeeUserId * an unique sakai internal user id. * @param selectedTimeslotId * a string value * @return a SignupMeeting object, which is a refreshed updat-to-date data. * @throws Exception * throw if anything goes wrong. * */ private void handleVersion(SignupMeeting meeting, SignupTimeslot currentTimeslot, String selectedAttendeeUserId, String selectedTimeslotId) throws Exception { for (int i = 0; i < MAX_NUMBER_OF_RETRY; i++) { try { // reset track info this.signupEventTrackingInfo = new SignupEventTrackingInfoImpl(); this.signupEventTrackingInfo.setMeeting(meeting); meeting = signupMeetingService.loadSignupMeeting(meeting.getId(), userId, siteId); currentTimeslot = meeting.getTimeslot(currentTimeslot.getId()); if (currentTimeslot.getAttendee(selectedAttendeeUserId) == null) throw new SignupUserActionException(Utilities.rb .getString("failed.move.due_to_attendee_notExisted")); moveAttendee(meeting, currentTimeslot, selectedAttendeeUserId, selectedTimeslotId); signupMeetingService.updateSignupMeeting(meeting,isOrganizer); return; } catch (OptimisticLockingFailureException oe) { // don't do any thing } } throw new SignupUserActionException(Utilities.rb.getString("failed.move.due_to_attendee_notExisted")); }
/** * Give it a number of tries to update the event/meeting object into DB * storage if this still satisfy the pre-condition regardless some changes * in DB storage */ private void handleVersion(SignupMeeting meeting, SignupTimeslot currentTimeslot, String toBeReplacedUserId, SignupAttendee newAttendee) throws Exception { for (int i = 0; i < MAX_NUMBER_OF_RETRY; i++) { try { this.signupEventTrackingInfo = new SignupEventTrackingInfoImpl(); this.signupEventTrackingInfo.setMeeting(meeting); meeting = signupMeetingService.loadSignupMeeting(meeting.getId(), userId, siteId); currentTimeslot = meeting.getTimeslot(currentTimeslot.getId()); if (currentTimeslot.getAttendee(toBeReplacedUserId) == null) throw new SignupUserActionException(Utilities.rb .getString("failed.replaced_due_to_attendee_notExisted_in_ts")); replace(meeting, currentTimeslot, toBeReplacedUserId, newAttendee); signupMeetingService.updateSignupMeeting(meeting, isOrganizer); return; } catch (OptimisticLockingFailureException oe) { // don't do any thing } } throw new SignupUserActionException(Utilities.rb.getString("failed.replace.someone.already.updated.db")); }
/** * * @param newComment * takes in a string new comment * @return * @throws Exception */ public SignupMeeting updateComment(String newComment) throws Exception { this.modifiedComment = newComment; boolean isOrganizer = originalMeeting.getPermission().isUpdate(); String currentUserId = sakaiFacade.getCurrentUserId(); for (int i = 0; i < MAX_NUMBER_OF_RETRY; i++) { try { SignupMeeting upToDateMeeting = signupMeetingService.loadSignupMeeting(originalMeeting.getId(), currentUserId, siteId); checkPrecondition(upToDateMeeting, relatedTimeslotId); if(isOrganizer) upToDateMeeting.setPermission(originalMeeting.getPermission()); signupMeetingService.updateSignupMeeting(upToDateMeeting, isOrganizer); upToDateMeeting = signupMeetingService.loadSignupMeeting(originalMeeting.getId(), currentUserId, siteId); return upToDateMeeting; } catch (OptimisticLockingFailureException oe) { // don't do any thing } } throw new SignupUserActionException(Utilities.rb.getString("someone.already.updated.db")); }
public void testTransactionExceptionPropagatedWithCallbackPreference() throws Throwable { TransactionAttribute txatt = new DefaultTransactionAttribute(); MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); tas.register(exceptionalMethod, txatt); MockCallbackPreferringTransactionManager ptm = new MockCallbackPreferringTransactionManager(); TestBean tb = new TestBean(); ITestBean itb = (ITestBean) advised(tb, ptm, tas); checkTransactionStatus(false); try { itb.exceptional(new OptimisticLockingFailureException("")); fail("Should have thrown OptimisticLockingFailureException"); } catch (OptimisticLockingFailureException ex) { // expected } checkTransactionStatus(false); assertSame(txatt, ptm.getDefinition()); assertFalse(ptm.getStatus().isRollbackOnly()); }
/** {@inheritDoc} */ public void save(final String groupName, final Requisition group) { checkGroupName(groupName); final File importFile = getImportFile(groupName); if (importFile.exists()) { final Requisition currentData = get(groupName); if (currentData.getDateStamp().compare(group.getDateStamp()) > 0) { throw new OptimisticLockingFailureException("Data in file "+importFile+" is newer than data to be saved!"); } } final FileWriter writer; try { writer = new FileWriter(importFile); } catch (final IOException e) { throw new PermissionDeniedDataAccessException("Unable to write file "+importFile, e); } CastorUtils.marshalWithTranslatedExceptions(group, writer); }
public long initIdPool(TableIdRuleVo ruleVo, long blocksize) { long oldId; List<Long> oldPoolLastIds = RmBeanHelper.getCommonServiceInstance().queryForList("select LAST_ID from RM_ID_POOL where ID=?", new String[] { ruleVo.getTableName() }, Long.class); if(oldPoolLastIds.size() == 0) { oldId = getMaxIdFromTable(ruleVo); } else { oldId = oldPoolLastIds.get(0).longValue(); } long newPoolLastId = oldId + blocksize; if(oldPoolLastIds.size() == 0) { RmBeanHelper.getCommonServiceInstance().doUpdate("insert into RM_ID_POOL (ID, VERSION, LAST_ID) values(?, ?, ?)", new Object[] { ruleVo.getTableName(), 1, newPoolLastId }); } else { int updateCount = RmBeanHelper.getCommonServiceInstance().doUpdate("update RM_ID_POOL set LAST_ID=?, VERSION=VERSION+1 where ID=? and LAST_ID=?", new Object[] { newPoolLastId, ruleVo.getTableName(), oldPoolLastIds.get(0) }); if(updateCount == 0) { throw new OptimisticLockingFailureException("can not update lastId that read this time: " + ruleVo.getTableName()); } } return oldId; }
@Test public void testSave() { Product product = new Product(); product.setId(123L); product.setName("Tv"); product.setQuantity(BigInteger.TEN); product.setDiscount(BigDecimal.valueOf(12.34)); productRepository.save(product); Product savedProduct = productRepository.findOne(123L); assertEquals(savedProduct, product); assertEquals(savedProduct.hashCode(), product.hashCode()); assertEquals(Long.valueOf(0), product.getVersion()); assertEquals("Tv", product.getName()); savedProduct.setName("Dvd"); savedProduct = productRepository.save(savedProduct); assertEquals(Long.valueOf(1), savedProduct.getVersion()); savedProduct.setVersion(0L); try { productRepository.save(savedProduct); fail("Expected OptimisticLockingFailureException"); } catch (OptimisticLockingFailureException e) { } productRepository.delete(product); }
@Bean public Job job() { Step step = stepBuilders.get("step") .<String, String>chunk(5) .reader(reader()) .processor(processor()) .writer(writer()) .faultTolerant().retryLimit(3).skipLimit(3) .retry(OptimisticLockingFailureException.class) .retry(DeadlockLoserDataAccessException.class) .skip(DeadlockLoserDataAccessException.class) .listener(mockRetryListener()) .listener(retryListener()) .build(); return jobBuilders.get("job").start(step).build(); }
/** {@inheritDoc} */ public void save(final String groupName, final Requisition group) { checkGroupName(groupName); final File importFile = getImportFile(groupName); if (importFile.exists()) { final Requisition currentData = get(groupName); if (currentData.getDateStamp().compare(group.getDateStamp()) > 0) { throw new OptimisticLockingFailureException("Data in file "+importFile+" is newer than data to be saved!"); } } final FileWriter writer; try { writer = new FileWriter(importFile); } catch (final IOException e) { throw new PermissionDeniedDataAccessException("Unable to write file "+importFile, e); } group.updateDateStamp(); CastorUtils.marshalWithTranslatedExceptions(group, writer); }
@Retryable(include = OptimisticLockingFailureException.class, maxAttempts = 10) public User getUserByToken(String token) { Session session = getSession(token); if (session == null) { return null; } User user = UserRepository.findByMail(session.getMail()); if (user == null) { user = ldapService.createUserByMail(extractMail(token)); } return user; }
@Retryable(include = OptimisticLockingFailureException.class, maxAttempts = 10) private Session getSession(String token) { logger.debug("Getting session for token {}", token); if (isTokenInDB(token)) { logger.debug("Successfully found token {} in DB", token); return sessionRepo.findByToken(token); } if (isTokenInProxy(token)) { logger.debug("Successfully validated token {} with proxy", token); if (UserRepository.findByMail(extractMail(token)) == null) { // user not in db yet, will create User newUser = ldapService.createUserByMail(extractMail(token)); UserRepository.insert(newUser); logger.info("Successfully created new user {}", newUser.getId()); } // session not in DB, but in proxy -> create new session and revalidate old ones refreshUserSessions(extractMail(token)); Session newSession = new Session(token); sessionRepo.insert(newSession); return newSession; } logger.debug("Failed to get Session for token {}: no session found", token); return null; }
@Retryable(include = OptimisticLockingFailureException.class, maxAttempts = 10) public void cleanUp() { List<Session> cleanables = sessionRepo.findAll() .stream() .filter(session -> !isTokenInProxy(session.getToken()) || UserRepository.findByMail(session.getMail()) == null) .collect(Collectors.toList()); logger.info("Starting session cleanup, will remove {} sessions", cleanables.size()); sessionRepo.deleteAll(cleanables); }
@Retryable(include = OptimisticLockingFailureException.class, maxAttempts = 10) public void updateSkills(String username, String skillName, int skillLevel, int willLevel, boolean mentor) throws UserNotFoundException, SkillNotFoundException, EmptyArgumentException { if (StringUtils.isEmpty(username) || StringUtils.isEmpty(skillName)) { logger.debug("Failed to modify skills: username or skillName empty"); throw new EmptyArgumentException("arguments must not be empty or null"); } User user = UserRepository.findByIdIgnoreCase(username); if (user == null) { logger.debug("Failed to add/modify {}'s skills: user not found", username); throw new UserNotFoundException("user not found"); } KnownSkill skill = skillRepository.findByName(skillName); if (skill == null || skill.isHidden()) { logger.debug("Failed to add/modify {}'s skill {}: skill not found or hidden", username, skillName); throw new SkillNotFoundException("skill not found/hidden"); } if (!isValidLevelConfiguration(skillLevel, willLevel)) { logger.debug("Failed to add/modify {}'s skill {}: illegal levels {}/{}", username, skillName, skillLevel, willLevel); throw new IllegalLevelConfigurationException("Invalid Skill-/WillLevel Configuration"); } user.addUpdateSkill(skillName, skillLevel, willLevel, skillService.isHidden(skillName), mentor); UserRepository.save(user); logger.info("Successfully updated {}'s skill {}", username, skillName); }
@Retryable(include = OptimisticLockingFailureException.class, maxAttempts = 10) public void createSkill(String name, boolean isHidden, Set<String> subSkills) throws EmptyArgumentException, DuplicateSkillException { name = SkillUtils.sanitizeName(name); subSkills = subSkills.stream().map(n -> SkillUtils.sanitizeName(n)).filter(n -> !StringUtils.isEmpty(n)).collect(Collectors.toSet()); if (StringUtils.isEmpty(name)) { throw new EmptyArgumentException("name is empty"); } if (skillRepository.findByName(name) != null) { logger.debug("Failed to create skill {}: already exists", name); throw new DuplicateSkillException("skill already existing"); } // check if subSkills are known if (!isValidSubSkills(subSkills)) { logger.debug("Failed to set subskills on skill {}: subskill not found", name); throw new SkillNotFoundException("cannot set subskill: not found"); } try { skillRepository.insert(new KnownSkill(name, new ArrayList<>(), isHidden, subSkills)); logger.info("Successfully created skill {}", name); } catch (DuplicateKeyException e) { logger.debug("Failed to create skill {}: already exists"); throw new DuplicateSkillException("skill already existing"); } }
@Retryable(include = OptimisticLockingFailureException.class, maxAttempts = 10) public boolean isHidden(String skillName) { KnownSkill skill = skillRepository.findByName(skillName); if (skill == null) { throw new SkillNotFoundException("skill not found"); } return skill.isHidden(); }
@ResponseStatus(HttpStatus.CONFLICT) @ExceptionHandler(OptimisticLockingFailureException.class) public @ResponseBody ExceptionInfo handleOptimisticLock(HttpServletRequest request, Exception e) { getLog().warn(String.format("Attempt a failed save, likely due to multiple requests, at '%s'; " + "this will generate a CONFLICT RESPONSE", request.getRequestURL().toString())); getLog().debug("Handling OptimisticLockingFailureException and returning CONFLICT response", e); return new ExceptionInfo(request.getRequestURL().toString(), e.getLocalizedMessage()); }
/** 楽観的排他(Hibernateのバージョンチェック)の例外 */ @ExceptionHandler(OptimisticLockingFailureException.class) public ResponseEntity<Map<String, String[]>> handleOptimisticLockingFailureException( OptimisticLockingFailureException e) { log.warn(e.getMessage(), e); return new ErrorHolder(msg, locale(), "error.OptimisticLockingFailure").result(HttpStatus.BAD_REQUEST); }
@Test public void exceptionTranslationWithTranslation() { MapPersistenceExceptionTranslator mpet1 = new MapPersistenceExceptionTranslator(); RuntimeException in1 = new RuntimeException("in"); InvalidDataAccessApiUsageException out1 = new InvalidDataAccessApiUsageException("out"); InvalidDataAccessApiUsageException out2 = new InvalidDataAccessApiUsageException("out"); mpet1.addTranslation(in1, out1); ChainedPersistenceExceptionTranslator chainedPet1 = new ChainedPersistenceExceptionTranslator(); assertSame("Should not translate yet", in1, DataAccessUtils.translateIfNecessary(in1, chainedPet1)); chainedPet1.addDelegate(mpet1); assertSame("Should now translate", out1, DataAccessUtils.translateIfNecessary(in1, chainedPet1)); // Now add a new translator and verify it wins MapPersistenceExceptionTranslator mpet2 = new MapPersistenceExceptionTranslator(); mpet2.addTranslation(in1, out2); chainedPet1.addDelegate(mpet2); assertSame("Should still translate the same due to ordering", out1, DataAccessUtils.translateIfNecessary(in1, chainedPet1)); ChainedPersistenceExceptionTranslator chainedPet2 = new ChainedPersistenceExceptionTranslator(); chainedPet2.addDelegate(mpet2); chainedPet2.addDelegate(mpet1); assertSame("Should translate differently due to ordering", out2, DataAccessUtils.translateIfNecessary(in1, chainedPet2)); RuntimeException in2 = new RuntimeException("in2"); OptimisticLockingFailureException out3 = new OptimisticLockingFailureException("out2"); assertNull(chainedPet2.translateExceptionIfPossible(in2)); MapPersistenceExceptionTranslator mpet3 = new MapPersistenceExceptionTranslator(); mpet3.addTranslation(in2, out3); chainedPet2.addDelegate(mpet3); assertSame(out3, chainedPet2.translateExceptionIfPossible(in2)); }
/** * Logs further details of OptimisticLockExceptions, using the given depth value to limit recursion Just In Case * * @param depth * @param t */ private void logOptimisticDetails(int depth, Throwable t) { if ((depth > 0) && (t != null)) { Object sourceObject = null; boolean optLockException = false; if ( t instanceof javax.persistence.OptimisticLockException ) { sourceObject = ((javax.persistence.OptimisticLockException)t).getEntity(); optLockException = true; } else if ( t instanceof OptimisticLockingFailureException ) { sourceObject = ((OptimisticLockingFailureException)t).getMessage(); optLockException = true; } else if ( t.getClass().getName().equals( "org.apache.ojb.broker.OptimisticLockException" ) ) { try { sourceObject = PropertyUtils.getSimpleProperty(t, "sourceObject"); } catch (Exception ex) { LOG.warn( "Unable to retrieve source object from OJB OptimisticLockException", ex ); } optLockException = true; } if ( optLockException ) { if (sourceObject != null) { if ( sourceObject instanceof String ) { LOG.error("source of OptimisticLockException Unknown. Message: " + sourceObject); } else { LOG.error("source of OptimisticLockException = " + sourceObject.getClass().getName() + " ::= " + sourceObject); } } } else { Throwable cause = t.getCause(); if (cause != t) { logOptimisticDetails(--depth, cause); } } } }