/// <summary>
        /// Logic launched after the step. Will launch the postprocessor.
        /// @see IStepExecutionListener#AfterStep
        /// </summary>
        /// <param name="stepExecution"></param>
        /// <returns></returns>
        public virtual ExitStatus AfterStep(StepExecution stepExecution)
        {
            ExitStatus returnStatus = stepExecution.ExitStatus;

            if (!"FAILED".Equals(returnStatus.ExitCode))
            {
                MethodInfo post = this.GetType().GetMethod("Postprocess", BindingFlags.Instance | BindingFlags.NonPublic);
                if (post.DeclaringType != typeof(AbstractExecutionListener))
                {
                    using (var scope = TransactionScopeManager.CreateScope())
                    {
                        try
                        {
                            returnStatus = Postprocess();
                        }
                        catch (Exception e)
                        {
                            // Need to catch exception to log and set status to FAILED, while
                            // Spring batch would only log and keep the status COMPLETED
                            Logger.Error(e, "Exception during postprocessor");
                            stepExecution.UpgradeStatus(BatchStatus.Failed);
                            throw;
                        }
                        scope.Complete();
                    }
                }
            }
            return(returnStatus);
        }
        public void FlatFileTestTransactionalTest()
        {
            var writer = new FlatFileItemWriter <Person>
            {
                Resource       = new FileSystemResource(_testPath2),
                LineAggregator = new LineAggregator(),
                HeaderWriter   = new HeaderWriter()
            };
            var reader = new FlatFileItemReader <Person>
            {
                Resource    = new FileSystemResource(_testPath2),
                LinesToSkip = 2,
                LineMapper  = new LineMapper()
            };

            var executionContext = new ExecutionContext();

            writer.Open(executionContext);
            try
            {
                for (int i = 0; i < CountTransactions; i++)
                {
                    using (TransactionScope scope = TransactionScopeManager.CreateScope())
                    {
                        writer.Write(GetPersons(i));
                        if (i == CountTransactions - 1) //SIMULATE FAILURE
                        {
                            throw new Exception("Bailing out ... should rollback ...");
                        }
                        scope.Complete();
                    }
                }
            }
            catch (Exception e)
            {
                Logger.Error(e, "An unexpected exception occured :");
            }
            writer.Close();

            var persons = new List <Person>();

            reader.Open(executionContext);
            Person person;

            while ((person = reader.Read()) != null)
            {
                persons.Add(person);
            }
            reader.Close();

            Assert.AreEqual((CountTransactions - 1) * CountObjects, persons.Count);

            for (var i = 0; i < persons.Count; i++)
            {
                Assert.AreEqual(i % CountObjects, persons[i].Id);
                Assert.IsTrue(persons[i].Name.StartsWith("Person" + i % CountObjects));
            }
        }
        /// <summary>
        /// Actual taskletstep execution.
        /// </summary>
        /// <param name="stepExecution"></param>
        /// <exception cref="Exception">&nbsp;</exception>
        protected override void DoExecute(StepExecution stepExecution)
        {
            stepExecution.ExecutionContext.Put(TaskletTypeKey, _tasklet.GetType().Name);
            stepExecution.ExecutionContext.Put(StepConstants.StepTypeKey, GetType().Name);

            _stream.Update(stepExecution.ExecutionContext);

            JobRepository.UpdateExecutionContext(stepExecution);
            JobRepository.UpdateExecutionContext(stepExecution.JobExecution);
            // Shared semaphore per step execution, so other step executions can run
            // in parallel without needing the lock
            Semaphore semaphore = CreateSemaphore();

            _stepOperations.Iterate(StepContextRepeatCallback.GetRepeatCallback(stepExecution,
                                                                                (context, chunkContext) =>
            {
                StepExecution lStepExecution = chunkContext.StepContext.StepExecution;
                _interruptionPolicy.CheckInterrupted(lStepExecution);

                ChunkTransactionCallback callback =
                    new ChunkTransactionCallback(chunkContext, semaphore, this);

                RepeatStatus result;

                using (var scope = TransactionScopeManager.CreateScope())
                {
                    TransactionScopeManager.RegisterTransactionSynchronization(scope, callback);
                    try
                    {
                        result = callback.DoInTransaction();
                    }
                    catch (Exception e)
                    {
                        //Log and rethrow
                        Logger.Error(e, "Transaction will be rollbacked because of an unexpected exception.");
                        throw;     // throw to ensure rollback will occur (no complete)
                    }
                    scope.Complete();
                }
                // Release connections since the transaction has ended
                ConnectionUtil.ReleaseConnections();
                Thread.Sleep(stepExecution.DelayConfig);

                _interruptionPolicy.CheckInterrupted(stepExecution);
                return(result);
            }
                                                                                ));
        }
        /// <summary>
        /// Logic launched after the step. Will launch the postprocessor.
        /// @see IStepExecutionListener#AfterStep
        /// </summary>
        /// <param name="stepExecution"></param>
        /// <returns></returns>
        public virtual ExitStatus AfterStep(StepExecution stepExecution)
        {
            ExitStatus returnStatus = stepExecution.ExitStatus;

            if (!"FAILED".Equals(returnStatus.ExitCode))
            {
                MethodInfo post = GetType().GetMethod("Postprocess", BindingFlags.Instance | BindingFlags.NonPublic);
                // determine worker / master mode for step
                if (stepExecution.remoteChunking != null)
                {
                    TimeSpan RemoteChunkingTimoutSecond = stepExecution.remoteChunking.RemoteChunkingTimoutSecond;
                    // master part
                    if (stepExecution.remoteChunking._master)
                    {
                        // wait for Master method send back signal
                        if (!stepExecution.remoteChunking.threadWait.WaitOne(-1))
                        {
                            Exception e = new JobExecutionException("Master step failed");
                            Logger.Error(e, "Clean message in the Queue.");
                            throw e;
                        }
                        // some worker failed master need to fail
                        if ("FAILED".Equals(stepExecution.ExitStatus.ExitCode))
                        {
                            Exception e = new JobExecutionException("Master step failed");
                            Logger.Error(e, "Clean message in the Queue.");
                            throw e;
                        }

                        // clean all message queues when master completed
                        Logger.Info("Master is completed.");
                        Logger.Info("Clean message in the Queue.");
                        stepExecution.remoteChunking.CleanAllQueue();
                    }
                    else
                    {
                        if (!stepExecution.remoteChunking.threadWait.WaitOne(-1))
                        {
                            returnStatus = stepExecution.ExitStatus;
                            throw new JobExecutionException("Worker step failed");
                        }

                        Logger.Info("Worker is completed.");
                    }
                }


                if (post.DeclaringType != typeof(AbstractExecutionListener))
                {
                    using (var scope = TransactionScopeManager.CreateScope())
                    {
                        try
                        {
                            returnStatus = Postprocess();
                        }
                        catch (Exception e)
                        {
                            // Need to catch exception to log and set status to FAILED, while
                            // Spring batch would only log and keep the status COMPLETED
                            Logger.Error(e, "Exception during postprocessor");
                            stepExecution.UpgradeStatus(BatchStatus.Failed);
                            throw;
                        }
                        scope.Complete();
                    }
                }
            }
            // batch failed need to join the thread
            else if (stepExecution.remoteChunking != null)
            {
                stepExecution.remoteChunking.controlThread.Join();
            }

            return(returnStatus);
        }
        public void EbcdicFileTestTransactionalWrite()
        {
            // local resources
            IResource fileResource     = new FileSystemResource(new FileInfo("C:/temp/outputs/PersonWritten.txt"));
            var       executionContext = new ExecutionContext();
            FileInfo  fileInfo         = new FileInfo("Ebcdic/Resources/copybooks/Person.fileformat");

            IResource copybookResource = new FileSystemResource(fileInfo);

            //1. WRITE
            EbcdicWriterMapper writerMapper = new EbcdicWriterMapper();

            writerMapper.AfterPropertiesSet();

            var writer = new EbcdicFileWriter <Ebcdic.Test.Person>
            {
                AppendAllowed      = false,
                WriteRdw           = false,
                Name               = "PersonWriter",
                Resource           = fileResource,
                EbcdicWriterMapper = writerMapper,
                DefaultValue       = EbcdicEncoder.DefaultValue.LowValue,
                Copybooks          = new List <IResource> {
                    new FileSystemResource(fileInfo)
                }
            };

            writer.AfterPropertiesSet();
            writer.Open(executionContext);

            try
            {
                for (int i = 0; i < CountTransactions; i++)
                {
                    using (TransactionScope scope = TransactionScopeManager.CreateScope())
                    {
                        writer.Write(GetPersons(i));
                        if (i == CountTransactions - 1) //SIMULATE FAILURE
                        {
                            throw new Exception("Bailing out ... should rollback ...");
                        }
                        scope.Complete();
                    }
                }
            }
            catch (Exception)
            {
                // DISCARDED (JUST TO AVOID UNIT TEST FAILURE ...)
            }
            writer.Close();

            Assert.IsTrue(System.IO.File.Exists("C:/temp/outputs/PersonWritten.txt"));
            Assert.IsTrue(new FileInfo("C:/temp/outputs/PersonWritten.txt").Length > 0);

            //2.READ WHAT WAS WRITTEN
            var reader = new EbcdicFileReader <Ebcdic.Test.Person>
            {
                EbcdicReaderMapper = new PersonMapper(),
                Rdw       = false,
                Resource  = fileResource,
                Name      = "PersonReader",
                SaveState = false,
                Copybook  = copybookResource
            };

            reader.AfterPropertiesSet();

            var persons = new List <Ebcdic.Test.Person>();

            reader.Open(executionContext);
            Ebcdic.Test.Person person;
            while ((person = reader.Read()) != null)
            {
                persons.Add(person);
            }
            reader.Close();

            Assert.AreEqual(CountObject * (CountTransactions - 1), persons.Count);
            foreach (Ebcdic.Test.Person p in persons)
            {
                Assert.AreEqual(p.Id, p.Value);
                Assert.IsTrue(p.Name.StartsWith("Name_" + p.Id));
            }
        }