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' } 
 | 
} 
 |