| Quintiq file version 2.0 | 
| #parent: #root | 
| Method DoFinalizeCurrentComponent (LibOpt_Task task, output Boolean hascreatedstream_o) as stream[JSON] | 
| { | 
|   Description: | 
|   [* | 
|     Finalize the current component.  | 
|     This method calls the `task.Delete()` method, which calls the 'public' `OnFinalize` method if it has not been called before. Therefore, AE code in `OnFinalize` is only executed after a dataset copy is created or after a breakpoint is triggered. | 
|     `task.Delete()` will always be called after the task of the downstream components are deleted, but before the tasks of the upstream components are deleted.  | 
|     Note that this method (or `HasBreakpoint` and `LibOpt_DatasetCopyConditional::DoFinalizeDataset`) do not call any reactive methods if there are no breakpoints or dataset copies on this component. | 
|     This is done for performance reasons to ensure that no unneeded transactions are started. | 
|   *] | 
|   TextBody: | 
|   [* | 
|     // Conditionally create a copy of the current dataset. | 
|     // We always make a robust dataset copy, because AE code in OnFinalize (which is called when task.Delete() happens) might throw an error. | 
|     // We can probably find some cases in which we can create a quick dataset copy, but this might cause errors if any changes are made to the DoFinalize methods. | 
|     LibOpt_DatasetCopyConditional::CopyDatasetConditionally( LibOpt_Component::ComponentPosition_Finalize(), task, true );    | 
|      | 
|     snapshotcomponent := task.SnapshotComponent(); | 
|     run := task.Run(); | 
|     streamJSON := stream[JSON]::Success(); | 
|     breakpoint_stream := null( stream[Void] ); | 
|     // It is intentional that a breakpoint can be triggered when this method is called procedurally | 
|     // Because this method might be called procedurally for performance reasons. This doesn't mean that we don't want a breakpoint. | 
|     if( this.HasBreakpoint( LibOpt_Component::ComponentPosition_Finalize(), task, breakpoint_stream ) ) | 
|     { | 
|       streamJSON := breakpoint_stream | 
|                     // We don't want to include the breakpoint duration in the DoFinalize snapshot timestamp,  | 
|                     // because we are only interested in the performance of the code, not in the pause duration. | 
|                     // The time required for copying the dataset is also not included, because dataset copies are also ignored by the Operation time stamp. | 
|                     ->|snapshotcomponent->LibOpt_SnapshotComponent::SetTimeStampDoFinalize( run ) | 
|                     ->|streamJSON; | 
|       hascreatedstream_o := true; | 
|     } | 
|     else | 
|     { | 
|       LibOpt_SnapshotComponent::SetTimeStampDoFinalize( snapshotcomponent, run ); | 
|     } | 
|      | 
|     // Finalize the datasets that were created on this component.  | 
|     // Note that hascreatedstream_o is an output variable of DoFinalizeDataset. | 
|     streamJSON := LibOpt_DatasetCopyConditional::DoFinalizeDataset( streamJSON, task, hascreatedstream_o ); | 
|      | 
|     if( hascreatedstream_o ) | 
|     { | 
|       // 'task' can only be deleted after breakpoints and dataset copies are handled. We use a stream to ensure that this happens. | 
|       streamJSON := streamJSON | 
|                     ->|task->( t ) | 
|                     { | 
|                       // Using a reactive code block to call t.Delete() and snapshotcomponent.SetTimeStampDoFinalizeDone() in the same transaction. | 
|                       // This ensures that the timestamp is always set right after the deletion of the task. | 
|                       t.Finalize(); | 
|                       t.Delete(); | 
|                       LibOpt_SnapshotComponent::SetTimeStampDoFinalizeDone( snapshotcomponent, run ); | 
|                     } | 
|                     ->|streamJSON; | 
|     } | 
|     else | 
|     { | 
|       // If there are no breakpoints or datasets on this component, then task.Delete() will be called procedurally.  | 
|       // This ensures that the optimizer does not slow down (by starting new transactions) when the AE is not debugging the optimizer. | 
|       task.Finalize(); | 
|       task.Delete(); | 
|       LibOpt_SnapshotComponent::SetTimeStampDoFinalizeDone( snapshotcomponent, run ); | 
|     } | 
|     return streamJSON; | 
|   *] | 
|   InterfaceProperties { Accessibility: 'Module' } | 
| } |