/// <summary> /// /// </summary> /// /// <param name="context"></param> /// <param name="ActionNode"></param> /// <param name="Actions"></param> /// /// <returns></returns> /// public override System.Xml.XmlElement ProcessApplication(EventRuleContext context, XmlElement ActionNode, ref string Actions) { Console.WriteLine("processing blanker..."); string name = GetParameter("name", ActionNode, context.SoapMessage, context.SoapNamespaceManager).Trim(); Console.WriteLine("found name: {0}.", name); XmlElement result = context.SoapMessage.CreateElement("results"); result.SetAttribute("name", name); return result; }
/// <summary> /// /// </summary> /// /// <param name="SoapNamespaceManager"></param> /// <param name="MessageTitle"></param> /// <param name="ActionNode"></param> /// <param name="Actions"></param> /// /// <returns></returns> /// public override XmlElement ProcessApplication(EventRuleContext context, XmlElement ActionNode, ref string Actions) { if (ActionNode.Name == "saveaction") { try { string Filename = GetParameter("file", ActionNode, context.SoapMessage, context.SoapNamespaceManager).Trim(); string Data = GetParameter("binary", ActionNode, context.SoapMessage, context.SoapNamespaceManager); if (Data == "") { Data = GetParameter("data", ActionNode, context.SoapMessage, context.SoapNamespaceManager); string NewFolder = Filename.Substring(0, Filename.LastIndexOf("\\")); System.IO.Directory.CreateDirectory(NewFolder); System.IO.FileStream fs = new System.IO.FileStream(Filename, System.IO.FileMode.Create); System.IO.StreamWriter sw = new System.IO.StreamWriter(fs); try { sw.Write(Data); Actions = "Saved data to " + Filename; } catch (Exception exx) { //ReportError(SoapMessage, exx); Console.WriteLine(exx); } finally { sw.Close(); } } else { byte[] Binary = System.Convert.FromBase64String(Data); System.IO.FileStream fs = new System.IO.FileStream(Filename, System.IO.FileMode.Create); try { fs.Write(Binary, 0, Binary.Length); Actions = "Saved data to " + Filename; } catch (Exception exx) { //ReportError(SoapMessage, exx); Console.WriteLine(exx); } finally { fs.Close(); } } } catch (_1800Communications.AggregationSystem._CoreLibrary.MessageQueueException exxx) { throw exxx; } catch (Exception exx) { //ReportError(SoapMessage, exx); Console.WriteLine(exx); } } return null; }
/// <summary> /// This routine takes a message, finds the appropriate actions, executes /// any necessary stylesheet, and executes each in turn. /// </summary> /// /// <param name="context"></param> /// /// <returns></returns> /// private bool ApplyRule(EventRuleContext context) { XmlNodeList actions = ruleNode.SelectNodes("action"); bool OKToSend = true; if (actions.Count == 0) { OKToSend = ExecuteAction(context, null, null); } else { foreach (XmlElement action in actions) { if (CheckTests(action, context.SoapMessage, context.SoapNamespaceManager)) { foreach (XmlElement actionDescription in action.SelectNodes("*")) { XmlElement actionCommand = null; switch (actionDescription.Name) { case "test": break; case "xsl:stylesheet": try { actionCommand = Transform(context.SoapMessage, actionDescription); } catch (System.Exception exception) { if (Logger.IsErrorEnabled) { LogError(exception, "failed to transform: {0}.", exception.Message); } actionCommand = null; } break; default: actionCommand = actionDescription; break; } if (actionCommand != null) { // look for nested action node. if (actionCommand.Name == "action") { foreach (XmlElement tempAction in actionCommand.SelectNodes("*")) { if (CheckTests(tempAction, context.SoapMessage, context.SoapNamespaceManager)) { // process nested action OKToSend = OKToSend && ExecuteAction(context, tempAction, action); } } } else if (CheckTests(actionCommand, context.SoapMessage, context.SoapNamespaceManager)) { // process action OKToSend = OKToSend && ExecuteAction(context, actionCommand, action); } } } } } } return OKToSend; }
/// <summary> /// /// </summary> /// /// <returns></returns> /// private EventRuleContext GetContext() { EventRuleContext context = new EventRuleContext(null); // Set up a name table so we can query based on namespaces NameTable SoapNameTable = new NameTable(); XmlNamespaceManager SoapNamespaceManager = new XmlNamespaceManager(SoapNameTable); SoapNamespaceManager.AddNamespace(String.Empty, "urn:none"); SoapNamespaceManager.AddNamespace("soap", SoapURN); // This allows custom namespaces as defined in the config xml foreach (XmlElement NamespaceNode in ruleNode.SelectNodes("namespaces/namespace")) { string NamespaceName = ""; string NamespaceURN = "urn:none"; if (NamespaceNode.GetAttributeNode("name") != null) { NamespaceName = NamespaceNode.GetAttribute("name"); } if (NamespaceNode.InnerText != "") { NamespaceURN = NamespaceNode.InnerText; } SoapNamespaceManager.AddNamespace(NamespaceName, NamespaceURN); } context.SoapNameTable = SoapNameTable; context.SoapNamespaceManager = SoapNamespaceManager; return context; }
protected virtual void SendApplication(XmlElement xeDestinationNode, EventRuleContext context) { // if we're looking at a "destinations" node, we should find info on delivery if (CheckTests(xeDestinationNode, context.SoapMessage, context.SoapNamespaceManager)) { // timeout stuff here TimeSpan tsTimeout = TimeSpan.Zero; XmlElement xeTimeout = (XmlElement)xeDestinationNode.SelectSingleNode("timeout"); if (xeTimeout != null) { tsTimeout = new TimeSpan( int.Parse("0" + GetParameter("days", xeTimeout, context.SoapMessage, context.SoapNamespaceManager)), int.Parse("0" + GetParameter("hours", xeTimeout, context.SoapMessage, context.SoapNamespaceManager)), int.Parse("0" + GetParameter("minutes", xeTimeout, context.SoapMessage, context.SoapNamespaceManager)), int.Parse("0" + GetParameter("seconds", xeTimeout, context.SoapMessage, context.SoapNamespaceManager)), int.Parse("0" + GetParameter("milliseconds", xeTimeout, context.SoapMessage, context.SoapNamespaceManager)) ); XmlElement SoapRouting = context.SoapMessage.CreateElement("soap", "Routing", SoapURN); XmlElement SoapLabel = context.SoapMessage.CreateElement("soap", "Label", SoapURN); SoapLabel.AppendChild(context.SoapMessage.CreateTextNode(context.Label)); SoapRouting.AppendChild(SoapLabel); context.SoapMessage.SelectSingleNode("soap:Envelope", context.SoapNamespaceManager).AppendChild(SoapRouting); foreach (XmlElement DestinationQueue in xeTimeout.SelectNodes("queue")) { if (CheckTests(DestinationQueue, context.SoapMessage, context.SoapNamespaceManager)) { string QueuePath = GetParameter("", DestinationQueue, context.SoapMessage.SelectSingleNode("*"), context.SoapNamespaceManager); //QueuePath = ResolveQueuePath(QueuePath, DestinationQueue, sIncomingQueueName); //if (QueuePath != "") //{ XmlElement DestinationNode = context.SoapMessage.CreateElement("soap", "Destination", SoapURN); DestinationNode.AppendChild(context.SoapMessage.CreateTextNode("QueuePath")); // me SoapRouting.AppendChild(DestinationNode); //} } } } foreach (XmlElement DestinationQueue in xeDestinationNode.SelectNodes("queue")) { // loop over all queues in the destination. All test conditions on the destinations element // have already been performed so get the queue path. string sQueuePath = GetParameter("", DestinationQueue, context.SoapMessage.SelectSingleNode("*"), context.SoapNamespaceManager).Trim(); if (Logger.IsInfoEnabled) { LogInfo("destination: {0}.", sQueuePath); } // If we actually have a path... if (sQueuePath != "") { //sQueuePath = ResolveQueuePath(sQueuePath, DestinationQueue, sIncomingQueueName); // Locate the queue we've settled on //MessageQueue CorrectQueue = null; //try //{ // CorrectQueue = FindQueue(sQueuePath); // // This would only be null if there's a catastrophic queue creation or naming error // if (CorrectQueue != null) // { // lock (CorrectQueue) // { try { // The Last Queue is useful for running errors back through context.SoapMessage.DocumentElement.RemoveAttribute("lastqueue"); if (!silent) { context.SoapMessage.DocumentElement.SetAttribute("lastqueue", sQueuePath); } // Create and send the message //Message AppMessage = new Message(); //try //{ // //set timeout here // if (tsTimeout != TimeSpan.Zero) // { // AppMessage.TimeToBeReceived = tsTimeout; // AppMessage.UseDeadLetterQueue = true; // } // AppMessage.Body = context.SoapMessage.DocumentElement; // AppMessage.Label = context.Label; // AppMessage.Recoverable = true; // CorrectQueue.Send(AppMessage); if (Logger.IsInfoEnabled) { LogInfo("sending message: {0}.", context.SoapMessage.DocumentElement.OuterXml); } } finally { //AppMessage.Dispose(); } } } } }
/// <remarks> /// Once the processing of a message is complete, it needs to be sent to the next /// component via another message queue. SendApplication() does just that. The /// message is sent out to each queue as specified by the configuration At this /// point a brief description of the queue naming system is merited: /// /// All queues are by default expected to by Private queues on the local machine. /// This is set via the _BaseQueue class level variable, which should be done in /// the inherited class configuration method. The default _BaseQueue is: /// ".\\PRIVATE$\\Aggregator." /// /// Message queue names consist of a path delineated by "." characters. Thus, /// ".\\PRIVATE$\\Aggregator.Incoming.Complete.AutoLoan" /// is a typical queue name. By default, when outputing to a queue, the name of the /// queue is determined by apending a new name onto the incoming queue. Thus, if a /// step of the process outputs to "Processed" and the incoming queue was the one /// specified above, then the message would be output to: /// ".\\PRIVATE$\\Aggregator.Incoming.Complete.AutoLoan.Processed" /// This allows "queue affinity". Suppose we have some step which is very generic, and /// executed on several different queues. This step defines it's output queue as "C" /// and listens to queues "A" and "B". With an absolute path, the results would be put /// out to queue "C". However, with relative paths, the results go out to either "A.C" /// or "B.C", thus it's tied to the incoming queue. /// /// The same logic applies as the number of incoming and outgoing queues increases. If /// this same process listens to queues "A", "B", and "C" and outputs to queues "D" and /// "E", then the results would be output to ("A.D" and "A.E") or ("B.D" and "B.E") or /// ("C.D" and "C.E"). /// /// This behavior can be overridden by specifying that the output queue is an absolute /// path. /// /// This routine may be overridden as necessary, though it is not recommended. /// </remarks> protected virtual void SendApplication(EventRuleContext context) { // Gotta look at all nodes so we catch any XSL // Note, this is uber-gay and needs to be done differently. Maybe XSL in the // destinations, but that breaks some aspects of the overall schema foreach (XmlElement ChildElement in ruleNode.SelectNodes("*")) { XmlElement xeDestination = ChildElement; // If this is XSL, transform it and use that as our context if (xeDestination.Name == "xsl:stylesheet") { xeDestination = Transform(context.SoapMessage, ChildElement); } if (xeDestination.Name == "destinations") { SendApplication(xeDestination, context); } } }
/// <summary> /// Stamps the application with Header information and associates that with the data /// being added to the application. /// </summary> /// /// <param name="SoapMessage">The Application</param> /// <param name="SoapNamespaceManager">Namespace Manager for the Application</param> /// <param name="ActionID">ID for this action</param> /// <param name="bBlankDatasetID">A flag that says whether to allow a blank dataset ID</param> /// <param name="UpdateMessage">Components Message about what was done</param> /// <param name="IncomingQueuePath">Queue this message was read from</param> /// <param name="NewChunk">The chunk to add to the application</param> /// <param name="WriteHeader">Should the header be written</param> /// <param name="WriteData">Should the data be written</param> /// /// <returns></returns> /// public XmlElement StampApplication(EventRuleContext context, string ActionID, bool bBlankDatasetID, string UpdateMessage, string IncomingQueuePath, XmlNode NewChunk, bool WriteHeader, bool WriteData) { // Don't bother if the app doesn't exist if (context.SoapMessage != null) { if (ActionID == null) { ActionID = ""; } if (ActionID == "" && !bBlankDatasetID) { ActionID = "[Unspecified]"; } // Set an index so this ActionID can be uniquely identified int Index = context.SoapMessage.SelectNodes("/soap:Envelope/soap:Body/dataset[@id='" + ActionID + "']", context.SoapNamespaceManager).Count + 1; // Try to write the header data int ActorID = -1; if (WriteHeader) { ActorID = MarkUsersApplication(context.SoapMessage, context.SoapNamespaceManager, UpdateMessage, IncomingQueuePath); } // Try to write the NewChunk if (WriteData) { XmlElement NewDataSet = context.SoapMessage.CreateElement("dataset"); NewDataSet.SetAttribute("id", ActionID); NewDataSet.SetAttribute("index", Index.ToString()); NewDataSet.SetAttribute("tool", ruleName); // If there was no actor, don't write the attribute if (ActorID > 0) { NewDataSet.SetAttribute("actor", ActorID.ToString()); } // If there was actually a new chunk, slap it in there if (NewChunk != null) { try { XmlNode xnNamespacesStripped = NewDataSet.OwnerDocument.ReadNode(new XmlTextReader(RemoveNamespaces(NewChunk), XmlNodeType.Element, null)); NewDataSet.AppendChild(xnNamespacesStripped); } catch (Exception exx) { //ReportErrorNow(SoapMessage, exx); NewDataSet.AppendChild(NewDataSet.OwnerDocument.ImportNode(NewChunk, true)); } } // Add to the Soap Message XmlNode Target = context.SoapMessage.SelectSingleNode("/soap:Envelope/soap:Body", context.SoapNamespaceManager); if (Target == null) { Target = context.SoapMessage.DocumentElement; } Target.AppendChild(NewDataSet); return NewDataSet; } else { return null; } } else { return null; } }
/// <summary> /// ProcessApplication() is the heart of the processing of individual messages. It takes /// the original message along with the appropriate action node from the config file. It /// uses these to create a third XML document which specifies how to handle the message. /// Finally, it creates an optional XML fragment. This fragment is then integrated into /// the SOAP message so that the results are available during later processes /// /// This routine is expected to be overridden. /// </summary> /// public abstract XmlElement ProcessApplication(EventRuleContext context, XmlElement ActionNode, ref string Actions);
/// <summary> /// /// </summary> /// /// <param name="context"></param> /// <param name="Action"></param> /// <param name="ActionParent"></param> /// /// <returns></returns> /// public virtual bool ExecuteAction(EventRuleContext context, XmlElement InnerAction, XmlElement ActionParent) { XmlElement NewChunk = null; string UpdateMessage = ""; Exception Error = null; int retryCount = 1; // Find out how many times to try this action in case of exception (default is 1) if (ActionParent != null && ActionParent.GetAttributeNode("retrycount") != null) { try { retryCount = int.Parse(ActionParent.GetAttribute("retrycount")); } catch { } } // Try to process the application for (int x = 0; x < retryCount; x++) { try { Error = null; NewChunk = ProcessApplication(context, InnerAction, ref UpdateMessage); break; } catch (Exception exception) { Error = exception; if (Logger.IsErrorEnabled) { LogError(exception, "failed to process application: {0}.", exception.Message); } } } if (Error != null) { // If there were errors all [RetryCount] times, send an error message //Error.Send(_ErrorQueueName); //MonitorSend(MessageType.Error, "", _ErrorQueueName, null); return (ActionParent.GetAttribute("failure") == "continue"); } else { // If it succeeded at all... string IncomingQueuePath = ""; //if (IncomingQueue != null) //{ // IncomingQueuePath = IncomingQueue.Path; //} // if there was data back, stamp it in the app if (NewChunk != null) { // Console.WriteLine("CHUNK: " + NewChunk.OuterXml); string actionId = null; bool blankDatasetId = false; if (ActionParent != null) { actionId = ActionParent.GetAttribute("id"); if (ActionParent.HasAttribute("allowblankdatasetid")) { try { blankDatasetId = Convert.ToBoolean(ActionParent.GetAttribute("allowblankdatasetid")); } catch { //ignore, default to false } } } StampApplication(context, actionId, blankDatasetId, UpdateMessage, IncomingQueuePath, NewChunk, true, (ActionParent.GetAttribute("results").ToLower() != "ignore")); } return true; } }