@Override public void removeEquipmentFromProcess(Long equipmentId, Long processId) { try { processCache.acquireWriteLockOnKey(processId); try { Process processCopy = processCache.getCopy(processId); log.debug("Removing Process Equipment {} for process {}", equipmentId, processCopy.getName()); processCopy.getEquipmentIds().remove(equipmentId); processCache.putQuiet(processCopy); } finally { processCache.releaseWriteLockOnKey(processId); } } catch (RuntimeException e) { throw new UnexpectedRollbackException("Unable to remove equipment reference in process.", e); } }
@Override @Transactional(value = "cacheTransactionManager", propagation = Propagation.REQUIRES_NEW) public List<ProcessChange> doRemoveSubEquipment(final SubEquipment subEquipment, final ConfigurationElementReport subEquipmentReport) { List<ProcessChange> processChanges = new ArrayList<ProcessChange>(); try { subEquipmentDAO.deleteItem(subEquipment.getId()); Long processId = this.subEquipmentFacade.getProcessIdForAbstractEquipment(subEquipment.getId()); SubEquipmentUnitRemove subEquipmentUnitRemove = new SubEquipmentUnitRemove(0L, subEquipment.getId(), subEquipment.getParentId()); processChanges.add(new ProcessChange(processId, subEquipmentUnitRemove)); } catch (RuntimeException e) { subEquipmentReport.setFailure("Rolling back removal of sub-equipment " + subEquipment.getId()); throw new UnexpectedRollbackException("Exception caught while removing Sub-equipment from DB: rolling back", e); } return processChanges; }
@Override public void updateRuleTag(Long id, Properties elementProperties) throws IllegalAccessException { try { ruleTagConfigTransacted.doUpdateRuleTag(id, elementProperties); ruleEvaluator.evaluateRule(id); if (LOGGER.isTraceEnabled()) { LOGGER.trace("updateRuleTag - Notifying Configuration update listeners"); } this.configurationUpdateImpl.notifyListeners(id); } catch (UnexpectedRollbackException e) { LOGGER.error("Rolling back Rule update in cache"); ruleTagCache.remove(id); ruleTagCache.loadFromDb(id); throw e; } }
@Override public ProcessChange createProcess(final ConfigurationElement element) throws IllegalAccessException { LOGGER.debug("Creating process with id " + element.getEntityId()); if (processCache.hasKey(element.getEntityId())) { throw new ConfigurationException(ConfigurationException.ENTITY_EXISTS, "Attempting to create a process with an already existing id: " + element.getEntityId()); } Process process = null; try { ProcessChange change = processConfigTransacted.doCreateProcess(element); process = processCache.get(element.getEntityId()); jmsContainerManager.subscribe(process); processFacade.loadAndStartAliveTag(element.getEntityId()); processCache.notifyListenersOfUpdate(element.getEntityId()); return change; } catch (RuntimeException ex) { LOGGER.error("Exception caught while creating a new Process - rolling back DB changes and removing from cache."); processCache.remove(element.getEntityId()); if (process != null){ jmsContainerManager.unsubscribe(process); } throw new UnexpectedRollbackException("Unexpected error while creating a new Process.", ex); } }
@Override public ProcessChange updateDataTag(Long id, Properties elementProperties) { try { ProcessChange processChange = dataTagConfigTransacted.doUpdateDataTag(id, elementProperties); if (LOGGER.isTraceEnabled()) { LOGGER.trace("createDataTag - Notifying Configuration update listeners"); } this.configurationUpdateImpl.notifyListeners(id); return processChange; } catch (UnexpectedRollbackException e) { LOGGER.error("Rolling back update in cache"); dataTagCache.remove(id); //DB transaction is rolled back here: reload the tag dataTagCache.loadFromDb(id); throw e; } }
@RequestMapping(method = RequestMethod.POST) public String registerNewMember(@Valid @ModelAttribute("newMember") Member newMember, BindingResult result, Model model) { if (!result.hasErrors()) { try { memberDao.register(newMember); return "redirect:/"; } catch (UnexpectedRollbackException e) { model.addAttribute("members", memberDao.findAllOrderedByName()); model.addAttribute("error", e.getCause().getCause()); return "index"; } } else { model.addAttribute("members", memberDao.findAllOrderedByName()); return "index"; } }
@Test public void unexpectedRollbackTest() { final String testName = TestUtils.getMethodName(); logger.info("-{}----------------------------------------------------", testName); List<String> values = Lists.newArrayList(TransactionTestService.ValuePrefix + "X01"); List<String> values2 = Lists.newArrayList(TransactionTestService.ValuePrefix + "X02"); List<String> values3 = Lists.newArrayList(TransactionTestService.ValuePrefix + "X03"); try { transactionTestService.insertAndAbortThenInsert(values, values2, values3); // 必ず例外発生 assertThat(testName, true); } catch (UnexpectedRollbackException ignored) { } catch (RuntimeException e) { logger.warn(e.getMessage()); assertThat(testName, true); } logger.info("----------------------------------------------------{}-", testName); }
/** * This implementation of commit handles participating in existing * transactions and programmatic rollback requests. * Delegates to {@code isRollbackOnly}, {@code doCommit} * and {@code rollback}. * @see org.springframework.transaction.TransactionStatus#isRollbackOnly() * @see #doCommit * @see #rollback */ @Override public final void commit(TransactionStatus status) throws TransactionException { if (status.isCompleted()) { throw new IllegalTransactionStateException( "Transaction is already completed - do not call commit or rollback more than once per transaction"); } DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status; if (defStatus.isLocalRollbackOnly()) { if (defStatus.isDebug()) { logger.debug("Transactional code has requested rollback"); } processRollback(defStatus); return; } if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) { if (defStatus.isDebug()) { logger.debug("Global transaction is marked as rollback-only but transactional code requested commit"); } processRollback(defStatus); // Throw UnexpectedRollbackException only at outermost transaction boundary // or if explicitly asked to. if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) { throw new UnexpectedRollbackException( "Transaction rolled back because it has been marked as rollback-only"); } return; } processCommit(defStatus); }
public void rollback() { if (rollbackCalled) { throw new UnexpectedRollbackException("Cannot rollback Redis transaction. Transaction already rolled back!"); } try { redisTemplate.discard(); rollbackCalled = true; } catch (Exception e) { throw new TransactionSystemException("Exception occurred rolling back Redis transaction: " + e.getMessage()); } }
/** * Simulate failure of the underlying transaction infrastructure to commit. * Check that the target method was invoked, but that the transaction * infrastructure exception was thrown to the client */ @Test public void cannotCommitTransaction() throws Exception { TransactionAttribute txatt = new DefaultTransactionAttribute(); Method m = setNameMethod; MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); tas.register(m, txatt); // Method m2 = getNameMethod; // No attributes for m2 PlatformTransactionManager ptm = mock(PlatformTransactionManager.class); TransactionStatus status = mock(TransactionStatus.class); given(ptm.getTransaction(txatt)).willReturn(status); UnexpectedRollbackException ex = new UnexpectedRollbackException("foobar", null); willThrow(ex).given(ptm).commit(status); TestBean tb = new TestBean(); ITestBean itb = (ITestBean) advised(tb, ptm, tas); String name = "new name"; try { itb.setName(name); fail("Shouldn't have succeeded"); } catch (UnexpectedRollbackException thrown) { assertTrue(thrown == ex); } // Should have invoked target and changed name assertTrue(itb.getName() == name); }
@Override @Transactional(value = "cacheTransactionManager", propagation=Propagation.REQUIRES_NEW) public void doRemoveEquipment(final Equipment equipment, final ConfigurationElementReport equipmentReport) { LOGGER.debug("Removing Equipment " + equipment.getId() + " from DB"); try { equipmentDAO.deleteItem(equipment.getId()); } catch (UnexpectedRollbackException ex) { equipmentReport.setFailure("Aborting removal of equipment " + equipment.getId() + " as unable to remove it from DB."); throw new UnexpectedRollbackException("Interrupting removal of Equipment as failed to remove it from DB - " + "control tags will not be removed.", ex); } }
@Override @Transactional(value = "cacheTransactionManager", propagation=Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED) public void doRemoveRuleTag(final Long id, final ConfigurationElementReport elementReport) { LOGGER.trace("Removing RuleTag " + id); try { RuleTag ruleTag = tagCache.get(id); Collection<Long> ruleIds = ruleTag.getCopyRuleIds(); if (!ruleIds.isEmpty()) { LOGGER.debug("Removing rules dependent on RuleTag " + id); for (Long ruleId : ruleIds) { //concurrent modifcation as a rule is removed from the list during the remove call! if (tagLocationService.isInTagCache(ruleId)) { //may already have been removed if a previous rule in the list was used in this rule! ConfigurationElementReport newReport = new ConfigurationElementReport(Action.REMOVE, Entity.RULETAG, ruleId); elementReport.addSubReport(newReport); ruleTagConfigHandler.removeRuleTag(ruleId, newReport); //call config handler bean so transaction annotation is noticed } } } tagCache.acquireWriteLockOnKey(id); Collection<Long> ruleInputTagIds = Collections.EMPTY_LIST; try { ruleInputTagIds = ruleTag.getCopyRuleInputTagIds(); Collection<Long> alarmIds = ruleTag.getCopyAlarmIds(); if (!alarmIds.isEmpty()) { LOGGER.debug("Removing Alarms dependent on RuleTag " + id); for (Long alarmId : alarmIds) { //need copy as modified concurrently by remove alarm ConfigurationElementReport alarmReport = new ConfigurationElementReport(Action.REMOVE, Entity.ALARM, alarmId); elementReport.addSubReport(alarmReport); alarmConfigHandler.removeAlarm(alarmId, alarmReport); } } for (Long inputTagId : ruleInputTagIds) { tagConfigGateway.removeRuleFromTag(inputTagId, id); //allowed to lock tag below the rule... } for (ConfigurationEventListener listener : configurationEventListeners) { listener.onConfigurationEvent(ruleTag, Action.REMOVE); } configurableDAO.deleteItem(ruleTag.getId()); } catch (RuntimeException rEx) { String errMessage = "Exception caught when removing rule tag with id " + id; LOGGER.error(errMessage, rEx); throw new UnexpectedRollbackException(errMessage, rEx); } finally { if (tagCache.isWriteLockedByCurrentThread(id)) { tagCache.releaseWriteLockOnKey(id); } } } catch (CacheElementNotFoundException e) { LOGGER.debug("Attempting to remove a non-existent RuleTag - no action taken."); elementReport.setWarning("Attempting to removed a non-existent RuleTag"); } }
/** * Creates the abstract equipment, puts it in the DB and then loads it into * the cache (in that order). The AliveTimer and CommFaultTag are then * generated in their respective caches. * * @param element * contains the creation detais * @return the generated AbstractEquipment object * @throws IllegalAccessException * should not be thrown here (inherited at interface from Tag * creation). */ protected T createAbstractEquipment(final ConfigurationElement element) throws IllegalAccessException { abstractEquipmentCache.acquireWriteLockOnKey(element.getEntityId()); try { LOGGER.debug("Creating (Sub)Equipment " + element.getEntityId()); T abstractEquipment = commonEquipmentFacade.createCacheObject(element.getEntityId(), element.getElementProperties()); try { configurableDAO.insert(abstractEquipment); abstractEquipmentCache.putQuiet(abstractEquipment); // clear alive and commfault caches and refresh // (synch ok as locked equipment so no changes to these ids) if (abstractEquipment.getAliveTagId() != null) { commonEquipmentFacade.loadAndStartAliveTag(abstractEquipment.getId()); } if (abstractEquipment.getCommFaultTagId() != null) { commFaultTagCache.remove(abstractEquipment.getCommFaultTagId()); commFaultTagCache.loadFromDb(abstractEquipment.getCommFaultTagId()); } } catch (Exception e) { if (abstractEquipment.getAliveTagId() != null) { aliveTimerCache.remove(abstractEquipment.getId()); } if (abstractEquipment.getCommFaultTagId() != null) { commFaultTagCache.remove(abstractEquipment.getCommFaultTagId()); } throw new UnexpectedRollbackException("Exception caught while creating equipment: rolling back changes", e); } // TODO necessary to use DB loading or not?? to check... // removed as now rely on automatic cache loading from DB: problem: also // used in checking if tag is alive or commfault, so added again // abstractEquipmentCache.putQuiet(abstractEquipment); // aliveTimerFacade.generateFromEquipment(abstractEquipment); // commFaultTagFacade.generateFromEquipment(abstractEquipment); return abstractEquipment; } finally { abstractEquipmentCache.releaseWriteLockOnKey(element.getEntityId()); } }
@Override public ProcessChange updateDeviceClass(Long id, Properties elementProperties) { try { ProcessChange processChange = deviceClassConfigTransacted.doUpdateDeviceClass(id, elementProperties); return processChange; } catch (UnexpectedRollbackException e) { LOGGER.error("Rolling back update in cache"); // DB transaction is rolled back here: reload the tag deviceClassCache.remove(id); deviceClassCache.loadFromDb(id); throw e; } }
@Override public ProcessChange updateControlTag(Long id, Properties elementProperties) throws IllegalAccessException { acquireEquipmentWriteLockForElement(id, elementProperties); try { return controlTagConfigTransacted.doUpdateControlTag(id, elementProperties); } catch (UnexpectedRollbackException e) { LOGGER.error("Rolling back ControlTag update in cache"); controlTagCache.remove(id); controlTagCache.loadFromDb(id); throw e; } finally { releaseEquipmentWriteLockForElement(id, elementProperties); } }
@Override public void updateAlarm(Long alarmId, Properties properties) { try { alarmConfigTransacted.doUpdateAlarm(alarmId, properties); alarmFacade.evaluateAlarm(alarmId); } catch (UnexpectedRollbackException e) { log.error("Rolling back Alarm update in cache"); alarmCache.remove(alarmId); alarmCache.loadFromDb(alarmId); throw e; } }
@Override public ProcessChange updateDevice(Long id, Properties elementProperties) { try { ProcessChange processChange = deviceConfigTransacted.doUpdateDevice(id, elementProperties); return processChange; } catch (UnexpectedRollbackException e) { LOGGER.error("Rolling back update in cache"); // DB transaction is rolled back here: reload the tag deviceCache.remove(id); deviceCache.loadFromDb(id); throw e; } }
/** * This method saves the user settings. */ private void saveUserSettings() { try { ServiceLocator.findService(TransactionManagement.class) .execute(new SaveInTransaction()); } catch (UnexpectedRollbackException e) { LOGGER.warn("This is not a problem here: " + e.getMessage()); } }
/** * This method saves the user settings. */ private void saveUserSettings() { try { ServiceLocator.findService(TransactionManagement.class) .execute(new SaveInTransaction()); } catch (UnexpectedRollbackException e) { LOG.warn("This is not a problem here: " + e.getMessage()); } }
private void sendExceptionEmail(String errorCode, String stackTrace, String urlException) { try{ singularSupportService.sendEmailToSupport(errorCode, stackTrace, urlException); }catch (UnexpectedRollbackException e){ getLogger().error(e.getMessage(), e); getLogger().warn("A Rollback happened because of a exception while sending an e-mail to support {}", e.getMessage()); } }
@Test(expected=UnexpectedRollbackException.class) public void testSaveUnlinkedSkipLinking() { Object a = createUnlinkedTestObject(); provider.save(a); fail("save should have resulted in an exception as references have not been linked correctly"); }
public void invokeRunnable(Runnable toinvoke) { try { daoInvoker.invokeTransactionalAccess(toinvoke); } catch (UnexpectedRollbackException e) { // this will stop the exceptions from reaching the portal LOG.info("Eval: Caught transaction rollback exception: " + e.getCause()); } }
/** * This implementation of commit handles participating in existing * transactions and programmatic rollback requests. * Delegates to {@code isRollbackOnly}, {@code doCommit} * and {@code rollback}. * @see org.springframework.transaction.TransactionStatus#isRollbackOnly() * @see #doCommit * @see #rollback */ public final void commit(TransactionStatus status) throws TransactionException { if (status.isCompleted()) { throw new IllegalTransactionStateException( "Transaction is already completed - do not call commit or rollback more than once per transaction"); } DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status; if (defStatus.isLocalRollbackOnly()) { if (defStatus.isDebug()) { logger.debug("Transactional code has requested rollback"); } processRollback(defStatus); return; } if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) { if (defStatus.isDebug()) { logger.debug("Global transaction is marked as rollback-only but transactional code requested commit"); } processRollback(defStatus); // Throw UnexpectedRollbackException only at outermost transaction boundary // or if explicitly asked to. if (status.isNewTransaction() || isFailEarlyOnGlobalRollbackOnly()) { throw new UnexpectedRollbackException( "Transaction rolled back because it has been marked as rollback-only"); } return; } processCommit(defStatus); }
/** * Simulate failure of the underlying transaction infrastructure to commit. * Check that the target method was invoked, but that the transaction * infrastructure exception was thrown to the client */ public void testCannotCommitTransaction() throws Exception { TransactionAttribute txatt = new DefaultTransactionAttribute(); Method m = setNameMethod; MapTransactionAttributeSource tas = new MapTransactionAttributeSource(); tas.register(m, txatt); // Method m2 = getNameMethod; // No attributes for m2 PlatformTransactionManager ptm = mock(PlatformTransactionManager.class); TransactionStatus status = mock(TransactionStatus.class); given(ptm.getTransaction(txatt)).willReturn(status); UnexpectedRollbackException ex = new UnexpectedRollbackException("foobar", null); willThrow(ex).given(ptm).commit(status); TestBean tb = new TestBean(); ITestBean itb = (ITestBean) advised(tb, ptm, tas); String name = "new name"; try { itb.setName(name); fail("Shouldn't have succeeded"); } catch (UnexpectedRollbackException thrown) { assertTrue(thrown == ex); } // Should have invoked target and changed name assertTrue(itb.getName() == name); }
@Override public void rollback(TransactionStatus status) throws TransactionException { if(logger.isWarnEnabled()){ logger.warn("Rollback all connected transactions."); } try{ TransactionSynchronizationUtils.triggerBeforeCompletion(); Map<DataSource, ConnectionHolder> connSet = RoutingSynchronizationManager.getSynchronizations(); Exception rollbackException = null; ConnectionHolder rollbackExceptionConnection = null; for (ConnectionHolder connection:connSet.values()) { try { connection.rollback(); if (logger.isDebugEnabled()) { logger.debug("Connection["+ connection +"] has been rolled back."); } } catch (Exception ex) { if (rollbackException == null) { rollbackException = ex; rollbackExceptionConnection = connection; } else { logger.warn("Rollback exception (" + rollbackExceptionConnection + ") " + ex.getMessage(), ex); } } } if (rollbackException != null) { throw new UnexpectedRollbackException("Rollback exception, originated at ("+rollbackExceptionConnection+") "+ rollbackException.getMessage(), rollbackException); } }finally{ RoutingSynchronizationManager .invokeAfterCompletion(TransactionSynchronization.STATUS_ROLLED_BACK); RoutingSynchronizationManager.clearSynchronization(); } }
/** * PROPAGATION_REQUIRES:内部事务设置了 {@link org.springframework.transaction.TransactionStatus#setRollbackOnly()} 来触发回滚, * 外部事务接受到了一个 {@link UnexpectedRollbackException} 也被回滚 */ @Test public void testTxRollbackInnerTxRollbackPropagationRequires() { try { springTxTest.txRollbackInnerTxRollbackPropagationRequires(); } catch (UnexpectedRollbackException e) { // Do nothing at all. } finally { Assert.assertEquals(1, springTxTest.mysqlConnectionTest()); } }
@Override @Transactional(value = "cacheTransactionManager", propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED) public ProcessChange doRemoveDataTag(final Long id, final ConfigurationElementReport elementReport) { ProcessChange processChange = new ProcessChange(); try { DataTag tagCopy = tagCache.getCopy(id); Collection<Long> ruleIds = tagCopy.getCopyRuleIds(); if (!ruleIds.isEmpty()) { LOGGER.trace("Removing Rules dependent on DataTag " + id); for (Long ruleId : new ArrayList<>(ruleIds)) { if (tagLocationService.isInTagCache(ruleId)) { //may already have been removed if a previous rule in the list was used in this rule! { ConfigurationElementReport newReport = new ConfigurationElementReport(Action.REMOVE, Entity.RULETAG, ruleId); elementReport.addSubReport(newReport); ruleTagConfigHandler.removeRuleTag(ruleId, newReport); } } } tagCache.acquireWriteLockOnKey(id); try { Collection<Long> alarmIds = tagCopy.getCopyAlarmIds(); if (!alarmIds.isEmpty()) { LOGGER.trace("Removing Alarms dependent on DataTag " + id); for (Long alarmId : new ArrayList<>(alarmIds)) { ConfigurationElementReport alarmReport = new ConfigurationElementReport(Action.REMOVE, Entity.ALARM, alarmId); elementReport.addSubReport(alarmReport); alarmConfigHandler.removeAlarm(alarmId, alarmReport); } } for (ConfigurationEventListener listener : configurationEventListeners) { listener.onConfigurationEvent(tagCopy, Action.REMOVE); } configurableDAO.deleteItem(tagCopy.getId()); } catch (Exception ex) { //commonTagFacade.setStatus(dataTag, Status.RECONFIGURATION_ERROR); elementReport.setFailure("Exception caught while removing datatag", ex); LOGGER.error("Exception caught while removing datatag with id " + id + "; rolling back DB transaction.", ex); throw new UnexpectedRollbackException("Exception caught while removing datatag.", ex); } finally { if (tagCache.isWriteLockedByCurrentThread(id)) { tagCache.releaseWriteLockOnKey(id); } } // if successful so far add remove event for DAQ layer DataTagRemove removeEvent = new DataTagRemove(); removeEvent.setDataTagId(id); if (tagCopy.getEquipmentId() != null) { removeEvent.setEquipmentId(tagCopy.getEquipmentId()); processChange = new ProcessChange(equipmentFacade.getProcessIdForAbstractEquipment(tagCopy.getEquipmentId()), removeEvent); } // TIMS-951: Allow attachment of DataTags to SubEquipments else if (tagCopy.getSubEquipmentId() != null) { removeEvent.setEquipmentId(subEquipmentFacade.getEquipmentIdForSubEquipment(tagCopy.getSubEquipmentId())); processChange = new ProcessChange(subEquipmentFacade.getProcessIdForAbstractEquipment(tagCopy.getSubEquipmentId()), removeEvent); } else { LOGGER.warn("doRemoveDataTag() - data tag #" + tagCopy.getId() + " is not attached to any Equipment or Sub-Equipment. This should normally never happen."); } } catch (CacheElementNotFoundException e) { LOGGER.warn("doRemoveDataTag() - Attempting to remove a non-existent DataTag - no action taken."); throw new CacheElementNotFoundException("Attempting to remove a non-existent DataTag - no action taken", e); } return processChange; }
@Override @Transactional(value = "cacheTransactionManager", propagation=Propagation.REQUIRES_NEW) public ProcessChange doRemoveControlTag(Long id, ConfigurationElementReport tagReport) { LOGGER.trace("Removing ControlTag " + id); try { Collection<Long> ruleIds = tagCache.get(id).getCopyRuleIds(); if (!ruleIds.isEmpty()) { LOGGER.trace("Removing rules dependent on ControlTag " + id); for (Long ruleId : ruleIds) { ConfigurationElementReport newReport = new ConfigurationElementReport(Action.REMOVE, Entity.RULETAG, ruleId); tagReport.addSubReport(newReport); ruleTagConfigHandler.removeRuleTag(ruleId, newReport); } } tagCache.acquireWriteLockOnKey(id); try { ControlTag controlTag = tagCache.get(id); if (!controlTag.getAlarmIds().isEmpty()) { LOGGER.trace("Removing Alarms dependent on ControlTag " + controlTag.getId()); for (Long alarmId : new ArrayList<Long>(controlTag.getAlarmIds())) { ConfigurationElementReport alarmReport = new ConfigurationElementReport(Action.REMOVE, Entity.ALARM, alarmId); tagReport.addSubReport(alarmReport); alarmConfigHandler.removeAlarm(alarmId, alarmReport); } } for (ConfigurationEventListener listener : configurationEventListeners) { listener.onConfigurationEvent(controlTag, Action.REMOVE); } //dataTagFacade.invalidate(controlTag, new DataTagQuality(DataTagQuality.REMOVED, "The ControlTag has been removed from the system and is no longer monitored."), new Timestamp(System.currentTimeMillis())); configurableDAO.deleteItem(controlTag.getId()); //if the ControlTag has no Address, do not send anything to the DAQ so return null if (((ControlTagFacade) commonTagFacade).isInProcessList(controlTag)) { tagCache.releaseWriteLockOnKey(id); //if the ControlTag is associated to some Equipment(or SubEquipment) inform the DAQ DataTagRemove removeEvent = new DataTagRemove(); removeEvent.setDataTagId(id); return getProcessChanges(removeEvent, id); } else { return new ProcessChange(); } } catch (Exception ex) { //commonTagFacade.setStatus(controlTag, Status.RECONFIGURATION_ERROR); LOGGER.error("Exception caught while removing a control tag.", ex); tagReport.setFailure("Unable to remove ControlTag with id " + id); throw new UnexpectedRollbackException("Unable to remove control tag " + id, ex); } finally { if (tagCache.isWriteLockedByCurrentThread(id)) { tagCache.releaseWriteLockOnKey(id); } } } catch (CacheElementNotFoundException e) { LOGGER.warn("Attempting to remove a non-existent ControlTag - no action taken."); tagReport.setWarning("Attempting to removed a non-existent ControlTag"); return new ProcessChange(); } }
@Override public ProcessChange updateProcess(final Long processId, final Properties elementProperties) throws IllegalAccessException { if (elementProperties.containsKey("id")) { LOGGER.warn("Attempting to change the process id - this is not currently supported!"); elementProperties.remove("id"); } if (elementProperties.containsKey("name")) { LOGGER.warn("Attempting to change the process name - this is not currently supported!"); elementProperties.remove("name"); } boolean aliveConfigure = false; if (elementProperties.containsKey("aliveInterval") || elementProperties.containsKey("aliveTagId")) { aliveConfigure = true; } ProcessChange processChange = new ProcessChange(processId); try { Long oldAliveId = processCache.getCopy(processId).getAliveTagId(); processConfigTransacted.doUpdateProcess(processId, elementProperties); //stop old, start new - transaction is committed here if (aliveConfigure) { processFacade.removeAliveDirectly(oldAliveId); processFacade.loadAndStartAliveTag(processId); processChange.requiresReboot(); } } catch (CacheElementNotFoundException cacheEx) { LOGGER.warn("Unable to locate Process " + processId + " in cache so unable to update it."); throw cacheEx; } catch (RuntimeException e) { LOGGER.error("Exception caught while updating Process " + processId + " - rolling back DB and cache changes for this Process."); throw new UnexpectedRollbackException("Unexpected exception caught while updating Process " + processId, e); } return processChange; }
/** * PROPAGATION_MANDATORY:强制性的事务,内部的事务发生回滚,那么外围的事务也会发生回滚,表现地和 {@link org.springframework.transaction.TransactionDefinition#PROPAGATION_REQUIRED} 一样,也会抛出 {@link UnexpectedRollbackException} */ @Test(expected = UnexpectedRollbackException.class) public void testTxRollbackInnerTxRollbackPropagationMandatory2() { springTxTest.txRollbackInnerTxRollbackPropagationMandatory2(); }
/** * PROPAGATION_SUPPORTS:如果当前事务上下文中存在事务,那么合并到当前上下文的事务中去,表现地和 {@link org.springframework.transaction.TransactionDefinition#PROPAGATION_REQUIRED} 一样 */ @Test(expected = UnexpectedRollbackException.class) public void testTxRollbackInnerTxRollbackPropagationSupports2() { springTxTest.txRollbackInnerTxRollbackPropagationSupports2(); }