/// <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; }
private SIF_Event createSIF_Event(IElementDef objType) { SIF_Event evnt = new SIF_Event(); evnt.Header.SIF_SourceId = "foo"; SIF_ObjectData sod = new SIF_ObjectData(); SIF_EventObject obj = new SIF_EventObject(); obj.ObjectName = objType.Name; sod.SIF_EventObject = obj; evnt.SIF_ObjectData = sod; obj.Action = EventAction.Add.ToString(); Object eventObject = null; try { eventObject = ClassFactory.CreateInstance(objType.FQClassName); } catch (Exception cfe) { throw new AdkException("Unable to create instance of " + objType.Name, fZone, cfe); } obj.AddChild(objType, (SifElement)eventObject); return evnt; }
/** * Sends a SIF_Event * @param zone The zone to send the sifEvent to */ public SIF_Ack SifEvent(IZone zone, Event sifEvent, String destinationId, String sifMsgId) { if (sifEvent.Data == null || sifEvent.Data.Available == false) { throw new AdkException("The sifEvent has no SIFDataObjects", zone); } SIF_ObjectData od = new SIF_ObjectData(); // Fill out the SIF_ObjectData IDataObjectInputStream inStr = sifEvent.Data; SifDataObject data = inStr.ReadDataObject(); SifVersion msgVersion = data.EffectiveSIFVersion; SIF_EventObject eo = new SIF_EventObject(); od.SIF_EventObject = eo; eo.Action = sifEvent.ActionString; eo.ObjectName = data.ElementDef.Tag(msgVersion); // Create the SIF_Event object SIF_Event msg = new SIF_Event(msgVersion); msg.SIF_ObjectData = od; SIF_Header msgHdr = msg.Header; // Assign SIF_DestinationId if applicable if (destinationId != null) { msgHdr.SIF_DestinationId = destinationId; } while (data != null) { eo.Attach(data); data = inStr.ReadDataObject(); } if (sifMsgId != null) { msgHdr.SIF_MsgId = sifMsgId; } SifContext[] contexts = sifEvent.Contexts; if (contexts == null) { contexts = new SifContext[] { SifContext.DEFAULT }; } SIF_Contexts msgContexts = new SIF_Contexts(); foreach (SifContext context in contexts) { msgContexts.AddSIF_Context(context.Name); } msgHdr.SIF_Contexts = msgContexts; return ((ZoneImpl)zone).Dispatcher.send(msg); }