package Ġcore . a as Ċ Ċ import Ġcom . fasterxml . jackson . annotation . JsonProperty Ċ import Ġcore . db . Asset Ċ import Ġcore . db . Auto Exercise Ċ import Ġcore . db . Auto Exercise Executor Ċ import Ġcore . db . Executor Ċ import Ġmu . Kotlin Logging Ċ import Ġorg . jetbrains . ex posed . dao . Entity ID Ċ import Ġorg . jetbrains . ex posed . sql . Sql Expression Builder Ċ import Ġorg . jetbrains . ex posed . sql . select Ċ import Ġorg . jetbrains . ex posed . sql . transactions . transaction Ċ import Ġorg . jetbrains . ex posed . sql . update Ċ import Ġorg . springframework . web . client . Rest Template ĊĊ Ċ // ĠTODO : Ġto Ġconf Ċ private Ġconst Ġval ĠEXEC UT OR _ GR ADE _ URL Ġ= Ġ"/ v 1 / grade " Ċ Ċ private Ġval Ġlog Ġ= ĠKotlin Logging . logger Ġ{} ĊĊ Ċ /** Ċ Ġ* ĠAuto as sess Ġa Ġsolution Ġto Ġan Ġautomatic Ġexercise . Ċ Ġ* ĠThe Ġassessment Ġis Ġperformed Ġsynchronous ly Ġand Ġmay Ġtake Ġa Ġlong Ġtime . Ċ Ġ* Ċ Ġ* Ġ@ throws ĠNo Executors Exception Ġif Ġthere Ġare Ġno Ġexec utors Ġcapable Ġof Ġassess ing Ġthis Ġexercise Ċ Ġ* Ġ@ throws ĠExecutor Over load Exception Ġif Ġall Ġexec utors Ġcapable Ġof Ġassess ing Ġthis Ġexercise Ġare Ġalready Ġover loaded Ċ Ġ* Ġ@ throws ĠExecutor Exception Ġif Ġan Ġexecutor Ġfails Ċ Ġ*/ Ċ fun Ġauto As sess ( auto Exercise Id : ĠEntity ID < Long >, Ġsubmission : ĠString ): ĠAuto Assessment Ġ{ ĊĠĠĠ Ġval Ġauto Exercise Ġ= Ġget Auto Exercise Details ( auto Exercise Id ) ĊĠĠĠ Ġval Ġrequest Ġ= Ġmap To Executor Request ( auto Exercise , Ġsubmission ) ĊĠĠĠ Ġval Ġexec utors Ġ= Ġget Cap able Executors ( auto Exercise Id ) ĊĠĠĠ Ġval Ġselected Executor Ġ= Ġselect Executor ( exec utors ) ĊĠĠĠ Ġreturn Ġcall Executor ( selected Executor , Ġrequest ) Ċ } ĊĊ Ċ private Ġdata Ġclass ĠAuto As sess Exercise Details ( ĊĠĠĠĠĠĠĠ Ġval Ġgrad ing Script : ĠString , Ġval Ġcontainer Image : ĠString , Ġval Ġmax Time : ĠInt , Ġval Ġmax Mem : ĠInt , ĊĠĠĠĠĠĠĠ Ġval Ġassets : ĠList < Auto As sess Exercise Asset >) Ċ Ċ private Ġdata Ġclass ĠAuto As sess Exercise Asset ( ĊĠĠĠĠĠĠĠ Ġval ĠfileName : ĠString , Ġval Ġfile Content : ĠString ) Ċ Ċ private Ġdata Ġclass ĠCap able Executor ( ĊĠĠĠĠĠĠĠ Ġval Ġid : ĠLong , Ġval Ġname : ĠString , Ġval ĠbaseUrl : ĠString , Ġval Ġload : ĠInt , Ġval Ġmax Load : ĠInt ) Ċ Ċ data Ġclass ĠAuto Assessment ( ĊĠĠĠĠĠĠĠ Ġval Ġgrade : ĠInt , Ġval Ġfeedback : ĠString ) ĊĊ Ċ private Ġfun Ġget Auto Exercise Details ( auto Exercise Id : ĠEntity ID < Long >): ĠAuto As sess Exercise Details Ġ{ ĊĠĠĠ Ġreturn Ġtransaction Ġ{ ĊĠĠĠĠĠĠĠ Ġval Ġassets Ġ= ĠAsset ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. select Ġ{ ĠAsset . auto Exercise Ġeq Ġauto Exercise Id Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠAuto As sess Exercise Asset ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit [ Asset . fileName ], ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit [ Asset . file Content ] ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ ĠAuto Exercise . select Ġ{ ĠAuto Exercise . id Ġeq Ġauto Exercise Id Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠAuto As sess Exercise Details ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit [ Auto Exercise . grading Script ], ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit [ Auto Exercise . container Image ], ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit [ Auto Exercise . max Time ], ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit [ Auto Exercise . max Mem ], ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġassets ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. first () ĊĠĠĠ Ġ} Ċ } ĊĊ Ċ data Ġclass ĠExecutor Request ( ĊĠĠĠĠĠĠĠ Ġ@ JsonProperty (" submission ") Ġval Ġsubmission : ĠString , ĊĠĠĠĠĠĠĠ Ġ@ JsonProperty (" grading _ script ") Ġval Ġgrad ing Script : ĠString , ĊĠĠĠĠĠĠĠ Ġ@ JsonProperty (" assets ") Ġval Ġassets : ĠList < Executor Request Asset >, ĊĠĠĠĠĠĠĠ Ġ@ JsonProperty (" image _ name ") Ġval Ġimage Name : ĠString , ĊĠĠĠĠĠĠĠ Ġ@ JsonProperty (" max _ time _ sec ") Ġval Ġmax Time : ĠInt , ĊĠĠĠĠĠĠĠ Ġ@ JsonProperty (" max _ mem _ mb ") Ġval Ġmax Mem : ĠInt ) Ċ Ċ data Ġclass ĠExecutor Request Asset ( ĊĠĠĠĠĠĠĠ Ġ@ JsonProperty (" file _ name ") Ġval ĠfileName : ĠString , ĊĠĠĠĠĠĠĠ Ġ@ JsonProperty (" file _ content ") Ġval Ġfile Content : ĠString ) ĊĊ Ċ private Ġfun Ġmap To Executor Request ( exercise : ĠAuto As sess Exercise Details , Ġsubmission : ĠString ): ĠExecutor Request Ġ= ĊĠĠĠĠĠĠĠ ĠExecutor Request ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġsubmission , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexercise . grading Script , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexercise . assets . map Ġ{ ĠExecutor Request Asset ( it . fileName , Ġit . file Content ) Ġ}, ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexercise . container Image , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexercise . max Time , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexercise . max Mem ĊĠĠĠĠĠĠĠ Ġ) Ċ Ċ private Ġfun Ġget Cap able Executors ( auto Exercise Id : ĠEntity ID < Long >): ĠSet < Cap able Executor > Ġ{ ĊĠĠĠ Ġreturn Ġtransaction Ġ{ ĊĠĠĠĠĠĠĠ Ġ( Executor Ġinner Join ĠAuto Exercise Executor ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. select Ġ{ ĠAuto Exercise Executor . auto Exercise Ġeq Ġauto Exercise Id Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠCap able Executor ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit [ Executor . id ]. value , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit [ Executor . name ], ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit [ Executor . baseUrl ], ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit [ Executor . load ], ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit [ Executor . max Load ]) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. toSet () ĊĠĠĠ Ġ} Ċ } Ċ Ċ private Ġfun Ġselect Executor ( exec utors : ĠSet < Cap able Executor >): ĠCap able Executor Ġ{ ĊĠĠĠ Ġif Ġ( exec utors . isEmpty ()) Ġ{ ĊĠĠĠĠĠĠĠ Ġthrow ĠNo Executors Exception (" No Ġcapable Ġexec utors Ġfound Ġfor Ġthis Ġauto Ġexercise ") ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġval Ġexecutor Ġ= Ġexec utors . reduce Ġ{ Ġbest Exec , Ġcurrent Exec Ġ-> ĊĠĠĠĠĠĠĠ Ġif Ġ( current Exec . load Ġ/ Ġcurrent Exec . max Load Ġ< Ġbest Exec . load Ġ/ Ġbest Exec . max Load ) Ġcurrent Exec Ġelse Ġbest Exec ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġif Ġ( executor . load Ġ>= Ġexecutor . max Load ) Ġ{ ĊĠĠĠĠĠĠĠ Ġthrow ĠExecutor Over load Exception (" All Ġcapable Ġexec utors Ġat Ġmax Ġload ") ĊĠĠĠ Ġ} ĊĠĠĠ Ġreturn Ġexecutor Ċ } ĊĊ Ċ data Ġclass ĠExecutor Response ( ĊĠĠĠĠĠĠĠ Ġ@ JsonProperty (" grade ") Ġval Ġgrade : ĠInt , ĊĠĠĠĠĠĠĠ Ġ@ JsonProperty (" feedback ") Ġval Ġfeedback : ĠString ) Ċ Ċ private Ġfun Ġcall Executor ( executor : ĠCap able Executor , Ġrequest : ĠExecutor Request ): ĠAuto Assessment Ġ{ ĊĠĠĠ Ġinc Executor Load ( executor . id ) ĊĠĠĠ Ġtry Ġ{ ĊĠĠĠĠĠĠĠ Ġlog . info Ġ{ Ġ" Calling Ġexecutor Ġ${ executor . name }, Ġload Ġis Ġnow Ġ${ get Executor Load ( executor . id )}" Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġtemplate Ġ= ĠRest Template () ĊĠĠĠĠĠĠĠ Ġval Ġresponse Entity Ġ= Ġtemplate . post For Entity ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġexecutor . baseUrl Ġ+ ĠEXEC UT OR _ GR ADE _ URL , Ġrequest , ĠExecutor Response :: class . java ) ĊĊĠĠĠĠĠĠĠ Ġif Ġ( response Entity . statusCode . isError ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlog . error Ġ{ Ġ" Executor Ġerror Ġ${ response Entity . statusCode Value } Ġwith Ġrequest Ġ$ request " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠExecutor Exception (" Executor Ġerror Ġ(${ response Entity . statusCode Value }) ") ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġval Ġresponse Ġ= Ġresponse Entity . body ĊĠĠĠĠĠĠĠ Ġif Ġ( response Ġ== Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlog . error Ġ{ Ġ" Executor Ġresponse Ġis Ġempty Ġwith Ġrequest Ġ$ request " Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠ Ġthrow ĠExecutor Exception (" Executor Ġerror Ġ( empty Ġbody )") ĊĠĠĠĠĠĠĠ Ġ} ĊĊĠĠĠĠĠĠĠ Ġreturn ĠAuto Assessment ( response . grade , Ġresponse . feedback ) ĊĊĠĠĠ Ġ} Ġfinally Ġ{ ĊĠĠĠĠĠĠĠ Ġdec Executor Load ( executor . id ) ĊĠĠĠĠĠĠĠ Ġlog . info Ġ{ Ġ" Call Ġfinished Ġto Ġexecutor Ġ${ executor . name }, Ġload Ġis Ġnow Ġ${ get Executor Load ( executor . id )}" Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ private Ġfun Ġinc Executor Load ( executor Id : ĠLong ) Ġ{ ĊĠĠĠ Ġtransaction Ġ{ ĊĠĠĠĠĠĠĠ ĠExecutor . update ({ ĠExecutor . id Ġeq Ġexecutor Id Ġ}) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwith ( Sql Expression Builder ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . update ( load , Ġload Ġ+ Ġ 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ private Ġfun Ġdec Executor Load ( executor Id : ĠLong ) Ġ{ ĊĠĠĠ Ġtransaction Ġ{ ĊĠĠĠĠĠĠĠ ĠExecutor . update ({ ĠExecutor . id Ġeq Ġexecutor Id Ġ}) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġwith ( Sql Expression Builder ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġit . update ( load , Ġload Ġ- Ġ 1 ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} Ċ } Ċ Ċ private Ġfun Ġget Executor Load ( executor Id : ĠLong ): ĠInt Ġ{ ĊĠĠĠ Ġreturn Ġtransaction Ġ{ ĊĠĠĠĠĠĠĠ ĠExecutor . slice ( Executor . load ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. select Ġ{ ĠExecutor . id Ġeq Ġexecutor Id Ġ} ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġ. map Ġ{ Ġit [ Executor . load ] Ġ} [ 0 ] ĊĠĠĠ Ġ} Ċ } Ċ