/// <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;
        }
Esempio n. 3
0
        /**
         *  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);
        }