/// TODO: This is a parallel version of creating a ueb model package initially written /// which was not working due to arcpy licensing issue. This code may be used to develop /// a parallel version of executing various python scripts in this PackageBuilder.cs class file /// <summary> /// Creates all data files and control files needed to run UEB model and then creates a package zip file /// that contains all those files /// </summary> /// <returns>PackageID/JobID which the client can query the server to see the status of package creation</returns> private HttpResponseMessage GetUEBPackageCreateParallel(DateTime startDate, DateTime endDate, byte timeStep) { HttpResponseMessage response = new HttpResponseMessage(); var tokenSource = new CancellationTokenSource(); CancellationToken cancellationToken = tokenSource.Token; List<byte> validTimeStepValues = new List<byte> { 1, 2, 3, 4, 6 }; // validate timeStep if (validTimeStepValues.Contains(timeStep) == false) { string errMsg = string.Format("Provided time setp value ({0}) is invalid", timeStep); logger.Error(errMsg); response.StatusCode = HttpStatusCode.BadRequest; response.Content = new StringContent(errMsg); return response; } // validate start and end dates if (startDate >= endDate) { string errMsg = string.Format("Provided start date value ({0}) is invalid.\n Start date needs to be a date before the end date.", startDate); logger.Error(errMsg); response.StatusCode = HttpStatusCode.BadRequest; response.Content = new StringContent(errMsg); return response; } //generate a guid to pass on the client as a job ID Guid jobGuid = Guid.NewGuid(); try { Task mainTask = new Task(() => { ResponseMessage daymetResponse; //int timeStep = 6; //TODO: this value needs to be passed as a parameter in GetUEBPackage method float constantWindSpeed = UEB.UEBSettings.WATERSHED_CONSTANT_WIND_SPEED; // create a task array to monitor all tasks related to daymet data processing List<Task> daymetTaskList = new List<Task>(); // start a new task to generate netcdf file for the watershed which would also generate watershed buffered shape file Task<HttpResponseMessage> taskCreateWsNetCDFFile = Task<HttpResponseMessage>.Factory.StartNew((t) => GenerateWatershedNetCDFFile(cancellationToken), tokenSource.Token, TaskCreationOptions.AttachedToParent); Helpers.TaskDataStore.SetTask(taskCreateWsNetCDFFile.Id.ToString(), taskCreateWsNetCDFFile); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskCreateWsNetCDFFile.Id.ToString()); // create a task to generate watershed DEM file int gridCellSize = 100; Task<HttpResponseMessage> taskCreateWsDEMFile = new Task<HttpResponseMessage>(() => GenerateWatershedDEMFile(cancellationToken, gridCellSize), tokenSource.Token, TaskCreationOptions.AttachedToParent); // create a task to generate watershed atmospheric pressure value Task<HttpResponseMessage> taskAtmPres = new Task<HttpResponseMessage>(() => GetWatershedAtmosphericPressure(cancellationToken), tokenSource.Token, TaskCreationOptions.AttachedToParent); // create a task for slope generation //Task<HttpResponseMessage> taskSlope = new Task<HttpResponseMessage>(() => // GetWatershedSlopeNetCDFFile(cancellationToken), tokenSource.Token, TaskCreationOptions.AttachedToParent); // create a task for slope generation //Task<HttpResponseMessage> taskAspect = new Task<HttpResponseMessage>(() => // GetWatershedAspectNetCDFFile(cancellationToken), tokenSource.Token, TaskCreationOptions.AttachedToParent); // make it wait since the ws netcdf file creation task uses the same input file as this one try { taskCreateWsNetCDFFile.Wait(); } catch (Exception e) { logger.Info(e.Message); } // start the task to generate ws dem file after the task to generate ws netcdf file/buffered watershed is done taskCreateWsNetCDFFile.ContinueWith((t) => { response = t.Result; if (response.StatusCode != HttpStatusCode.OK) { tokenSource.Cancel(); } else { taskCreateWsDEMFile.Start(); Helpers.TaskDataStore.SetTask(taskCreateWsDEMFile.Id.ToString(), taskCreateWsDEMFile); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskCreateWsDEMFile.Id.ToString()); } }, TaskContinuationOptions.NotOnCanceled); // make it wait since the dem file creation task uses the same input file as this one try { taskCreateWsDEMFile.Wait(); } catch (Exception e) { logger.Info(e.Message); } // start the task to generate atm pressure after the task to generate ws dem file is done taskCreateWsDEMFile.ContinueWith((t) => { response = t.Result; if (response.StatusCode != HttpStatusCode.OK) { tokenSource.Cancel(); } else { taskAtmPres.Start(); Helpers.TaskDataStore.SetTask(taskAtmPres.Id.ToString(), taskAtmPres); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskAtmPres.Id.ToString()); //taskSlope.Start(); //Helpers.TaskDataStore.SetTask(taskSlope.Id.ToString(), taskSlope); //Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskSlope.Id.ToString()); //taskAspect.Start(); //Helpers.TaskDataStore.SetTask(taskAspect.Id.ToString(), taskAspect); //Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskAspect.Id.ToString()); } }, TaskContinuationOptions.NotOnCanceled); // make it wait since the atmo pressure calculation uses the same input file as this one //try //{ // taskAtmPres.Wait(); //} //catch (Exception e) //{ // logger.Info(e.Message); //} // update task data store at the end of tmin task taskAtmPres.ContinueWith(t => { response = t.Result; Helpers.TaskDataStore.SetTaskResult(taskAtmPres.Id.ToString(), response); if (response.StatusCode != HttpStatusCode.OK) { tokenSource.Cancel(); } }, TaskContinuationOptions.NotOnCanceled); // start a task to generate ws slope data Task<HttpResponseMessage> taskSlope = Task<HttpResponseMessage>.Factory.StartNew((t) => GetWatershedSlopeNetCDFFile(cancellationToken), tokenSource.Token, TaskCreationOptions.AttachedToParent); Helpers.TaskDataStore.SetTask(taskSlope.Id.ToString(), taskSlope); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskSlope.Id.ToString()); // make it wait since the aspect calculation uses the same input file as this one //try //{ // taskSlope.Wait(); //} //catch (Exception e) //{ // logger.Info(e.Message); //} // update task data store at the end of slope task taskSlope.ContinueWith(t => { response = t.Result; Helpers.TaskDataStore.SetTaskResult(taskSlope.Id.ToString(), response); if (response.StatusCode != HttpStatusCode.OK) { tokenSource.Cancel(); } }, TaskContinuationOptions.NotOnCanceled); // start a task to generate aspect data Task<HttpResponseMessage> taskAspect = Task<HttpResponseMessage>.Factory.StartNew((t) => GetWatershedAspectNetCDFFile(cancellationToken), tokenSource.Token, TaskCreationOptions.AttachedToParent); Helpers.TaskDataStore.SetTask(taskAspect.Id.ToString(), taskAspect); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskAspect.Id.ToString()); // make it wait since the LatLon calculation uses the same input file as this one //try //{ // taskAspect.Wait(); //} //catch (Exception e) //{ // logger.Info(e.Message); //} // update task data store at the end of aspect task taskAspect.ContinueWith(t => { response = t.Result; Helpers.TaskDataStore.SetTaskResult(taskAspect.Id.ToString(), response); if (response.StatusCode != HttpStatusCode.OK) { tokenSource.Cancel(); } }, TaskContinuationOptions.NotOnCanceled); // start a task to generate ws lat/lon data Task<HttpResponseMessage> taskLatLon = Task<HttpResponseMessage>.Factory.StartNew((t) => GetWatershedLatLonValues(cancellationToken), tokenSource.Token, TaskCreationOptions.AttachedToParent); Helpers.TaskDataStore.SetTask(taskLatLon.Id.ToString(), taskLatLon); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskLatLon.Id.ToString()); // make it wait since the land cover for watershed calculation uses the same input file as this one //try //{ // taskLatLon.Wait(); //} //catch (Exception e) //{ // logger.Info(e.Message); //} // update task data store at the end of tmin task taskLatLon.ContinueWith(t => { response = t.Result; Helpers.TaskDataStore.SetTaskResult(taskLatLon.Id.ToString(), response); if (response.StatusCode != HttpStatusCode.OK) { tokenSource.Cancel(); } }, TaskContinuationOptions.NotOnCanceled); // start a task to generate NLCD dataset for the watershed Task<HttpResponseMessage> taskLandCoverData = Task<HttpResponseMessage>.Factory.StartNew((t) => GetWatershedLandCoverData(cancellationToken), tokenSource.Token, TaskCreationOptions.AttachedToParent); Helpers.TaskDataStore.SetTask(taskLandCoverData.Id.ToString(), taskLandCoverData); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskLandCoverData.Id.ToString()); // set a task to generate land cover variable data Task<HttpResponseMessage> taskLandCoverVariables = new Task<HttpResponseMessage>(() => GetWatershedLandCoverVariablesData(cancellationToken), tokenSource.Token, TaskCreationOptions.AttachedToParent); // start land cover varaible data task when land cover data task ends taskLandCoverData.ContinueWith(t => { response = t.Result; Helpers.TaskDataStore.SetTaskResult(taskLandCoverData.Id.ToString(), response); if (response.StatusCode != HttpStatusCode.OK) { tokenSource.Cancel(); } else if (taskLandCoverVariables.IsCanceled == false) { taskLandCoverVariables.Start(); Helpers.TaskDataStore.SetTask(taskLandCoverVariables.Id.ToString(), taskLandCoverVariables); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskLandCoverVariables.Id.ToString()); } }, TaskContinuationOptions.NotOnCanceled); // update task data store when this task is done taskLandCoverVariables.ContinueWith(t => { response = t.Result; Helpers.TaskDataStore.SetTaskResult(taskLandCoverVariables.Id.ToString(), response); if (response.StatusCode != HttpStatusCode.OK) { tokenSource.Cancel(); } }, TaskContinuationOptions.NotOnCanceled); // put the tmin and tmax tasks into an array to monitor when both of them get finished Task<ResponseMessage>[] tMinTmaxTasks = new Task<ResponseMessage>[2]; // start a task to generate daily single tmin data netcdf file for the watershed string outputTminDataVarName = "tmin"; string inputDaymetTminFileNamePattern = "tmin*.nc"; Task<ResponseMessage> taskTmin = Task<ResponseMessage>.Factory.StartNew((t) => { return DataProcessor.GetWatershedSingleTempDataPointNetCDFFile(cancellationToken, outputTminDataVarName, inputDaymetTminFileNamePattern, _packageRequestProcessRootDirPath, startDate, endDate); }, tokenSource.Token, TaskCreationOptions.AttachedToParent); Helpers.TaskDataStore.SetTask(taskTmin.Id.ToString(), taskTmin); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskTmin.Id.ToString()); tMinTmaxTasks[0] = taskTmin; daymetTaskList.Add(taskTmin); // make this wait as the following tmax task uses the same input file //try //{ // taskTmin.Wait(); //} //catch (Exception e) //{ // logger.Info(e.Message); //} //string outputTmaxDataVarName = "tmax"; //string inputDaymetTmaxFileNamePattern = "tmax*.nc"; //Task<ResponseMessage> taskTmax = new Task<ResponseMessage>(() => // DataProcessor.GetWatershedSingleTempDataPointNetCDFFile(cancellationToken, outputTmaxDataVarName, inputDaymetTmaxFileNamePattern)); // update task data store at the end of tmin task taskTmin.ContinueWith(t => { daymetResponse = t.Result; if (daymetResponse.StatusCode != ResponseStatus.OK) { tokenSource.Cancel(); } Helpers.TaskDataStore.SetTaskResult(taskTmin.Id.ToString(), daymetResponse); }, TaskContinuationOptions.NotOnCanceled); // start a task to generate daily single tmax data netcdf file for the watershed string outputTmaxDataVarName = "tmax"; string inputDaymetTmaxFileNamePattern = "tmax*.nc"; Task<ResponseMessage> taskTmax = Task<ResponseMessage>.Factory.StartNew((t) => { return DataProcessor.GetWatershedSingleTempDataPointNetCDFFile(cancellationToken, outputTmaxDataVarName, inputDaymetTmaxFileNamePattern, _packageRequestProcessRootDirPath, startDate, endDate); }, tokenSource.Token, TaskCreationOptions.AttachedToParent); Helpers.TaskDataStore.SetTask(taskTmax.Id.ToString(), taskTmax); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskTmax.Id.ToString()); tMinTmaxTasks[1] = taskTmax; daymetTaskList.Add(taskTmax); // make this wait as the following tmax task uses the same input file //try //{ // taskTmax.Wait(); //} //catch (Exception e) //{ // logger.Info(e.Message); //} // create a task that will monitor when all tasks in tMinTmaxTasks array are complete Task tMinTMaxTaskManager = Task.WhenAll(tMinTmaxTasks); // put the multiple temp and vp tasks into an array to monitor when they both get done so that we can start // the task for multiple rh data file generation Task<ResponseMessage>[] taVpMultipleTasks = new Task<ResponseMessage>[2]; // set a task to generate daily multiple temperature data netcdf file for watershed when tmin and tmax netcdf file generation have finished Task<ResponseMessage> taskMultipleTemp = new Task<ResponseMessage>(() => DataProcessor.GetWatershedMultipleTempDataPointsNetCDFFile(cancellationToken, timeStep, _packageRequestProcessRootDirPath, startDate), tokenSource.Token, TaskCreationOptions.AttachedToParent); daymetTaskList.Add(taskMultipleTemp); taVpMultipleTasks[0] = taskMultipleTemp; tMinTMaxTaskManager.ContinueWith(t => { if (taskMultipleTemp.IsCanceled == false) { taskMultipleTemp.Start(); Helpers.TaskDataStore.SetTask(taskMultipleTemp.Id.ToString(), taskMultipleTemp); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskMultipleTemp.Id.ToString()); } }); // set a task to generate daily multiple vp data netcdf file for waterhed Task<ResponseMessage> taskMultipleVp = new Task<ResponseMessage>(() => DataProcessor.GetWatershedMultipleVaporPresDataPointsNetCDFFile(cancellationToken, timeStep, _packageRequestProcessRootDirPath, startDate), tokenSource.Token, TaskCreationOptions.AttachedToParent); daymetTaskList.Add(taskMultipleVp); taVpMultipleTasks[1] = taskMultipleVp; // create a task that will monitor when all task in taVpMultipleTasks array completes Task taVpMultipleTaskManager = Task.WhenAll(taVpMultipleTasks); // when tmax data generation completes (tmin task is also done at this time), start ta multiplda daily data genration task taskTmax.ContinueWith(t => { daymetResponse = t.Result; Helpers.TaskDataStore.SetTaskResult(taskTmax.Id.ToString(), daymetResponse); if (daymetResponse.StatusCode != ResponseStatus.OK) { tokenSource.Cancel(); } else if (taskMultipleTemp.IsCanceled == false) { //taskMultipleTemp.Start(); //Helpers.TaskDataStore.SetTask(taskMultipleTemp.Id.ToString(), taskMultipleTemp); //Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskMultipleTemp.Id.ToString()); } }, TaskContinuationOptions.NotOnCanceled); // start a task to generate daily single vapor pressure netcdf file for watershed - note this task may start independent of tmax and ta multiple data generation tasks string inputDaymetVpFileNamePattern = "vp*.nc"; Task<ResponseMessage> taskVp = Task<ResponseMessage>.Factory.StartNew((t) => { return DataProcessor.GetWatershedSingleVaporPresDataPointNetCDFFile(cancellationToken, inputDaymetVpFileNamePattern, _packageRequestProcessRootDirPath, startDate, endDate); }, tokenSource.Token, TaskCreationOptions.AttachedToParent); Helpers.TaskDataStore.SetTask(taskVp.Id.ToString(), taskVp); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskVp.Id.ToString()); daymetTaskList.Add(taskVp); //make this wait since the single precp task uses the same input file //try //{ // taskVp.Wait(); //} //catch (Exception e) //{ // logger.Info(e.Message); //} // start a task to generate daily single prec netcdf file for watershed string inputDaymetPrcpFileNamePattern = "prcp*.nc"; Task<ResponseMessage> taskPrecp = Task<ResponseMessage>.Factory.StartNew((t) => { return DataProcessor.GetWatershedSinglePrecpDataPointNetCDFFile(cancellationToken, inputDaymetPrcpFileNamePattern, _packageRequestProcessRootDirPath, startDate, endDate); }, tokenSource.Token, TaskCreationOptions.AttachedToParent); Helpers.TaskDataStore.SetTask(taskPrecp.Id.ToString(), taskPrecp); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskPrecp.Id.ToString()); daymetTaskList.Add(taskPrecp); // set a task to generate daily multiple prec data netcdf file for waterhed Task<ResponseMessage> taskMultiplePrecp = new Task<ResponseMessage>(() => DataProcessor.GetWatershedMultiplePrecpDataPointsNetCDFFile(cancellationToken, timeStep, _packageRequestProcessRootDirPath, startDate), tokenSource.Token, TaskCreationOptions.AttachedToParent); daymetTaskList.Add(taskMultiplePrecp); // when the daily single prec netcdf task ends start the daily multiple precp task taskPrecp.ContinueWith(t => { daymetResponse = t.Result; Helpers.TaskDataStore.SetTaskResult(taskPrecp.Id.ToString(), daymetResponse); if (daymetResponse.StatusCode != ResponseStatus.OK) { tokenSource.Cancel(); } else if (taskMultiplePrecp.IsCanceled == false) { taskMultiplePrecp.Start(); Helpers.TaskDataStore.SetTask(taskMultiplePrecp.Id.ToString(), taskMultiplePrecp); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskMultiplePrecp.Id.ToString()); } }, TaskContinuationOptions.NotOnCanceled); // set a task to generate daily multiple wind data netcdf file for watershed Task<ResponseMessage> taskMultipleWind = new Task<ResponseMessage>(() => DataProcessor.GetWatershedMultipleWindDataPointsNetCDFFile(cancellationToken, constantWindSpeed, _packageRequestProcessRootDirPath), tokenSource.Token, TaskCreationOptions.AttachedToParent); daymetTaskList.Add(taskMultipleWind); // when daily multiple precp task is done start the multiple wind task - wind task uses the precp netcdf file taskMultiplePrecp.ContinueWith(t => { daymetResponse = t.Result; Helpers.TaskDataStore.SetTaskResult(taskMultiplePrecp.Id.ToString(), daymetResponse); if (daymetResponse.StatusCode != ResponseStatus.OK) { tokenSource.Cancel(); } else if (taskMultipleWind.IsCanceled == false) { taskMultipleWind.Start(); Helpers.TaskDataStore.SetTask(taskMultipleWind.Id.ToString(), taskMultipleWind); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskMultipleWind.Id.ToString()); } }, TaskContinuationOptions.NotOnCanceled); // when daily multiple wind task is done update the task data store taskMultipleWind.ContinueWith(t => { daymetResponse = t.Result; Helpers.TaskDataStore.SetTaskResult(taskMultipleWind.Id.ToString(), daymetResponse); if (daymetResponse.StatusCode != ResponseStatus.OK) { tokenSource.Cancel(); } }, TaskContinuationOptions.NotOnCanceled); // when the daily single vp netcdf task ends start the daily multiple vp task taskVp.ContinueWith(t => { daymetResponse = t.Result; Helpers.TaskDataStore.SetTaskResult(taskVp.Id.ToString(), daymetResponse); if (daymetResponse.StatusCode != ResponseStatus.OK) { tokenSource.Cancel(); } else if (taskMultipleVp.IsCanceled == false) { taskMultipleVp.Start(); Helpers.TaskDataStore.SetTask(taskMultipleVp.Id.ToString(), taskMultipleVp); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskMultipleVp.Id.ToString()); } }, TaskContinuationOptions.NotOnCanceled); // when daily multiple vp task is done update the task data store taskMultipleVp.ContinueWith(t => { daymetResponse = t.Result; Helpers.TaskDataStore.SetTaskResult(taskMultipleVp.Id.ToString(), daymetResponse); if (daymetResponse.StatusCode != ResponseStatus.OK) { tokenSource.Cancel(); } }, TaskContinuationOptions.NotOnCanceled); // set a task to generate daily multiple rh data netcdf file for waterhed Task<ResponseMessage> taskMultipleRH = new Task<ResponseMessage>(() => DataProcessor.GetWatershedMultipleRHDataPointsNetCDFFile(cancellationToken, timeStep, _packageRequestProcessRootDirPath), tokenSource.Token, TaskCreationOptions.AttachedToParent); daymetTaskList.Add(taskMultipleRH); // start the multiple daily rh task when multiple temp and multiple vp tasks have finished taVpMultipleTaskManager.ContinueWith((t) => { if (taskMultipleRH.IsCanceled == false) { taskMultipleRH.Start(); Helpers.TaskDataStore.SetTask(taskMultipleRH.Id.ToString(), taskMultipleRH); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), taskMultipleRH.Id.ToString()); } }, TaskContinuationOptions.NotOnCanceled); // when daily multiple rh task is done update the task data store taskMultipleRH.ContinueWith(t => { daymetResponse = t.Result; Helpers.TaskDataStore.SetTaskResult(taskMultipleRH.Id.ToString(), daymetResponse); if (daymetResponse.StatusCode != ResponseStatus.OK) { tokenSource.Cancel(); } }, TaskContinuationOptions.NotOnCanceled); // set a task to monitor all daymet data processing tasks we have defined above Task daymetTaskManager = Task.WhenAll(daymetTaskList); // create a task to generate the packgae zip file Task<HttpResponseMessage> pkgTask = new Task<HttpResponseMessage>(() => CreateUEBpackageZipFile(jobGuid.ToString(), startDate, endDate, timeStep, null), tokenSource.Token, TaskCreationOptions.AttachedToParent); // when all daymet tasks are done, start the task for creating the package zip file daymetTaskManager.ContinueWith((t) => { pkgTask.Start(); Helpers.TaskDataStore.SetTask(pkgTask.Id.ToString(), pkgTask); Helpers.TaskDataStore.SetChildTask(jobGuid.ToString(), pkgTask.Id.ToString()); }, TaskContinuationOptions.NotOnCanceled); }, tokenSource.Token); mainTask.Start(); Helpers.TaskDataStore.SetTask(jobGuid.ToString(), mainTask); mainTask.ContinueWith((t) => { if (mainTask.IsCanceled || mainTask.IsFaulted || tokenSource.IsCancellationRequested) { CleanUpOnFailure(); string errMsg = "UEB pacakage could not be created."; logger.Info(errMsg); //UpdatePackageBuildStatusFile(PackageBuildStatus.Error); } else { response.StatusCode = HttpStatusCode.OK; response.Content = new StringContent("UEB package creation is complete for job id:" + jobGuid); Helpers.TaskDataStore.SetTaskResult(jobGuid.ToString(), response); logger.Info(response.Content.ToString()); //UpdatePackageBuildStatusFile(PackageBuildStatus.Complete); } }, TaskContinuationOptions.NotOnCanceled); } catch (AggregateException e) { string responseMsg = string.Empty; foreach (var v in e.InnerExceptions) { responseMsg += v.Message + "\n"; } logger.Error(responseMsg); } catch (Exception ex) { tokenSource.Cancel(); string errMsg = "UEB package creation failed.\n" + ex.Message; logger.Error(errMsg); } PackageCreationStatus pkgStatus = new PackageCreationStatus(); pkgStatus.Message = "UEB package creation has started. When done you will be notified."; pkgStatus.PackageID = jobGuid.ToString(); string jsonResponse = JsonConvert.SerializeObject(pkgStatus, Formatting.Indented); response.StatusCode = HttpStatusCode.OK; response.Content = new StringContent(jsonResponse); return response; }
/// <summary> /// Creates UEB model package /// <remarks> /// POST is used since the input data needs to come in as a zip file in the body of the request /// and can't be sent as query parameter /// </remarks> /// </summary> /// <returns></returns> public HttpResponseMessage PostUEBPackageCreate() { string uebPackageBuildRequestJson = string.Empty; HttpResponseMessage response = new HttpResponseMessage(); Stream uebPackageBuildRequestZipFile = null; ServiceContext db = new ServiceContext(); ServiceLog serviceLog = null; var t_stream = this.Request.Content.ReadAsStreamAsync().ContinueWith(s => { uebPackageBuildRequestZipFile = s.Result; }); t_stream.Wait(); // generate a guid to pass on to the client as a job ID Guid jobGuid = Guid.NewGuid(); // set the package request processing root dir path _packageRequestProcessRootDirPath = Path.Combine(UEB.UEBSettings.WORKING_DIR_PATH, jobGuid.ToString()); // set other directory paths necessary for processing the request to build ueb package _sourceFilePath = _packageRequestProcessRootDirPath; _targetTempPackageFilePath = Path.Combine(_packageRequestProcessRootDirPath, UEB.UEBSettings.PACKAGE_FILES_OUTPUT_SUB_DIR_PATH); _targetPackageDirPath = Path.Combine(_packageRequestProcessRootDirPath, UEB.UEBSettings.PACKAGE_OUTPUT_SUB_DIR_PATH); // set the path for saving the client request zip file _clientPackageRequestDirPath = Path.Combine(_packageRequestProcessRootDirPath, UEB.UEBSettings.PACKAGE_BUILD_REQUEST_SUB_DIR_PATH); string packageRequestZipFile = Path.Combine(_clientPackageRequestDirPath, UEB.UEBSettings.PACKAGE_BUILD_REQUEST_ZIP_FILE_NAME); try { var service = db.Services.First(s => s.APIName == "GenerateUEBPackageController.PostUEBPackageCreate"); serviceLog = new ServiceLog { JobID = jobGuid.ToString(), ServiceID = service.ServiceID, CallTime = DateTime.Now, RunStatus = RunStatus.InQueue }; db.ServiceLogs.Add(serviceLog); db.SaveChanges(); serviceLog = db.ServiceLogs.First(s => s.JobID == serviceLog.JobID); if (Directory.Exists(_packageRequestProcessRootDirPath)) { Directory.Delete(_packageRequestProcessRootDirPath); } Directory.CreateDirectory(_packageRequestProcessRootDirPath); if (Directory.Exists(_targetTempPackageFilePath)) { Directory.Delete(_targetTempPackageFilePath); } Directory.CreateDirectory(_targetTempPackageFilePath); if (Directory.Exists(_clientPackageRequestDirPath)) { Directory.Delete(_clientPackageRequestDirPath); } Directory.CreateDirectory(_clientPackageRequestDirPath); using (var fileStream = File.Create(packageRequestZipFile)) { uebPackageBuildRequestZipFile.CopyTo(fileStream); } // unzip the request zip file ZipFile.ExtractToDirectory(packageRequestZipFile, _clientPackageRequestDirPath); } catch (Exception ex) { logger.Error(ex.Message); response.StatusCode = HttpStatusCode.BadRequest; response.Content = new StringContent(ex.Message); serviceLog.RunStatus = RunStatus.Error; serviceLog.Error = ex.Message; db.SaveChanges(); return response; } // read the file with json extension to a string - uebPackageBuildRequestJson string[] jsonFiles = Directory.GetFiles(_clientPackageRequestDirPath, "*.json"); if (jsonFiles.Length != 1) { string errMsg = "Either no json file was found in the package request or there are multiple json files"; logger.Error(errMsg); response.StatusCode = HttpStatusCode.BadRequest; response.Content = new StringContent(errMsg); serviceLog.RunStatus = RunStatus.Error; serviceLog.Error = errMsg; db.SaveChanges(); return response; } using (var fileReader = new StreamReader(jsonFiles[0])) { uebPackageBuildRequestJson = fileReader.ReadToEnd(); } UEB.UEBPackageRequest pkgRequest; try { pkgRequest = JsonConvert.DeserializeObject<UEB.UEBPackageRequest>(uebPackageBuildRequestJson); } catch (Exception ex) { logger.Error(ex.Message); response.StatusCode = HttpStatusCode.BadRequest; response.Content = new StringContent(ex.Message); serviceLog.RunStatus = RunStatus.Error; serviceLog.Error = ex.Message; db.SaveChanges(); return response; } // check if the client request is valid string validationResult = ValidateUEBPackageRequest(pkgRequest); if (string.IsNullOrEmpty(validationResult) == false) { logger.Error(validationResult); response.StatusCode = HttpStatusCode.BadRequest; response.Content = new StringContent(validationResult); serviceLog.RunStatus = RunStatus.Error; serviceLog.Error = validationResult; db.SaveChanges(); return response; } // if the domain file is a shape file, extract the domain zip file to the root processing dir path string domainFile = Path.Combine(_clientPackageRequestDirPath, pkgRequest.DomainFileName); if (Path.GetExtension(domainFile) == ".zip") { // unzip the domain shape zip file ZipFile.ExtractToDirectory(domainFile, _packageRequestProcessRootDirPath); } // copy all the files with extensions (.dat, .nc) that came with the client uebpackagerequest zip file // to the package root processing folder string[] files = Directory.GetFiles(_clientPackageRequestDirPath); string fileName = string.Empty; string destFile = string.Empty; foreach (string file in files) { if (Path.GetExtension(file) == ".nc" || Path.GetExtension(file) == ".dat") { // Use static Path methods to extract only the file name from the path. fileName = Path.GetFileName(file); destFile = Path.Combine(_packageRequestProcessRootDirPath, fileName); // Copy the file and overwrite destination file if they already exist. File.Copy(file, destFile, true); } } PackageCreationStatus pkgStatus = new PackageCreationStatus(); pkgStatus.Message = "UEB package build request is now in a job queue."; pkgStatus.PackageID = jobGuid.ToString(); string jsonResponse = JsonConvert.SerializeObject(pkgStatus, Formatting.Indented); response.StatusCode = HttpStatusCode.OK; response.Content = new StringContent(jsonResponse); //PK:2/11/2014 (Added): start the package build process - this would start the package build process for this request // if no other requests are in queue. Othewise it will start the build process for the build request that // has been in queue for the longest time (first-in and first-out principle) PackageBuilder uebPkgBuilder = new PackageBuilder(); int numberOfJobsStarted = uebPkgBuilder.Run(); logger.Info("Number of queued jobs started:" + numberOfJobsStarted); return response; }