Blame | Last modification | View Log | RSS feed
//---------------------------------------------------------------------------#pragma warn -com#include <LoggingMacros.h>#pragma warn +com#pragma hdrstop#include "UdTransferManager.h"#include "UdTransferThread.h"#include "DataModule.h"#include "UdTransferHistory.h"#include "IDevice.h"//---------------------------------------------------------------------------namespace{AnsiString GetSQLDateTime( TDateTime datetime ){AnsiString sqldate;sqldate.sprintf("TO_DATE('%s','YYYY-MM-DD HH24:MI:SS')",datetime.FormatString("yyyy-mm-dd hh:nn:ss").c_str());return sqldate;}}//---------------------------------------------------------------------------#pragma package(smart_init)UdTransferManager::UdTransferManager() :m_deviceSimulatorFactory( 0 ){// Get required settingsm_username = getenv("USERNAME");m_hostname = getenv("COMPUTERNAME");if( m_username.IsEmpty() ){char name[ 256 ];unsigned long size = sizeof( name );if( GetUserName( name, &size ) ){m_username = name;}}if( m_hostname.IsEmpty() ){char name[ 256 ];unsigned long size = sizeof( name );if( GetComputerName( name, &size ) ){m_hostname = name;}}m_tasksLock = new Syncobjs::TCriticalSection;// Load the device simulator librarym_deviceSimulatorWrapperDll = ::LoadLibrary("DeviceSimulatorWrapperP.dll");if( m_deviceSimulatorWrapperDll == NULL ){MessageDlg("Failed to load library 'DeviceSimulatorWrapperP.dll'.\nDevice simulation functionality will not be available.",mtError, TMsgDlgButtons() << mbOK, 0 );}else{// Get a device factory instancem_getDeviceFactory = reinterpret_cast< getDeviceFactory_t >(::GetProcAddress( m_deviceSimulatorWrapperDll, "getDeviceFactory" ) );if( m_getDeviceFactory == NULL ){MessageDlg("Failed to get device factory from library 'DeviceSimulatorWrapperP.dll'.\nDevice simulation functionality will not be available.",mtError, TMsgDlgButtons() << mbOK, 0 );}else{m_deviceSimulatorFactory = m_getDeviceFactory();}}}//---------------------------------------------------------------------------UdTransferManager::~UdTransferManager(){UdTransferThreadItem thread = m_threads.begin();for( ; thread != m_threads.end(); thread++ ){if( (*thread).second != NULL ){(*thread).second->StopTransfer();delete (*thread).second;}}m_threads.clear();delete m_tasksLock;if( m_deviceSimulatorWrapperDll != NULL ){// Freeing the library deletes the factory instanceFreeLibrary( m_deviceSimulatorWrapperDll );m_deviceSimulatorFactory = 0;}}//---------------------------------------------------------------------------void UdTransferManager::AddNewTask( const UdTransferTask & task ){// Add the new task to the databaseTADOQuery * txnquery = new TADOQuery(NULL);if( txnquery == NULL ) return;txnquery->Connection = Data_Module->IntegrationDBConnection;AnsiString sql_statement;sql_statement.sprintf("insert into TRANSFER_HISTORY "" (ADDED_TIME, USERNAME, HOSTNAME, STATUS, "" RAMP_TIME, SOURCE_PATH, BATCH_SIZE, "" DURATION, FREQUENCY, RECURRING, "" RAMP_TYPE, RAMP_GRADIENT, DESTINATION) ""values (sysdate, '%s', '%s', %d, "" %s, '%s', %d, "" %d, %d, %d, "" %d, %f, '%s') ",m_username, m_hostname, (int)UdTransferPending,GetSQLDateTime(task.rampTime), task.sourcePath, task.batchSize,task.duration, task.frequency, task.recurring,(int)task.rampType, task.gradient, task.destination);txnquery->SQL->Text = sql_statement;if( txnquery->ExecSQL() != 1 ){MERROR( "Failed to add new UD transfer task to the DB" );}txnquery->Close();// Now get its id and add it to our listsql_statement.sprintf("select TRANSFER_NO, ADDED_TIME ""from TRANSFER_HISTORY ""where USERNAME = '%s' and "" HOSTNAME = '%s' and "" STATUS = %d and "" RAMP_TIME = %s and "" BATCH_SIZE = %d and "" DURATION = %d and "" FREQUENCY = %d and "" RECURRING = %d and "" RAMP_TYPE = %d and "" RAMP_GRADIENT = %f ""order by ADDED_TIME desc ",m_username, m_hostname, (int)UdTransferPending,GetSQLDateTime(task.rampTime), task.batchSize,task.duration, task.frequency, task.recurring,(int)task.rampType, task.gradient);txnquery->SQL->Text = sql_statement;txnquery->Open();UdTransferTask newTask( task );if( !txnquery->Eof ){newTask.id = txnquery->FieldByName("TRANSFER_NO")->AsInteger;m_tasksLock->Acquire();m_tasks.push_back( newTask );m_tasksLock->Release();if( !LaunchTask( newTask ) ){MERROR( "Failed to launch newly added task (" << newTask.id << ")" );}}else{MERROR( "Failed to retrieve ID of added UD transfer task" );}delete txnquery;}//---------------------------------------------------------------------------void UdTransferManager::LoadPendingTasks(){TADOQuery * txnquery = new TADOQuery(NULL);if( txnquery == NULL ) return;txnquery->Connection = Data_Module->IntegrationDBConnection;AnsiString sql_statement;sql_statement.sprintf("select TRANSFER_NO, BATCH_SIZE, DURATION, FREQUENCY, "" RECURRING, SOURCE_PATH, RAMP_TIME, RAMP_TYPE, "" RAMP_GRADIENT, STATUS, DESTINATION ""from TRANSFER_HISTORY ""where STATUS = %d and "" USERNAME = '%s' and "" HOSTNAME = '%s' ",(int)UdTransferPending,m_username,m_hostname);txnquery->SQL->Text = sql_statement;txnquery->Open();UdTransferTask task;while( !txnquery->Eof ){task.id = txnquery->FieldByName("TRANSFER_NO")->AsInteger;task.batchSize = txnquery->FieldByName("BATCH_SIZE")->AsInteger;task.duration = txnquery->FieldByName("DURATION")->AsInteger;task.frequency = txnquery->FieldByName("FREQUENCY")->AsInteger;task.recurring = (txnquery->FieldByName("RECURRING")->AsInteger > 0);task.sourcePath = txnquery->FieldByName("SOURCE_PATH")->AsString;task.rampTime = txnquery->FieldByName("RAMP_TIME")->AsDateTime;task.rampType = (RampTestType)txnquery->FieldByName("RAMP_TYPE")->AsInteger;task.gradient = txnquery->FieldByName("RAMP_GRADIENT")->AsFloat;task.state = (UdTransferTaskState)txnquery->FieldByName("STATUS")->AsInteger;task.destination = txnquery->FieldByName("DESTINATION")->AsString;m_tasksLock->Acquire();m_tasks.push_back( task );m_tasksLock->Release();txnquery->Next();}delete txnquery;if( !m_tasks.empty() ){// Ask user to start any previously pending tasksAnsiString msg;if( m_tasks.size() == 1 ){msg = "There is a UD task currently pending. Do you want to start it now?";}else{msg = "There are " + IntToStr(m_tasks.size()) + " UD transfer tasks currently pending.";msg += "\nDo you want to start them now?";}if( MessageDlg(msg, mtConfirmation, TMsgDlgButtons() << mbYes << mbNo, 0 ) == mbYes ){m_tasksLock->Acquire();try {UdTransferTaskItem it = m_tasks.begin();for( ; it != m_tasks.end(); it++ ){if( (*it).state == UdTransferPending ){LaunchTask( (*it) );}}}__finally{m_tasksLock->Release();}}}}//---------------------------------------------------------------------------void UdTransferManager::UpdateTask( const UdTransferTask & task,const AnsiString & comment ){// Find our locally stored taskm_tasksLock->Acquire();try {UdTransferTaskItem it = m_tasks.begin();for( ; it != m_tasks.end(); it++ ){if( (*it).id == task.id ) break;}if( (it != m_tasks.end()) ) // TODO: && ((*it) != task) ){bool taskDone = (((*it).state > UdTransferAborted) &&(task.state <= UdTransferAborted));TADOQuery * txnquery = new TADOQuery(NULL);if( txnquery == NULL ) return;txnquery->Connection = Data_Module->IntegrationDBConnection;// Find parameters that have changed and add them to the update querystd::stringstream stream;stream << "update TRANSFER_HISTORY set ";if( (*it).batchSize != task.batchSize ) stream << " BATCH_SIZE = " << task.batchSize << ",";if( (*it).duration != task.duration ) stream << " DURATION = " << task.duration << ",";if( (*it).frequency != task.frequency ) stream << " FREQUENCY = " << task.frequency << ",";if( (*it).recurring != task.recurring ) stream << " RECURRING = " << task.recurring << ",";if( (*it).sourcePath != task.sourcePath ) stream << " SOURCE_PATH = '" << task.sourcePath.c_str() << "',";if( (*it).destination != task.destination ) stream << " DESTINATION = '" << task.destination.c_str() << "',";if( (*it).state != task.state ) stream << " STATUS = " << task.state << ",";if( (*it).rampType != task.rampType ) stream << " RAMP_TYPE = " << task.rampType << ",";if( (*it).gradient != task.gradient ) stream << " RAMP_GRADIENT = " << task.gradient << ",";if( (*it).rampTime != task.rampTime ) stream << " RAMP_TIME = " << GetSQLDateTime(task.rampTime).c_str() << ",";if( !comment.IsEmpty() ) stream << " COMMENTS = '" << comment.c_str() << "',";if( taskDone ) stream << " END_TIME = sysdate,";AnsiString sql_statement, temp;temp = stream.str().c_str();temp.Delete(temp.Length(), 1); // Remove last commasql_statement.sprintf("%s where TRANSFER_NO = %d",temp, task.id);txnquery->SQL->Text = sql_statement;if( txnquery->ExecSQL()!= 1 ){MERROR( "Failed to update transfer history on statement: " << sql_statement );}delete txnquery;(*it) = task;if( taskDone ){m_tasks.erase( it );UdTransferThreadItem thread = m_threads.find( task.id );if( thread != m_threads.end() ){(*thread).second->StopTransfer();}}}}__finally{m_tasksLock->Release();}UdTransferHistoryForm->RefreshHistory();}//---------------------------------------------------------------------------bool UdTransferManager::GetTaskDetails( UdTransferTask & task ){bool found = false;m_tasksLock->Acquire();try {UdTransferTaskItem it = m_tasks.begin();for( ; it != m_tasks.end(); it++ ){if( (*it).id == task.id ){found = true;task = (*it);break;}}}__finally{m_tasksLock->Release();}return found;}//---------------------------------------------------------------------------bool UdTransferManager::LaunchTask( const UdTransferTask & task ){bool launched = false;// Ensure we haven't already got a thread for this taskUdTransferThreadItem thread = m_threads.find( task.id );if( thread == m_threads.end() ){m_threads[task.id] = new UdTransferThread( task, this, m_deviceSimulatorFactory );launched = true;}return launched;}//---------------------------------------------------------------------------bool UdTransferManager::GetTaskStatistics( const int & taskId,UdTransferStatistics & stats ){bool found = false;// Check if we are currently processing the device, if so// request the stats from the task threadUdTransferThreadItem thread = m_threads.find( taskId );if( thread != m_threads.end() ){if( (*thread).second != NULL ){(*thread).second->GetTransferStatistics( stats );found = true;}}// Otherwise grab the info from the databaseif( !found ){TADOQuery * txnquery = new TADOQuery(NULL);if( txnquery == NULL ) return false;txnquery->Connection = Data_Module->IntegrationDBConnection;AnsiString sql_statement;sql_statement.sprintf("select ADDED_TIME, END_TIME, NUMBER_FILES, NUMBER_BYTES, BATCH_HISTORY ""from TRANSFER_HISTORY ""where TRANSFER_NO = %d",taskId);txnquery->SQL->Text = sql_statement;txnquery->Open();if( !txnquery->Eof ){stats.completed = true;stats.startTime = txnquery->FieldByName("ADDED_TIME")->AsDateTime;stats.processedFiles = txnquery->FieldByName("NUMBER_FILES")->AsInteger;stats.processedBytes = txnquery->FieldByName("NUMBER_BYTES")->AsInteger;// End time may not be populated in times of program crashes. Ignore the// problem here and handle it when the statistics get used.try{stats.endTime = txnquery->FieldByName("END_TIME")->AsDateTime;}catch( EDatabaseError & e ) { }AnsiString batches = txnquery->FieldByName("BATCH_HISTORY")->AsString;if( !batches.IsEmpty() &&(batches != "(null)") ){// Tokenise our batch history string to our listTStringList * list = new TStringList;try {if( list != NULL ){try {list->CommaText = batches;for( int i = 0; i < list->Count; i++ ){stats.batches.push_back( list->Strings[i].ToInt() );}}catch( EConvertError & e ) {} // Ignore}}__finally{delete list;}}found = true;}delete txnquery;}return found;}//---------------------------------------------------------------------------void UdTransferManager::UpdateTaskStatistics( const int & taskId,const UdTransferStatistics & stats ){// Format the batches list into a comma delimited stringAnsiString batches;BatchSizeItem batch = (int *)stats.batches.begin();for( ; batch != stats.batches.end(); batch++ ){if( batch != stats.batches.begin() ) batches += ",";batches += IntToStr( *batch );}TADOQuery * txnquery = new TADOQuery(NULL);if( txnquery == NULL ) return;txnquery->Connection = Data_Module->IntegrationDBConnection;AnsiString sql_statement;sql_statement.sprintf("update TRANSFER_HISTORY set "" NUMBER_FILES = %d, "" NUMBER_BYTES = %d, "" BATCH_HISTORY = '%s' ""where TRANSFER_NO = %d",stats.processedFiles,stats.processedBytes,batches,taskId);txnquery->SQL->Text = sql_statement;if( txnquery->ExecSQL() != 1 ){MERROR( "Failed to persist transfer statistics to database for task " << taskId );}txnquery->Close();delete txnquery;UdTransferHistoryForm->RefreshHistory();}//---------------------------------------------------------------------------bool UdTransferManager::IsTaskRunning(){bool running = false;UdTransferThreadItem thread = m_threads.begin();for( ; thread != m_threads.end(); thread++ ){if( ((*thread).second != NULL) &&(*thread).second->IsRunning() ){running = true;break;}}return running;}