private void RemoveErrorFilesOfSameObjectOnSucceeded(CognosInstructions instructions, string basepath_data, string sessionid) { int probed = 0; string curcand = String.Empty; /* [pstraka>dlatikay 20110622] iterates through all ".error" files which belong to ".cognos" files which are about the same object, * and rename them to ".resolved", since they are no longer hindering, and an MCP/ennag/Nagios watchdog should stop complaining */ try { var cands = Directory.GetFiles(basepath_data, String.Format("*.error")); foreach (string cand in cands) { curcand = cand; /* don't reckon our own job */ if (!cand.StartsWith(sessionid)) { /* now, is there an instruction file with the same guid? */ var previous_instruction_file = Path.Combine(basepath_data, String.Format("{0}.cognos", Path.GetFileNameWithoutExtension(cand))); if (File.Exists(previous_instruction_file)) { /* open and parse it to compare if it is about the same object */ var prev_instruction = Tools.ParseInstructionsFromXMLFile <CognosInstructions>(previous_instruction_file); if (prev_instruction.sOK == instructions.sOK) /* [dlatikay 20110622] ATTN when we ever create reports for anything that is outside rep02List, we shall need to find a way to compare the OT as well on this occasion */ { /* yep. rename it */ var resolved_path = Path.Combine(basepath_data, Path.ChangeExtension(cand, "resolved")); File.Move(cand, resolved_path); File.AppendAllText(resolved_path, String.Format("Resolved by {0} on {1}, because job {2} succeeded creating the same object's report rendition", Environment.UserName, DateTime.Now, sessionid)); } } ++probed; } } /* done - log into current job */ Log(LogfilePathOut, String.Format("Finished watching for resolved previous errors after probing {0} candidate file(s) with the '.error' extension.", probed)); } catch (Exception ex) { /* failed - also log into current job */ Log(LogfilePathOut, String.Format("Failed watching for resolved previous errors after probing {0} candidate file(s) with the '.error' extension, trying {1}: {2}", probed, curcand, ex.ToString())); } }
/// <summary> /// Lets COGNOS render a safety incident report, extract it from there as a pdf, and stream it back /// </summary> public bool RenderRep0006(CognosInstructions instructions, string basepath_exe, string basepath_data, MemoryStream pdf_chunk, out Exception Error) { Error = null; try { /* compose the command */ string sessionid = Guid.NewGuid().ToString(); string instructionfile = Path.Combine(basepath_data, String.Format(@"{0}.cognos", sessionid)); string logfilename_out = Path.Combine(basepath_data, String.Format(@"{0}.log", sessionid)); string logfilename_err = Path.Combine(basepath_data, String.Format(@"{0}.error", sessionid)); string outputfile = Path.Combine(basepath_data, String.Format(@"{0}.pdf", sessionid)); /* the tool is supposed to make the same assumption: DL904893844888820V00 */ /* publish the paths */ LogfilePathOut = logfilename_out; LogfilePathErr = logfilename_err; /* validate the target stream */ if (pdf_chunk == null) { throw new ArgumentNullException("pdf_chunk", "The target stream must be passed to RenderRep0006"); } else if (!pdf_chunk.CanWrite) { throw new ArgumentOutOfRangeException("pdf_chunk.CanWrite", "The target stream passed to RenderRep0006 must be writable"); } /* 1. make an instruction file for the session */ string xml = null; using (var ms = new MemoryStream()) { var xs = new XmlSerializer(typeof(CognosInstructions)); using (var tw = new XmlTextWriter(ms, Encoding.UTF8)) { xs.Serialize(tw, (object)instructions); byte[] bytes = ((MemoryStream)tw.BaseStream).ToArray(); xml = new UTF8Encoding().GetString(bytes); File.WriteAllText(instructionfile, xml); } } /* 2. execute the COGNOS report generator (external assembly), waiting for it to complete */ /* [dlatikay,pstraka 20110222] for some reason unclear to me, if the report engine is syseu-sara, the exe is still * started as NETWORK SERVICE. this account needs permission to execute, otherwise it will fail */ string exepath = Path.Combine(basepath_exe, @"sherm-tpi-cognos.exe"); //start.RedirectStandardError = true; //start.RedirectStandardOutput = true; //start.UseShellExecute = true; //start.WorkingDirectory = basepath_exe; //start.CreateNoWindow = true; using (Process proc = new Process()) { Log(LogfilePathOut, String.Format(@"Attempting to launch '{0}' as '{1}'.", exepath, Environment.UserName)); /* [dlatikay 20110507] commented-out sections below in favour of this simplified code: */ proc.StartInfo.FileName = exepath; proc.StartInfo.Arguments = instructionfile; proc.StartInfo.WindowStyle = ProcessWindowStyle.Normal; proc.Start(); Log(LogfilePathOut, String.Format(@"Launched '{0}' as '{1}'.", exepath, Environment.UserName)); /* [dlatikay 20110507] this will need timeout handling * [dlatikay 20111117] defined a timeout of three minutes */ proc.WaitForExit(1000 * 60 * 3); /* three minutes */ /* DIAGNOSIS */ //start.WorkingDirectory = basepath_exe; //start.UserName = "******"; //start.Domain = "SAPPIEU"; //var pwd=new System.Security.SecureString(); //pwd.AppendChar('q'); //pwd.AppendChar('R'); //pwd.AppendChar('j'); //pwd.AppendChar('l'); //pwd.AppendChar('9'); //pwd.AppendChar('5'); //start.Password = pwd; /* /DIAGNOSIS */ // proc.StartInfo = start; // /* attach the console/error streams */ // proc.OutputDataReceived += new DataReceivedEventHandler(proc_OutputDataReceived); // proc.ErrorDataReceived += new DataReceivedEventHandler(proc_ErrorDataReceived); // Log(LogfilePathOut, String.Format(@"About to start '{0}' as '{1}'.", start.FileName, Environment.UserName)); // proc.Start(); // //proc.BeginOutputReadLine(); // //proc.BeginErrorReadLine(); // while (!proc.HasExited) // { // /* every 1000 ms, wait until it is done // * [dlatikay 20101007] as soon as this works, it will need timeout handling */ // Log(LogfilePathOut, String.Format(@"Waiting '{0}' to finish...'.", start.FileName, Environment.UserName)); // proc.WaitForExit(1000); // Log(LogfilePathOut, String.Format(@"Waited another second for '{0}' to finish.'.", start.FileName, Environment.UserName)); // } } /* stream back the file */ if (File.Exists(outputfile)) { Log(LogfilePathOut, String.Format(@"Got file '{0}' after process terminated.", outputfile)); using (FileStream fs = File.OpenRead(outputfile)) { sherm.core.Extensions.StreamExtensions.CopyTo(fs, pdf_chunk); /* rewind so that next process may read */ pdf_chunk.Seek(0, SeekOrigin.Begin); } } else { Log(LogfilePathOut, String.Format(@"Couldn't find file '{0}' after process terminated.", outputfile)); throw new FileNotFoundException("The anticipated output file could not be found after the report generator executable finished", outputfile); } /* don't delete the temp files, GC will do that independently: here, we only search for .error files from the same job */ RemoveErrorFilesOfSameObjectOnSucceeded(instructions, basepath_data, sessionid); /* successfully completed */ return(true); } catch (Exception ex) { Log(LogfilePathErr, String.Format("Caught exception in RenderRep0006: {0}", ex.ToString())); Error = ex; return(false); } }