/// <summary> Post a SIF_LogEntry to the server. /// /// Use this form of the <c>log</c> method to post a simple /// error, warning, or informative message to the server that references a /// SIF Message and optionally a set of SIF Data Objects previously received /// by the agent. /// /// </summary> /// <param name="level">The LogLevel to assign to this log entry /// </param> /// <param name="message">A textual description of the error /// </param> /// <param name="info">The <i>SifMessageInfo</i> instance from the Adk message /// handler implementation identifying a SIF Message received by the agent /// </param> /// <param name="objects">One or more SifDataObject instances received in the message /// identified by the <i>info</i> parameter /// </param> public virtual void Log(LogLevel level, string message, SifMessageInfo info, SifDataObject [] objects) { Log(level, message, null, null, -1, -1, info, objects); }
public void OnQueryResults(IDataObjectInputStream data, SIF_Error error, IZone zone, IMessageInfo info) { SifMessageInfo smi = (SifMessageInfo)info; if (error != null) { Adk.Log.Warn("Received Error Response: " + error.SIF_Desc); } else { string debug = string.Format ("Received Response for {0} from zone: {1}. Packet {2} of {3}", data.ObjectType, zone.ZoneId, smi.PacketNumber, smi.MorePackets ? smi.PacketNumber + "+" : smi.PacketNumber + " (FINAL)"); zone.Log.Info(debug); zone.ServerLog.Log (LogLevel.INFO, debug, null, "1003", LogEntryCodes.CATEGORY_SUCCESS, LogEntryCodes.CODE_SUCCESS, smi, null); bool logToconsole = fAgent.getChameleonProperty(zone, "logConsole", false); if (fAgent.getChameleonProperty(zone, "logResponses", true)) { Log (fDir + Path.DirectorySeparatorChar + zone.ZoneId + Path.DirectorySeparatorChar + "Responses\\" + data.ObjectType.Name + "\\" + data.ObjectType.Name + DateTime.Now.ToFileTime().ToString() + ".xml", data, smi, logToconsole); } } }
/// <summary> Post a SIF_LogEntry to the server. /// /// Use this form of the <c>log</c> method to post an /// error, warning, or informative message to the server that references a /// SIF Message and optionally a set of SIF Data Objects previously received /// by the agent. The log entry can also have an extended error description /// and application-defined error code. /// /// </summary> /// <param name="level">The LogLevel to assign to this log entry /// </param> /// <param name="desc">A textual description of the error /// </param> /// <param name="extDesc">Extended error description, or <c>null</c> if no /// value is to be assigned to the SIF_LogEntry/SIF_ExtDesc element /// </param> /// <param name="appCode">Error code specific to the application posting the log /// entry, or <c>null</c> if no value is to be assigned to the /// SIF_LogEntry/SIF_ApplicationCode element /// </param> /// <param name="info">The <i>SifMessageInfo</i> instance from the Adk message /// handler implementation identifying a SIF Message received by the agent /// </param> /// <param name="objects">One or more SifDataObject instances received in the message /// identified by the <i>info</i> parameter /// </param> public virtual void Log(LogLevel level, string desc, string extDesc, string appCode, SifMessageInfo info, SifDataObject [] objects) { Log(level, desc, extDesc, appCode, -1, -1, info, objects); }
private void Log(string fileName, IDataObjectInputStream input, SifMessageInfo info, bool logToConsole) { try { // Ensure that the directory is there FileInfo file = new FileInfo(fileName); file.Directory.Create(); int numObjects = 0; using (Stream outStream = File.OpenWrite(fileName)) { using (TextWriter twriter = new StreamWriter(outStream, Encoding.UTF8)) { twriter.WriteLine("<SIF_ObjectData>"); twriter.Flush(); SifWriter writer = new SifWriter(twriter); SifWriter consoleWriter = null; if (logToConsole) { consoleWriter = new SifWriter(Console.Out); } SifDataObject o; while ((o = input.ReadDataObject()) != null) { numObjects++; Track(o); writer.Write(o); if (logToConsole) { consoleWriter.Write(o); Console.WriteLine(); } } writer.Flush(); if (logToConsole) { consoleWriter.Flush(); } twriter.WriteLine("</SIF_ObjectData>"); } outStream.Close(); Console.WriteLine ("Received {0} objects for {1}, Packet# {2}", numObjects, input.ObjectType.Name, info.PacketNumber); } } catch (Exception ex) { Adk.Log.Error(ex.Message, ex); } }
public void OnQueryResults(IDataObjectInputStream data, SIF_Error error, IZone zone, IMessageInfo info) { SifMessageInfo smi = (SifMessageInfo)info; fResultsRequestInfo = smi.SIFRequestInfo; doBehavior(zone); Assert.IsNotNull(fResultsRequestInfo, "RequestInfo should not be null in onQueryResults()"); if (RequestStateObject != null) { Assert.AreEqual(RequestStateObject, fResultsRequestInfo.UserData, "Custom State in onQueryResults()"); } }
public void OnQueryPending(IMessageInfo info, IZone zone) { SifMessageInfo smi = (SifMessageInfo)info; fPendingRequestInfo = smi.SIFRequestInfo; // TODO: should we test error handling in the onQueryPending handler? //doBehavior( zone ); Assert.IsNotNull(fPendingRequestInfo, "RequestInfo should not be null in onQueryPending()"); if (RequestStateObject != null) { Assert.AreEqual(RequestStateObject, fPendingRequestInfo.UserData, "Custom State in onQueryPending()"); } }
public void OnQueryResults(IDataObjectInputStream data, SIF_Error error, IZone zone, IMessageInfo info) { SifMessageInfo smi = (SifMessageInfo)info; if (!(fRequestState.Equals(smi.SIFRequestInfo.UserData))) { // This is a SIF_ZoneStatus response from a previous invocation of the agent return; } if (data.Available) { SIF_ZoneStatus zoneStatus = data.ReadDataObject() as SIF_ZoneStatus; AsyncUtils.QueueTaskToThreadPool(new zsDelegate(_processSIF_ZoneStatus), zoneStatus, zone); } }
public void OnMessageProcessed(SifMessageType messageType, IMessageInfo info) { string fileName = null; SifMessageInfo smi = (SifMessageInfo)info; if (messageType == SifMessageType.SIF_Response) { // Log Query responses in the standard OpenADK Message tracing format //N-ObjectType-ZoneID-SourceID-PacketNum|”error”.txt fileName = string.Format ("{0:00000}-{1}-{2}-{3}-{4}.txt", fResponseOrdinal++, smi.SIFRequestObjectType.Name, smi.Zone.ZoneId, smi.SourceId, smi.PacketNumber); } else if (messageType == SifMessageType.SIF_Event) { fileName = string.Format ("{0:00000}-{1}-{2}-{3}-SIF_Event.txt", fResponseOrdinal++, "ChangeThis", smi.Zone.ZoneId, smi.SourceId); } if (fileName != null) { try { FileInfo file = new FileInfo(fDir + "\\Raw\\" + fileName); file.Directory.Create(); using ( StreamWriter writer = new StreamWriter(file.FullName, true, Encoding.UTF8) ) { writer.Write(smi.Message); writer.Close(); } } catch (Exception ex) { Adk.Log.Warn(ex.Message, ex); } } }
public void OnEvent(Event evnt, IZone zone, IMessageInfo info) { bool logToconsole = fAgent.getChameleonProperty(zone, "logConsole", false); SifMessageInfo smi = (SifMessageInfo)info; string debug = string.Format ("Received {0} Event from {1} in Zone: {2}", evnt.ActionString, smi.SourceId, zone.ZoneId); zone.ServerLog.Log (LogLevel.INFO, debug, null, "1003", LogEntryCodes.CATEGORY_SUCCESS, LogEntryCodes.CODE_SUCCESS, smi, null); Adk.Log.Info(debug); Log (fDir + Path.DirectorySeparatorChar + zone.ZoneId + Path.DirectorySeparatorChar + "Events\\" + evnt.ObjectType.Name + "\\" + evnt.ObjectType.Name + DateTime.Now.ToFileTime().ToString() + ".xml", evnt.Data, smi, logToconsole); }
/// <summary> /// Attempts to parse attributes out of the source message enough to make a valid /// SIF_Ack with a SIF_Error. This is useful in conditions where the source message cannot /// be parsed by the ADK /// </summary> /// <param name="sourceMessage"> The original message as a string</param> /// <param name="error">The error to place in the SIF_Ack/SIF_Error</param> /// <param name="zone">The zone associated with this message</param> /// <returns></returns> /// <exception cref="AdkMessagingException"></exception> public static SIF_Ack ackError(String sourceMessage, SifException error, ZoneImpl zone) { SifMessageInfo parsed = null; try { StringReader reader = new StringReader(sourceMessage); parsed = SifMessageInfo.Parse(reader, false, zone); reader.Close(); } catch (Exception e) { zone.Log.Error(e, e); } SIF_Ack errorAck = new SIF_Ack(zone.HighestEffectiveZISVersion); if (parsed != null) { // Set SIFVersion, OriginalSourceId, and OriginalMsgId; if (parsed.SifVersion != null) { errorAck.SifVersion = parsed.SifVersion; } errorAck.SIF_OriginalMsgId = parsed.GetAttribute("SIF_MsgId"); errorAck.SIF_OriginalSourceId = parsed.GetAttribute("SIF_SourceId"); } SetRequiredAckValues(errorAck); SIF_Error newErr = new SIF_Error(); newErr.SIF_Category = (int)error.ErrorCategory; newErr.SIF_Code = error.ErrorCode; newErr.SIF_Desc = error.ErrorDesc; newErr.SIF_ExtendedDesc = error.ErrorExtDesc; errorAck.SIF_Error = newErr; return(errorAck); }
/// <summary> /// Sends the message to the SIF Zone and returns the SIFAck that was received /// </summary> /// <param name="msg"></param> /// <param name="isPullMessage"></param> /// <returns></returns> public virtual SIF_Ack send(SifMessagePayload msg, bool isPullMessage) { if (fZone.ProtocolHandler == null) { throw new AdkTransportException("Zone is not connected", fZone); } try { PolicyManager policyMan = PolicyManager.GetInstance(fZone); if (policyMan != null) { policyMan.ApplyOutboundPolicy(msg, fZone); } } catch (AdkException adkex) { throw new AdkMessagingException("Unable to apply outbound message policy: " + adkex, fZone, adkex); } SIF_Ack ack = null; SifWriter w = null; byte stage = 1; bool queued = false; SifMessageType pload = 0; bool cancelled = false; ICollection<IMessagingListener> msgList = null; try { // Assign values to message header SIF_Header hdr = msg.Header; hdr.SIF_Timestamp = DateTime.Now; hdr.SIF_MsgId = SifFormatter.GuidToSifRefID(Guid.NewGuid()); hdr.SIF_SourceId = fSourceId; hdr.SIF_Security = secureChannel(); // Adk 1.5+: SIF_LogEntry requires that we *duplicate* the // header within the object payload. This is really the only // place we can do that and ensure that the SIF_Header and // the SIF_LogEntry/SIF_LogEntryHeader are identical. if (msg is SIF_Event) { // TODO: Should this be done at a higher level, such as zone.ReportEvent()? SIF_Event ev = ((SIF_Event)msg); SIF_ObjectData od = (SIF_ObjectData)ev.GetChild(InfraDTD.SIF_EVENT_SIF_OBJECTDATA); SIF_EventObject eo = od == null ? null : od.SIF_EventObject; if (eo != null) { SIF_LogEntry logentry = (SIF_LogEntry)eo.GetChild(InfraDTD.SIF_LOGENTRY); if (logentry != null) { SIF_LogEntryHeader sleh = new SIF_LogEntryHeader(); sleh.SIF_Header = (SIF_Header)hdr.Clone(); logentry.SIF_LogEntryHeader = sleh; } } } if (!isPullMessage || (Adk.Debug & AdkDebugFlags.Messaging_Pull) != 0) { msg.LogSend(fZone.Log); } } catch (Exception thr) { throw new AdkMessagingException ("MessageDispatcher could not assign outgoing message header: " + thr, fZone, thr); } try { // Convert message to a stream using (MessageStreamImpl memBuf = new MessageStreamImpl()) { w = new SifWriter(memBuf.GetInputStream()); w.Write(msg); w.Flush(); stage = 2; // SIF_Event and SIF_Response are posted to the agent local queue // if enabled, otherwise sent immediately. All other message types // are sent immediately even when the queue is enabled. // if (fQueue != null && (msg is SIF_Event || msg is SIF_Response)) { fQueue.PostMessage(msg); queued = true; } // Notify MessagingListeners... pload = (SifMessageType)Adk.Dtd.GetElementType(msg.ElementDef.Name); if (pload != SifMessageType.SIF_Ack) { msgList = GetMessagingListeners(fZone); if (msgList.Count > 0) { StringBuilder stringBuffer = new StringBuilder(memBuf.Decode()); SifMessageInfo msgInfo = new SifMessageInfo(msg, fZone); foreach (IMessagingListener listener in msgList) { try { if (!listener.OnSendingMessage(pload, msgInfo, stringBuffer) ) { cancelled = true; } } catch { } // Do Nothing } } } if (!cancelled) { // Send the message IMessageInputStream ackStream = fZone.fProtocolHandler.Send(memBuf); { try { // Parse the results into a SIF_Ack ack = (SIF_Ack) fParser.Parse ( ackStream.GetInputStream(), fZone, isPullMessage ? SifParserFlags.ExpectInnerEnvelope : SifParserFlags.None ); } catch (Exception parseEx) { if (isPullMessage && (parseEx is AdkParsingException || parseEx is SifException || parseEx is System.Xml.XmlException)) { String ackStr = ackStream.ToString(); if ((Adk.Debug & AdkDebugFlags.Message_Content ) != 0) { fZone.Log.Info( ackStr ); } // The SIFParse was unable to parse this message. Try to create an appropriate // SIF_Ack, if SIFMessageInfo is able to parse enough of the message throw new PullMessageParseException(parseEx, ackStr, fZone); } throw new AdkMessagingException(parseEx.Message, fZone); } } if (ack != null) { ack.message = msg; if (!isPullMessage || (Adk.Debug & AdkDebugFlags.Messaging_Pull) != 0) { ack.LogRecv(fZone.Log); } } // Notify MessagingListeners... if (msgList != null && msgList.Count > 0) { SifMessageInfo msgInfo = new SifMessageInfo(msg, fZone); foreach (IMessagingListener listener in msgList) { try { listener.OnMessageSent(pload, msgInfo, ack); } catch { } // Do Nothing } } } else { // Prepare a success SIF_Ack to return ack = msg.AckImmediate(); } } } catch (AdkMessagingException) { throw; } catch (AdkTransportException) { throw; } catch (Exception thr) { if (stage == 1) { throw new AdkMessagingException ( "MessageDispatcher could not convert outgoing infrastructure message to a string: " + thr, fZone); } if (stage == 2) { throw new AdkMessagingException ( "MessageDispatcher could not convert SIF_Ack response to an object: " + thr, fZone); } } finally { // Removed queued message from queue if (queued) { try { fQueue.RemoveMessage(msg.MsgId); } catch { // Do nothing } } } return ack; }
/// <summary> /// Selects an appropriate MappingsContext object to use for an inbound <c>Map</c> /// operation. Call this method on the root Mappings object to obtain a /// MappingsContext instance, then call its <c>Map</c> method to perform an inbound /// mapping operation. /// </summary> /// <param name="elementDef">The ElementDef of the Element being mapped to</param> /// <param name="message">The Message being mapped from</param> /// <returns>a MappingsContext that can be used for evaluating mappings</returns> /// <exception cref="AdkMappingException"/> public MappingsContext SelectInbound(IElementDef elementDef, SifMessageInfo message) { return SelectContext(MappingDirection.Inbound, elementDef, message.SifVersion, message.Zone.ZoneId, message.SourceId); }
/// <summary> /// Selects an appropriate MappingsContext object to use for an outbound <c>Map</c> /// operation. Call this method on the root Mappings object to obtain a /// MappingsContext instance, then call its <c>map</c> method to perform an outbound /// mapping operation. /// </summary> /// <param name="elementDef">The ElementDef of the Element being mapped to</param> /// <param name="message">The Message being mapped from</param> /// <returns>a MappingsContext that can be used for evaluating mappings</returns> /// <exception cref="AdkMappingException"/> public MappingsContext SelectOutbound(IElementDef elementDef, SifMessageInfo message) { return SelectContext(MappingDirection.Outbound, elementDef, message.LatestSIFRequestVersion, message.Zone.ZoneId, message.SourceId); }
/// <summary> Respond to SIF RequestsGetTopicMap /// </summary> public virtual void OnRequest(IDataObjectOutputStream outStream, Query query, IZone zone, IMessageInfo inf) { SifMessageInfo info = (SifMessageInfo)inf; SifWriter debug = new SifWriter(Console.Out); Console.WriteLine ("Received a request for " + query.ObjectTag + " from agent \"" + info.SourceId + "\" in zone " + zone.ZoneId); // Read all students from the database to populate a HashMap of // field/value pairs. The field names can be whatever we choose as long // as they match the field names used in the <mappings> section of the // agent.cfg configuration file. Each time a record is read, convert it // to a StudentPersonal object using the Mappings class and stream it to // the supplied output stream. // IDbCommand command = null; // Set a basic filter on the outgoing data stream // What will happen is that any object written to the output stream will // be evaluated based on the query conditions. If the object doesn't meet the // query conditions, it will be excluded outStream.Filter = query; // Get the root Mappings object from the configuration file Edustructures.SifWorks.Tools.Mapping.Mappings m = fCfg.Mappings.GetMappings("Default"); // Ask the root Mappings instance to select a Mappings from its // hierarchy. For example, you might have customized the agent.cfg // file with mappings specific to zones, versions of SIF, or // requesting agents. The Mappings.select() method will select // the most appropriate instance from the hierarchy given the // three parameters passed to it. // //IDictionary<string, string> dataMap = new System.Collections.Generic.Dictionary<string, string>(); // IFieldAdaptor adaptor = new StringMapAdaptor(dataMap); //m.MapOutbound(); MappingsContext mc = m.SelectOutbound(StudentDTD.STUDENTPERSONAL, info); try { int count = 0; // Query the database for all students command = fConn.CreateCommand(); fConn.Open(); command.CommandText = "SELECT * FROM Students"; using (IDataReader rs = command.ExecuteReader(CommandBehavior.CloseConnection)) { DataReaderAdaptor dra = new DataReaderAdaptor(rs); while (rs.Read()) { // Finally, create a new StudentPersonal object and ask the // Mappings to populate it with SIF elements from the HashMap // of field/value pairs. As long as there is an <object>/<field> // definition for each entry in the HashMap, the ADK will take // care of producing the appropriate SIF element/attribute in // the StudentPersonal object. // StudentPersonal sp = new StudentPersonal(); sp.RefId = Adk.MakeGuid(); // TODO: When using custom macros for outboud mapping operations, set the ValueBuilder. // You will need to call SetValueBuilder() giving the MappingsContext a derived version // of DefaultValueBuilder that has the macro methods available in it. mc.SetValueBuilder(new DataUtilMacro(dra)); mc.Map(sp, dra); // Now write out the StudentPersonal to the output stream and // we're done publishing this student. // Console.WriteLine("\nThe agent has read these values from the database:"); DumpFieldsToConsole(rs); Console.WriteLine("To produce this StudentPersonal object:"); debug.Write(sp); debug.Flush(); outStream.Write(sp); } rs.Close(); } Console.WriteLine ("- Returned " + count + " records from the Student database in response"); } catch (Exception ex) { Console.WriteLine("- Returning a SIF_Error response: " + ex); throw new SifException (SifErrorCategoryCode.RequestResponse, SifErrorCodes.REQRSP_GENERIC_ERROR_1, "An error occurred while querying the database for students", ex.ToString(), zone); } finally { if (command != null) { try { fConn.Close(); } catch (Exception ignored) { Log.Warn(ignored.Message, ignored); } } } }
/// <summary> Post a SIF_LogEntry to the server. /// /// Use this form of the <c>log</c> method to post an error, warning, /// or informative message to the server that references a /// SIF Message and optionally a set of SIF Data Objects previously received /// by the agent. The log entry is assigned a category and code defined by /// the SIF Specification, and may have an extended error description and /// optional application-defined error code. /// /// </summary> /// <param name="level">The LogLevel to assign to this log entry /// </param> /// <param name="desc">A textual description of the error /// </param> /// <param name="extDesc">Extended error description, or <c>null</c> if no /// value is to be assigned to the SIF_LogEntry/SIF_ExtDesc element /// </param> /// <param name="appCode">Error code specific to the application posting the log /// entry, or <c>null</c> if no value is to be assigned to the /// SIF_LogEntry/SIF_ApplicationCode element /// </param> /// <param name="category">The SIF_Category value to assign to this log entry, as /// defined by the SIF Specification /// </param> /// <param name="category">The SIF_Code value to assign to this log entry, as /// defined by the SIF Specification /// </param> /// <param name="info">The <i>SifMessageInfo</i> instance from the Adk message /// handler implementation identifying a SIF Message received by the agent /// </param> /// <param name="objects">One or more SifDataObject instances received in the message /// identified by the <i>info</i> parameter /// </param> public virtual void Log(LogLevel level, string desc, string extDesc, string appCode, int category, int code, SifMessageInfo info, params SifDataObject [] objects) { if (fZone == null) { throw new SystemException ("ServerLog.log can only be called on a zone's ServerLog instance"); } string msg = null; SIF_LogEntry le = null; if (Adk.SifVersion.CompareTo(SifVersion.SIF15r1) >= 0) { // Create a SIF_LogEntry le = new SIF_LogEntry(); le.SetSource(LogSource.AGENT); le.SetLogLevel(LogLevel.Wrap(level == null ? "Unknown" : level.ToString())); if (desc != null) { le.SIF_Desc = desc; } if (extDesc != null) { le.SIF_ExtendedDesc = extDesc; } if (appCode != null) { le.SIF_ApplicationCode = appCode; } if (category != -1) { le.SIF_Category = category.ToString(); } if (code != -1) { le.SIF_Code = code; } // Reference a SIF_Message? if (info != null) { try { SIF_Header headerCopy = (SIF_Header)info.SIFHeader.Clone(); SIF_LogEntryHeader sleh = new SIF_LogEntryHeader(); sleh.SIF_Header = headerCopy; // Assign to SIF_OriginalHeader le.SIF_OriginalHeader = sleh; } catch (Exception ex) { fZone.Log.Warn ("Unable to clone SIF_Header for SIF_LogEntry event:" + ex.Message, ex); } } if (objects != null) { SIF_LogObjects slos = new SIF_LogObjects(); le.SIF_LogObjects = slos; for (int i = 0; i < objects.Length; i++) { if (objects[i] == null) { continue; } // Package into a SIF_LogObject and add to the repeatable list // of SIF_LogEntry/SIF_LogObjects SIF_LogObject lo = new SIF_LogObject(); lo.ObjectName = objects[i].ObjectType.Tag(info.SifVersion); lo.AddChild((SifElement)objects[i].Clone()); slos.Add(lo); } } } else { // When running in SIF 1.1 or earlier, there is no // SIF_LogEntry support. Build a string that can be // written to the local zone log, including as much // information from the would-be SIF_LogEntry as // possible. StringBuilder b = new StringBuilder(); b.Append("Server Log [Level="); b.Append(level == null ? "Unknown" : level.ToString()); if (category != -1 && code != -1) { b.Append(", Category="); b.Append(category); b.Append(", Code="); b.Append(code); } if (appCode != null) { b.Append(", AppCode="); b.Append(appCode); } b.Append("] "); if (desc != null) { b.Append(desc); } if (extDesc != null) { b.Append(". " + extDesc); } msg = b.ToString(); } // Post the the server IServerLogModule [] chain = _getLogChain(fZone); for (int i = 0; i < chain.Length; i++) { if (le != null) { chain[i].Log(fZone, le); } else { chain[i].Log(fZone, msg); } } }
public void OnQueryResults(IDataObjectInputStream data, SIF_Error error, IZone zone, IMessageInfo info) { SifMessageInfo smi = (SifMessageInfo)info; DateTime start = DateTime.Now; if (smi.Timestamp.HasValue) { start = smi.Timestamp.Value; } Console.WriteLine(); Console.WriteLine("********************************************* "); Console.WriteLine("Received SIF_Response packet from zone" + zone.ZoneId); Console.WriteLine("Details... "); Console.WriteLine("Request MsgId: " + smi.SIFRequestMsgId); Console.WriteLine("Packet Number: " + smi.PacketNumber); Console.WriteLine(); if (error != null) { Console.WriteLine("The publisher returned an error: "); Console.WriteLine("Category: " + error.SIF_Category + " Code: " + error.SIF_Code); Console.WriteLine("Description " + error.SIF_Desc); if (error.SIF_ExtendedDesc != null) { Console.WriteLine("Details: " + error.SIF_ExtendedDesc); } return; } try { int objectCount = 0; while (data.Available) { SifDataObject next = data.ReadDataObject(); objectCount++; Console.WriteLine(); Console.WriteLine("Text Values for " + next.ElementDef.Name + " " + objectCount + " {" + next.Key + "}"); SifXPathContext context = SifXPathContext.NewSIFContext(next); // Print out all attributes Console.WriteLine("Attributes:"); XPathNodeIterator textNodes = context.Select("//@*"); while (textNodes.MoveNext()) { XPathNavigator navigator = textNodes.Current; Element value = (Element)navigator.UnderlyingObject; IElementDef valueDef = value.ElementDef; Console.WriteLine(valueDef.Parent.Tag(SifVersion.LATEST) + "/@" + valueDef.Tag(SifVersion.LATEST) + "=" + value.TextValue + ", "); } Console.WriteLine(); // Print out all elements that have a text value Console.WriteLine("Element:"); textNodes = context.Select("//*"); while (textNodes.MoveNext()) { XPathNavigator navigator = textNodes.Current; Element value = (Element)navigator.UnderlyingObject; String textValue = value.TextValue; if (textValue != null) { IElementDef valueDef = value.ElementDef; Console.WriteLine(valueDef.Tag(SifVersion.LATEST) + "=" + textValue + ", "); } } } Console.WriteLine(); Console.WriteLine("Total Objects in Packet: " + objectCount); } catch (Exception ex) { Console.WriteLine(ex.Message); Console.WriteLine(ex.StackTrace); } if (!smi.MorePackets) { // This is the final packet. Print stats Console.WriteLine("Final Packet has been received."); IRequestInfo ri = smi.SIFRequestInfo; if (ri != null) { Console.WriteLine("Source Query: "); Console.WriteLine(ri.UserData); TimeSpan difference = start.Subtract(ri.RequestTime); Console.WriteLine("Query execution time: " + difference.Milliseconds + " ms"); } } else { Console.WriteLine("This is not the final packet for this SIF_Response"); } Console.WriteLine("********************************************* "); Console.WriteLine( ); PrintPrompt(); }
public void OnQueryPending(IMessageInfo info, IZone zone) { SifMessageInfo smi = (SifMessageInfo)info; Console.WriteLine("Sending SIF Request with MsgId " + smi.MsgId + " to zone " + zone.ZoneId); }
/// <summary> Dispatch a SIF_Event. /// /// <b>When ALQ Disabled:</b> Dispatching of this event is handled in a /// separate EvDisp thread in case SMB is invoked. This makes it possible /// to asynchronously return a SIF_Ack code to the dispatchEvent() caller /// before the handling of the event by the Subscriber is completed. The /// EvDisp also tracks the internal dispatch state of this particular message. /// The Topic matching the object type is then notified via its Subscriber's /// onEvent method. If a TrackQueryResults object is created within that /// method, its constructor will wakeup the EvDisp thread, instructing it to /// return a value of 2 (Intermediate). If no TrackQueryResults object is /// instantiated during the Subscriber.onEvent method, the EvDisp thread /// returns a 1 (Immediate) status code upon completion. /// /// <b>When ALQ Enabled:</b> Dispatching is immediate. The Topic matching /// the object type is then notified via its Subscriber's onEvent method, /// then processing ends. No EvDisp thread is needed because if a /// TrackQueryResults is used it will draw upon the ALQ instead of invoking /// SMB on the zone server. /// /// Note if an exception is thrown at any time during the processing of a /// SIF_Event, it is propagated up the call stack. The PH must not return a /// SIF_Ack for the message; the ALQ must not delete the message from its /// queue. /// /// </summary> private int dispatchEvent(SIF_Event sifEvent) { if ((Adk.Debug & AdkDebugFlags.Messaging_Event_Dispatching) != 0) { fZone.Log.Debug("Dispatching SIF_Event (" + sifEvent.MsgId + ")..."); } // Was this event reported by this agent? if (!fZone.Properties.ProcessEventsFromSelf && sifEvent.Header.SIF_SourceId.Equals(fZone.Agent.Id)) { if ((Adk.Debug & AdkDebugFlags.Messaging_Event_Dispatching) != 0) { fZone.Log.Debug ( "SIF_Event ignored because it was originally reported by this agent (see the adk.messaging.processEventsFromSelf property)"); } return 1; } SIF_ObjectData odata = sifEvent.SIF_ObjectData; if (odata == null) { throw new SifException (SifErrorCategoryCode.Xml, SifErrorCodes.XML_MISSING_MANDATORY_ELEMENT_6, "SIF_Event message missing mandatory element", "SIF_ObjectData is a required element", fZone); } // // Loop through all SIF_EventObjects inside this SIF_Event and dispatch // to corresponding topics // SIF_EventObject eventObj = odata.SIF_EventObject; if (eventObj == null) { throw new SifException ( SifErrorCategoryCode.Xml, SifErrorCodes.XML_MISSING_MANDATORY_ELEMENT_6, "SIF_Event message missing mandatory element", "SIF_ObjectData/SIF_EventObject is a required element", fZone); } int ackCode = 1; int thisCode; SifMessageInfo msgInfo = new SifMessageInfo(sifEvent, fZone); IElementDef typ = Adk.Dtd.LookupElementDef(eventObj.ObjectName); if (typ == null) { // SIF Data Object type not supported throw new SifException ( SifErrorCategoryCode.EventReportingAndProcessing, SifErrorCodes.EVENT_INVALID_EVENT_3, "Agent does not support this object type", eventObj.ObjectName, fZone); } // TODO: For now, the ADK only routes SIF Events to the first context // in the event. This needs to be implemented to support // events in multiple contexts SifContext eventContext = msgInfo.SIFContexts[0]; ISubscriber target = null; ITopic topic = null; // // Lookup the Topic for this SIF object type // Topics are only used for the SIF Default context // topic = fZone.Agent.TopicFactory.LookupInstance(typ, eventContext); if (topic != null) { target = topic.GetSubscriber(); } if (target == null) { // Is a Subscriber registered with the Zone? target = fZone.GetSubscriber(eventContext, typ); if (target == null) { // Is a Subscriber registered with the Agent? target = fZone.GetSubscriber(eventContext, typ); if (target == null) { // // No Subscriber message handler found. Try calling the Undeliverable- // MessageHandler for the zone or agent. If none is registered, // return an error SIF_Ack indicating the object type is not // supported. // Boolean handled = false; IUndeliverableMessageHandler errHandler = fZone.ErrorHandler; if (errHandler != null) { handled = errHandler.OnDispatchError(sifEvent, fZone, msgInfo); // Notify MessagingListeners... IEnumerable<IMessagingListener> mList = GetMessagingListeners(fZone); foreach (IMessagingListener ml in mList) { ml.OnMessageProcessed(SifMessageType.SIF_Event, msgInfo); } } if (!handled) { fZone.Log.Warn("Received a SIF_Event (" + sifEvent.MsgId + "), but no Subscriber object is registered to handle it"); throw new SifException( SifErrorCategoryCode.EventReportingAndProcessing, SifErrorCodes.EVENT_INVALID_EVENT_3, "Agent does not support this object type", eventObj.ObjectName, fZone); } return 1; } } } // // Call Subscriber.onEvent with the event data // IList<SifElement> sel = eventObj.GetChildList(); SifDataObject[] data = new SifDataObject[sel.Count]; for (int x = 0; x < sel.Count; x++) { data[x] = (SifDataObject)sel[x]; } // Wrap in an Event object DataObjectInputStreamImpl dataStr = DataObjectInputStreamImpl.newInstance(); dataStr.Data = data; Event adkEvent = new Event(dataStr, eventObj.Action, eventObj.GetChildList()[0].ElementDef); adkEvent.Zone = fZone; if ((Adk.Debug & AdkDebugFlags.Messaging_Event_Dispatching) != 0) { fZone.Log.Debug ( "SIF_Event contains " + data.Length + " " + eventObj.ObjectName + " objects (" + eventObj.Action + ")"); } if (fQueue == null) { if ((Adk.Debug & AdkDebugFlags.Messaging_Event_Dispatching) != 0) { fZone.Log.Debug ("Dispatching SIF_Event to Subscriber message handler via EvDisp"); } // // -- No ALQ available -- // Dispatch in a separate EvDisp thread. Block until an ack // status code is available, then return it // EvDisp disp; try { disp = checkoutEvDisp(adkEvent); thisCode = disp.dispatch(target, adkEvent, fZone, topic, msgInfo); } finally { checkinEvDisp(adkEvent); } } else { if ((Adk.Debug & AdkDebugFlags.Messaging_Event_Dispatching) != 0) { fZone.Log.Debug("Dispatching SIF_Event to Subscriber message handler"); } // // -- ALQ is available -- // Dispatch immediately. // try { target.OnEvent(adkEvent, fZone, msgInfo); } catch (SifException) { throw; } catch (Exception thr) { throw new SifException (SifErrorCategoryCode.EventReportingAndProcessing, SifErrorCodes.EVENT_GENERIC_ERROR_1, "Error processing SIF_Event", "Exception in Subscriber.onEvent message handler: " + thr, fZone); } thisCode = 1; } if (thisCode > ackCode) { ackCode = thisCode; } if ((Adk.Debug & AdkDebugFlags.Messaging) != 0) { fZone.Log.Debug ("SIF_Event (" + sifEvent.MsgId + ") dispatching returning SIF_Ack status " + ackCode); } return ackCode; }
/// <summary> Dispatch a SIF_Response. /// /// SIF_Response messages are dispatched as follows: /// /// <ul> /// <li> /// If a TrackQueryResults object issued the original SIF_Request /// during this agent session (i.e. the agent process has not /// terminated since the SIF_Request was issued), the response is /// dispatched to that TrackQueryResults object via its QueryResults /// interface. /// </li> /// <li> /// If a Topic exists for the data type associated with the /// SIF_Response, it is dispatched to the QueryResults object /// registered with that Topic. /// </li> /// <li> /// If no Topic exists for the data type associated with the /// SIF_Response, it is dispatched to the QueryResults object /// registered with the Zone from which the SIF_Response was /// received. /// </li> /// </ul> /// /// <b>SIF_ZoneStatus</b> is handled specially. When Zone.awaitingZoneStatus /// returns true, the agent is blocking on a call to Zone.getZoneStatus(). /// In this case, the SIF_ZoneStatus object is routed directly to the Zone /// object instead of being dispatched via the usual QueryResults mechanism. /// /// </summary> private void dispatchResponse(SIF_Response rsp) { // block thread until Zone.Query() has completed in case it is in the // midst of a SIF_Request. This is done to ensure that we don't receive // the SIF_Response from the zone before the ADK and agent have finished // with the SIF_Request in Zone.Query() fZone.WaitForRequestsToComplete(); bool retry = false; IRequestInfo reqInfo = null; AdkException cacheErr = null; try { try { reqInfo = fRequestCache.LookupRequestInfo(rsp.SIF_RequestMsgId, fZone); } catch (AdkException adke) { cacheErr = adke; } #if PROFILED if( objType != null ) { ProfilerUtils.profileStart( com.OpenADK.sifprofiler.api.OIDs.ADK_SIFRESPONSE_REQUESTOR_MESSAGING.ToString(), Adk.Dtd.LookupElementDef(objType), rsp.MsgId ); } #endif SIF_Error error = null; SIF_ObjectData od = rsp.SIF_ObjectData; if (od == null) { throw new SifException ( SifErrorCategoryCode.Xml, SifErrorCodes.XML_MISSING_MANDATORY_ELEMENT_6, "SIF_Response missing mandatory element", "SIF_ObjectData is a required element of SIF_Response", fZone); } IList<SifElement> sel = od.GetChildList(); if (sel.Count < 1) { error = rsp.SIF_Error; // // If the SIF_Response has no SIF_ObjectData elements but does // have a SIF_Error child, the associated object type can // only be gotten from the RequestCache, but that had // failed so try and call the UndeliverableMessageHandler. // if (cacheErr != null || reqInfo == null) { bool handled = false; IUndeliverableMessageHandler errHandler = fZone.ErrorHandler; if (errHandler != null) { SifMessageInfo msginfo = new SifMessageInfo(rsp, fZone); msginfo.SIFRequestInfo = reqInfo; handled = errHandler.OnDispatchError(rsp, fZone, msginfo); // Notify MessagingListeners... NotifyMessagingListeners_OnMessageProcessed (SifMessageType.SIF_Response, msginfo); } if (!handled) { fZone.Log.Warn ( "Received a SIF_Response message with MsgId " + rsp.MsgId + " (for SIF_Request with MsgId " + rsp.SIF_RequestMsgId + ") " + " containing an empty result set or a SIF_Error, but failed to obtain the SIF Data Object" + " type from the RequestCache" + (cacheErr != null ? (" due to an error: " + cacheErr.Message) : "")); } return; } } string objectType = reqInfo != null ? reqInfo.ObjectType : null; if (objectType == null && sel.Count > 0) { objectType = sel[0].ElementDef.Tag(rsp.SifVersion); } if (objectType != null && (string.Compare(objectType, "SIF_ZoneStatus", true) == 0)) { // SIF_ZoneStatus is a special case if (fZone.AwaitingZoneStatus()) { fZone.SetZoneStatus((SIF_ZoneStatus)sel[0]); return; } } if (reqInfo == null) { reqInfo = new UnknownRequestInfo(rsp.SIF_RequestMsgId, objectType); } // Decide where to send this response IQueryResults target = getQueryResultsTarget (rsp, null, Adk.Dtd.LookupElementDef(objectType), null, fZone); if (target == null) { bool handled = false; IUndeliverableMessageHandler errHandler = fZone.ErrorHandler; if (errHandler != null) { SifMessageInfo msginfo = new SifMessageInfo(rsp, fZone); if (reqInfo != null) { msginfo.SIFRequestInfo = reqInfo; } handled = errHandler.OnDispatchError(rsp, fZone, msginfo); // Notify MessagingListeners... NotifyMessagingListeners_OnMessageProcessed (SifMessageType.SIF_Response, msginfo); } if (!handled) { fZone.Log.Warn ("Received a SIF_Response message with MsgId " + rsp.MsgId + " (for SIF_Request with MsgId " + rsp.SIF_RequestMsgId + "), but no QueryResults object is registered to handle it or the request was issued by a TrackQueryResults that has timed out"); } return; } // // Dispatch the message... // IElementDef sifRequestObjectDef = Adk.Dtd.LookupElementDef(objectType); DataObjectInputStreamImpl dataStr = DataObjectInputStreamImpl.newInstance(); dataStr.fObjType = sifRequestObjectDef; if (error == null) { // Convert to a SifDataObject array SifDataObject[] data = new SifDataObject[sel.Count]; for (int i = 0; i < sel.Count; i++) { data[i] = (SifDataObject)sel[i]; } // Let the QueryResults object process the message dataStr.Data = data; } SifMessageInfo msgInf = new SifMessageInfo(rsp, fZone); msgInf.SIFRequestInfo = reqInfo; msgInf.SIFRequestObjectType = sifRequestObjectDef; target.OnQueryResults(dataStr, error, fZone, msgInf); // Notify MessagingListeners... NotifyMessagingListeners_OnMessageProcessed(SifMessageType.SIF_Response, msgInf); } catch (AdkException adkEx) { retry = adkEx.Retry; throw; } catch (Exception thr) { throw new SifException ( SifErrorCategoryCode.Generic, SifErrorCodes.GENERIC_GENERIC_ERROR_1, "Error processing SIF_Response", "Exception in QueryResults message handler: " + thr.ToString(), fZone); } finally { // If the reqInfo variable came from the cache, and retry is set to false, // remove it from the cache if this is the last packet if (!(reqInfo is UnknownRequestInfo) && !retry) { String morePackets = rsp.SIF_MorePackets; if (!(morePackets != null && morePackets.ToLower().Equals("yes"))) { // remove from the cache fRequestCache.GetRequestInfo(rsp.SIF_RequestMsgId, fZone); } } #if PROFILED if( BuildOptions.PROFILED ) { if( reqInfo != null ) { ProfilerUtils.profileStop(); } #endif } }
/// <summary> Dispatch a message. /// /// </summary> /// <param name="msg">The infrastructure message to dispatch /// </param> public virtual int dispatch(SifMessagePayload msg) { string errTyp = null; int status = 1; try { SifMessageType pload = (SifMessageType)Adk.Dtd.GetElementType(msg.ElementDef.Name); if (pload == SifMessageType.SIF_SystemControl) { IList<SifElement> ch = ((SIF_SystemControl)msg).SIF_SystemControlData.GetChildList(); if (ch != null && ch.Count > 0) { if (ch[0].ElementDef == InfraDTD.SIF_SLEEP) { fZone.ExecSleep(); } else if (ch[0].ElementDef == InfraDTD.SIF_WAKEUP) { fZone.ExecWakeup(); } else if (ch[0].ElementDef == InfraDTD.SIF_PING) { // Notify MessagingListeners... SifMessageInfo msginfo = new SifMessageInfo(msg, fZone); NotifyMessagingListeners_OnMessageProcessed (SifMessageType.SIF_SystemControl, msginfo); if (fZone.IsSleeping(AdkQueueLocation.QUEUE_LOCAL)) { return 8; } return 1; } else { fZone.Log.Warn("Received unknown SIF_SystemControlData: " + ch[0].Tag); throw new SifException (SifErrorCategoryCode.Xml, SifErrorCodes.XML_MISSING_MANDATORY_ELEMENT_6, "SIF_SystemControlData must contain SIF_Ping, SIF_Wakeup, or SIF_Sleep", fZone); } // Notify MessagingListeners... SifMessageInfo msginfo2 = new SifMessageInfo(msg, fZone); NotifyMessagingListeners_OnMessageProcessed (SifMessageType.SIF_SystemControl, msginfo2); } return status; } // If zone is asleep, return status code if (fZone.IsSleeping(AdkQueueLocation.QUEUE_LOCAL)) { return 8; } // Some agents don't want to receive messages - for example, the // SIFSend Adk Example agent. This is very rare but we offer a property // to allow for it if (fZone.Properties.DisableMessageDispatcher) { return status; } switch (pload) { case SifMessageType.SIF_Event: errTyp = "Subscriber.onEvent"; status = dispatchEvent((SIF_Event)msg); break; case SifMessageType.SIF_Request: errTyp = "Publisher.onRequest"; dispatchRequest((SIF_Request)msg); break; case SifMessageType.SIF_Response: errTyp = "QueryResults"; dispatchResponse((SIF_Response)msg); break; default: fZone.Log.Warn ("Agent does not know how to dispatch " + msg.ElementDef.Name + " messages"); throw new SifException (SifErrorCategoryCode.Generic, SifErrorCodes.GENERIC_MESSAGE_NOT_SUPPORTED_2, "Message not supported", msg.ElementDef.Name, fZone); } } catch (LifecycleException) { throw; } catch (SifException se) { // Check if AdkException.setRetry() was called; use transport // error category to force ZIS to resend message if (se.Retry) { se.ErrorCategory = SifErrorCategoryCode.Transport; se.ErrorCode = SifErrorCodes.WIRE_GENERIC_ERROR_1; } logAndRethrow("SIFException in " + errTyp + " message handler for " + msg.ElementDef.Name, se); } catch (AdkZoneNotConnectedException adkznce) { // Received a message while the zone was disconnected. Return a system transport // error so that the message is not removed from the queue SifException sifEx = new SifException( SifErrorCategoryCode.Transport, SifErrorCodes.WIRE_GENERIC_ERROR_1, adkznce.Message, fZone); logAndRethrow("Message received while zone is not connected", sifEx); } catch (AdkException adke) { // Check if ADKException.setRetry() was called; use transport // error category to force ZIS to resent message if (adke.Retry) { logAndThrowRetry(adke.Message, adke); } logAndThrowSIFException("ADKException in " + errTyp + " message handler for " + msg.ElementDef.Name, adke); } catch (Exception uncaught) { logAndThrowSIFException("Uncaught exception in " + errTyp + " message handler for " + msg.ElementDef.Name, uncaught); } return status; }
/// <summary> Respond to SIF Requests /// </summary> public virtual void OnRequest(IDataObjectOutputStream outStream, Query query, IZone zone, IMessageInfo inf) { SifMessageInfo info = (SifMessageInfo)inf; SifWriter debug = new SifWriter(Console.Out); Console.WriteLine ("Received a request for " + query.ObjectTag + " from agent \"" + info.SourceId + "\" in zone " + zone.ZoneId); // Tell the ADK to automatically filter out any objects that don't meet the requirements // of the query conditions outStream.Filter = query; // Read all learners from the database to populate a HashMap of // field/value pairs. The field names can be whatever we choose as long // as they match the field names used in the <mappings> section of the // agent.cfg configuration file. Each time a record is read, convert it // to a LearnerPersonal object using the Mappings class and stream it to // the supplied output stream. // IDictionary data = new Hashtable(); IDbCommand command = null; Console.WriteLine("The SIF Request was requested in the following SIF Versions"); foreach (SifVersion version in info.SIFRequestVersions) { Console.WriteLine(" - " + version); } Console.WriteLine("This agent will respond in its latest supported version, which is: "); Console.WriteLine(" - " + info.LatestSIFRequestVersion); // Get the root Mappings object from the configuration file Mappings m = fCfg.Mappings.GetMappings("Default").Select (info.SourceId, zone.ZoneId, info.LatestSIFRequestVersion); // Ask the root Mappings instance to select a Mappings from its // hierarchy. For example, you might have customized the agent.cfg // file with mappings specific to zones, versions of SIF, or // requesting agents. The Mappings.selectOutbound() method will select // the most appropriate instance from the hierarchy given the // three parameters passed to it. MappingsContext mappings = m.SelectOutbound(StudentDTD.STUDENTPERSONAL, info); try { int count = 0; // Query the database for all students command = fConn.CreateCommand(); fConn.Open(); command.CommandText = "SELECT * FROM Students"; using (IDataReader rs = command.ExecuteReader(CommandBehavior.CloseConnection)) { DataReaderAdaptor dra = new DataReaderAdaptor(rs); while (rs.Read()) { count++; // Finally, create a new LearnerPersonal object and ask the // Mappings to populate it with SIF elements from the HashMap // of field/value pairs. As long as there is an <object>/<field> // definition for each entry in the HashMap, the ADK will take // care of producing the appropriate SIF element/attribute in // the LearnerPersonal object. // StudentPersonal sp = new StudentPersonal(); sp.RefId = Adk.MakeGuid(); mappings.Map(sp, dra); // Now write out the LearnerPersonal to the output stream and // we're done publishing this student. // Console.WriteLine("\nThe agent has read these values from the database:"); DumpDictionaryToConsole(data); Console.WriteLine("To produce this LearnerPersonal object:"); debug.Write(sp); debug.Flush(); outStream.Write(sp); data.Clear(); } rs.Close(); } Console.WriteLine ("- Returned " + count + " records from the Student database in response"); } catch (Exception ex) { Console.WriteLine("- Returning a SIF_Error response: " + ex.ToString()); throw new SifException (SifErrorCategoryCode.RequestResponse, SifErrorCodes.REQRSP_GENERIC_ERROR_1, "An error occurred while querying the database for students", ex.ToString(), zone); } finally { if (command != null) { try { fConn.Close(); } catch (Exception ignored) { } } } }
private void NotifyMessagingListeners_OnMessageProcessed(SifMessageType messageType, SifMessageInfo info) { IEnumerable<IMessagingListener> msgList = GetMessagingListeners(fZone); foreach (IMessagingListener listener in msgList) { listener.OnMessageProcessed(messageType, info); } }
/// <summary> Dispatch a SIF_Request. /// /// <b>When ALQ Disabled:</b> The SIF_Request is immediately dispatched to /// the Publisher of the associated topic. Only after the Publisher has /// returned a result does this method return, causing the SIF_Request to /// be acknowledged. The result data returned by the Publisher is handed to /// the zone's ResponseDelivery thread, which sends SIF_Response messages to /// the ZIS until all of the result data has been sent, potentially with /// multiple SIF_Response packets. Note without the ALQ, there is the /// potential for the agent to terminate before all data has been sent, /// causing some results to be lost. In this case the SIF_Request will have /// never been ack'd and will be processed again the next time the agent /// is started. /// /// /// <b>When ALQ Enabled:</b> The SIF_Request is placed in the ALQ where it /// will be consumed by the zone's ResponseDelivery thread at a later time. /// This method returns immediately, causing the SIF_Request to be /// acknowledged. The ResponseDelivery handles dispatching the request to /// the Publisher of the associated topic, and also handles returning /// SIF_Response packets to the ZIS. With the ALQ, the processing of the /// SIF_Request and the returning of all SIF_Response data is guaranteed /// because the original SIF_Request will not be removed from the ALQ until /// both of these activities have completed successfully (even over multiple /// agent sessions). /// /// /// Note that any error that occurs during a SIF_Request should result in a /// successful SIF_Ack (because the SIF_Request was received successfully), /// and a single SIF_Response with a SIF_Error payload. The SIF Compliance /// harness checks for this. /// /// /// </summary> /// <param name="req">The SIF_Request to process /// </param> private void dispatchRequest(SIF_Request req) { SifVersion renderAsVer = null; SIF_Query q = null; SIF_QueryObject qo = null; IElementDef typ = null; int maxBufSize = 0; bool rethrow = false; try { // block thread until Zone.query() has completed in case it is in the // midst of a SIF_Request and the destination of that request is this // agent (i.e. a request of self). This is done to ensure that we don't // receive the SIF_Request from the zone before the ADK and agent have // finished issuing it in Zone.query() fZone.WaitForRequestsToComplete(); // // Check SIF_Version. If the version is not supported by the Adk, // fail the SIF_Request with an error SIF_Ack. If the version is // supported, continue on; the agent may not support this version, // but that will be determined later and will result in a SIF_Response // with a SIF_Error payload. // SIF_Version[] versions = req.GetSIF_Versions(); if (versions == null || versions.Length == 0) { rethrow = true; throw new SifException ( SifErrorCategoryCode.Xml, SifErrorCodes.XML_MISSING_MANDATORY_ELEMENT_6, "SIF_Request/SIF_Version is a mandatory element", fZone); } // SIF_Version specifies the version of SIF that will be used to render // the SIF_Responses // TODO: Add support for multiple SIF_Request versions renderAsVer = SifVersion.Parse(versions[0].Value); if (!Adk.IsSIFVersionSupported(renderAsVer)) { rethrow = true; throw new SifException ( SifErrorCategoryCode.RequestResponse, SifErrorCodes.REQRSP_UNSUPPORTED_SIFVERSION_7, "SIF_Version " + renderAsVer + " is not supported by this agent", fZone); } // Check max buffer size int? maximumBufferSize = req.SIF_MaxBufferSize; if (!maximumBufferSize.HasValue ) { rethrow = true; throw new SifException ( SifErrorCategoryCode.Xml, SifErrorCodes.XML_MISSING_MANDATORY_ELEMENT_6, "SIF_Request/SIF_MaxBufferSize is a mandatory element", fZone); } maxBufSize = maximumBufferSize.Value; if (maxBufSize < 4096 || maxBufSize > Int32.MaxValue) { throw new SifException ( SifErrorCategoryCode.RequestResponse, SifErrorCodes.REQRSP_UNSUPPORTED_MAXBUFFERSIZE_8, "Invalid SIF_MaxBufferSize value (" + maxBufSize + ")", "Acceptable range is 4096 to " + Int32.MaxValue, fZone); } // Check to see if the Context is supported try { IList<SifContext> contexts = req.SifContexts; } catch (AdkNotSupportedException contextNotSupported) { throw new SifException( SifErrorCategoryCode.Generic, SifErrorCodes.GENERIC_CONTEXT_NOT_SUPPORTED_4, contextNotSupported.Message, fZone); } // Lookup the SIF_QueryObject q = req.SIF_Query; if (q == null) { // If it's a SIF_ExtendedQuery or SIF_Example, throw the appropriate error if (req.SIF_ExtendedQuery != null) { throw new SifException( SifErrorCategoryCode.RequestResponse, SifErrorCodes.REQRSP_NO_SUPPORT_FOR_SIF_EXT_QUERY, "SIF_ExtendedQuery is not supported", fZone); } else { throw new SifException ( SifErrorCategoryCode.Xml, SifErrorCodes.XML_MISSING_MANDATORY_ELEMENT_6, "SIF_Request/SIF_Query is a mandatory element", fZone); } } qo = q.SIF_QueryObject; if (qo == null) { rethrow = true; throw new SifException ( SifErrorCategoryCode.Xml, SifErrorCodes.XML_MISSING_MANDATORY_ELEMENT_6, "SIF_Query/SIF_QueryObject is a mandatory element", fZone); } // Lookup the ElementDef for the requested object type typ = Adk.Dtd.LookupElementDef(qo.ObjectName); if (typ == null) { throw new SifException ( SifErrorCategoryCode.RequestResponse, SifErrorCodes.REQRSP_INVALID_OBJ_3, "Agent does not support this object type: " + qo.ObjectName, fZone); } } catch (SifException se) { if (!rethrow) { sendErrorResponse(req, se, renderAsVer, maxBufSize); } // rethrow all errors at this point throw se; // // Capture the SifException so it can be written to the output stream // // and thus returned as the payload of the SIF_Response message later // // in this function. // error = se; // fZone.Log.Error("Error in dispatchRequest that will be put into the SIF_Response", se); } // For now, SIFContext is not repeatable in SIF Requests SifContext requestContext = req.SifContexts[0]; Object target = null; // // Lookup the Publisher for this object type using Topics, // but only if the context is the Default context // if (typ != null && SifContext.DEFAULT.Equals(requestContext)) { ITopic topic = null; topic = fZone.Agent.TopicFactory.LookupInstance(typ, requestContext); if (topic != null) { target = topic.GetPublisher(); } } if (target == null) { target = fZone.GetPublisher(requestContext, typ); if (target == null) { // // No Publisher message handler found. Try calling the Undeliverable- // MessageHandler for the zone or agent. If none is registered, // return an error SIF_Ack indicating the object type is not // supported. // Boolean handled = false; IUndeliverableMessageHandler errHandler = fZone.ErrorHandler; if (errHandler != null) { SifMessageInfo msginfo = new SifMessageInfo(req, fZone); handled = errHandler.OnDispatchError(req, fZone, msginfo); // Notify MessagingListeners... foreach (IMessagingListener ml in GetMessagingListeners(fZone)) { ml.OnMessageProcessed(SifMessageType.SIF_Request, msginfo); } } if (!handled) { fZone.Log.Warn("Received a SIF_Request for " + qo.ObjectName + " (MsgId=" + req.MsgId + "), but no Publisher object is registered to handle it"); SifException sifEx = new SifException( SifErrorCategoryCode.RequestResponse, SifErrorCodes.REQRSP_INVALID_OBJ_3, "Agent does not support this object type", qo.ObjectName, fZone); sendErrorResponse(req, sifEx, renderAsVer, maxBufSize); throw sifEx; } else { #if PROFILED ( BuildOptions.PROFILED ) ProfilerUtils.profileStop(); #endif return; } } } //bool success; DataObjectOutputStreamImpl outStream = null; SifMessageInfo msgInfo = new SifMessageInfo(req, fZone); Query query = null; try { // Convert SIF_Request/SIF_Query into a Query object if (q != null) { query = new Query(q); } msgInfo.SIFRequestObjectType = typ; } catch (Exception thr) { fZone.Log.Debug(thr.ToString()); SifException sifEx = new SifException (SifErrorCategoryCode.Xml, SifErrorCodes.XML_MALFORMED_2, "Could not parse SIF_Query element", thr.Message, fZone, thr); sendErrorResponse(req, sifEx, renderAsVer, maxBufSize); throw sifEx; } try { outStream = DataObjectOutputStreamImpl.NewInstance(); outStream.Initialize ( fZone, query, req.SourceId, req.MsgId, renderAsVer, maxBufSize ); // Call the agent-supplied Publisher, or if we have an error, write // that error to the output stream instead ((IPublisher)target).OnRequest(outStream, query, fZone, msgInfo); // Notify MessagingListeners... NotifyMessagingListeners_OnMessageProcessed (SifMessageType.SIF_Request, msgInfo); } catch (SifException se) { // For a SIF_Request, a SifException (other than a Transport Error) // does not mean to return an error ack but instead to return a // valid SIF_Response with a SIF_Error payload (see the SIF // Specification). Transport Errors must be returned to the ZIS so // that the message will be retried later. // if (se.Retry || se.ErrorCategory == SifErrorCategoryCode.Transport) { //success = false; //retry was requested, so we have to tell the output stream to not send an empty response outStream.DeferResponse(); throw; } outStream.SetError(se.Error); } catch (AdkException adke) { // If retry requested, throw a Transport Error back to the ZIS // instead of returning a SIF_Error in the SIF_Response payload if (adke.Retry) { //success = false; //retry was requested, so we have to tell the output stream to not send an empty response outStream.DeferResponse(); throw; } // Return SIF_Error payload in SIF_Response SIF_Error err = new SIF_Error(); err.SIF_Category = (int)SifErrorCategoryCode.Generic; err.SIF_Code = SifErrorCodes.GENERIC_GENERIC_ERROR_1; err.SIF_Desc = adke.Message; outStream.SetError(err); } catch (Exception thr) { SIF_Error err = new SIF_Error(); err.SIF_Category = (int)SifErrorCategoryCode.Generic; err.SIF_Code = SifErrorCodes.GENERIC_GENERIC_ERROR_1; err.SIF_Desc = "Agent could not process the SIF_Request at this time"; err.SIF_ExtendedDesc = "Exception in " + "Publisher.onRequest" + " message handler: " + thr.ToString(); outStream.SetError(err); } finally { try { outStream.Close(); } catch { // Do Nothing } try { outStream.Commit(); } catch { /* Do Nothing */ } #if PROFILED ProfilerUtils.profileStop(); #endif outStream.Dispose(); } }
/// <summary> Handles SIF_Responses /// </summary> public virtual void OnQueryResults(IDataObjectInputStream inStream, SIF_Error error, IZone zone, IMessageInfo inf) { SifMessageInfo info = (SifMessageInfo)inf; Console.WriteLine ("\nReceived a query response from agent \"" + info.SourceId + "\" in zone " + zone.ZoneId); IRequestInfo reqInfo = info.SIFRequestInfo; if (reqInfo != null) { Console.WriteLine ("\nResponse was received in {0}. Object State is '{1}'", DateTime.Now.Subtract(reqInfo.RequestTime), reqInfo.UserData); } // // Use the Mappings class to translate the LearnerPersonal objects received // from the zone into a HashMap of field/value pairs, then dump the table // to System.out // // Always check for an error response if (error != null) { Console.WriteLine ("The request for LearnerPersonal failed with an error from the provider:"); Console.WriteLine (" [Category=" + error.SIF_Category + "; Code=" + error.SIF_Code + "]: " + error.SIF_Desc + ". " + error.SIF_ExtendedDesc); return; } // Get the root Mappings object from the configuration file Mappings m = fCfg.Mappings.GetMappings("Default"); // Ask the root Mappings instance to select a Mappings from its // hierarchy. For example, you might have customized the agent.cfg // file with mappings specific to zones, versions of SIF, or // requesting agents. The Mappings.select() method will select // the most appropriate instance from the hierarchy given the // three parameters passed to it. MappingsContext mappings = m.SelectInbound(StudentDTD.STUDENTPERSONAL, info); Hashtable data = new Hashtable(); StringMapAdaptor sma = new StringMapAdaptor(data, Adk.Dtd.GetFormatter(SifVersion.LATEST)); int count = 0; while (inStream.Available) { Console.WriteLine("Object Number {0}", count++); StudentPersonal sp = (StudentPersonal)inStream.ReadDataObject(); // Ask the Mappings object to populate the dictionary with field/value pairs // by using the mapping rules in the configuration file to decompose // the LearnerPersonal object into field values. mappings.Map(sp, sma); // Now dump the field/value pairs to System.out DumpDictionaryToConsole(data); Console.WriteLine(); data.Clear(); } }