예제 #1
0
        //        /// <summary>  Throws an AdkMessagingException, optionally logging its message first</summary>
        //        public static void  _throw(AdkMessagingException thr, Category log)
        //        {
        //            if ((Adk.Debug & AdkDebugFlags.Exceptions) != 0)
        //                thr.log(log);
        //            throw thr;
        //        }
        //        
        //        /// <summary>  Throws an AdkTransportException, optionally logging its message first</summary>
        //        public static void  _throw(AdkTransportException thr, Category log)
        //        {
        //            if ((Adk.Debug & AdkDebugFlags.Exceptions) != 0)
        //                thr.log(log);
        //            throw thr;
        //        }
        /// <summary>  Throws a SifException, optionally logging its message first</summary>
        public static void _throw( SifException thr,
                                   ILog log )
        {
            SifException exc = thr;

            //  If exception has a non-success status code and no errors, substitute a
            //  more descriptive exception
            if ( thr.Ack != null && (!thr.Ack.HasStatusCode( 0 ) && !thr.Ack.HasError()) ) {
                StringBuilder b = new StringBuilder();
                b.Append( "Received non-success status code (" );

                SIF_Status s = thr.Ack.SIF_Status;
                if ( s == null ) {
                    b.Append( "and no SIF_Status element exists" );
                }
                else {
                    b.Append( s.SIF_Code );
                }

                b.Append( ") but no error information" );

                exc = new SifException( b.ToString(), thr.Ack, thr.Zone );
            }

            if ( (Adk.Debug & AdkDebugFlags.Exceptions) != 0 ) {
                exc.Log( log );
            }

            throw exc;
        }
예제 #2
0
//		/// <summary>  Throws an AdkMessagingException, optionally logging its message first</summary>
//		public static void  _throw(AdkMessagingException thr, Category log)
//		{
//			if ((Adk.Debug & AdkDebugFlags.Exceptions) != 0)
//				thr.log(log);
//			throw thr;
//		}
//
//		/// <summary>  Throws an AdkTransportException, optionally logging its message first</summary>
//		public static void  _throw(AdkTransportException thr, Category log)
//		{
//			if ((Adk.Debug & AdkDebugFlags.Exceptions) != 0)
//				thr.log(log);
//			throw thr;
//		}

        /// <summary>  Throws a SifException, optionally logging its message first</summary>
        public static void _throw(SifException thr,
                                  ILog log)
        {
            SifException exc = thr;

            //  If exception has a non-success status code and no errors, substitute a
            //  more descriptive exception
            if (thr.Ack != null && (!thr.Ack.HasStatusCode(0) && !thr.Ack.HasError()))
            {
                StringBuilder b = new StringBuilder();
                b.Append("Received non-success status code (");

                SIF_Status s = thr.Ack.SIF_Status;
                if (s == null)
                {
                    b.Append("and no SIF_Status element exists");
                }
                else
                {
                    b.Append(s.SIF_Code);
                }

                b.Append(") but no error information");

                exc = new SifException(b.ToString(), thr.Ack, thr.Zone);
            }

            if ((Adk.Debug & AdkDebugFlags.Exceptions) != 0)
            {
                exc.Log(log);
            }

            throw exc;
        }
예제 #3
0
        /// <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);
        }
예제 #4
0
        /// <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;
        }
예제 #5
0
        private void doBehavior(IZone zone, String reportObjectRefId, IDataObjectOutputStream reportStream)
        {
            fWasCalled = true;
            if ((Behavior & HandlerBehavior.WaitForPulse) != 0)
            {
                Console.WriteLine("Signaling...");
                fSignalObject.Set();
                Console.WriteLine("Waiting...");
                fWaitForObject.WaitOne();
                Console.WriteLine("Resuming publishing...");
            }

            if ((Behavior & HandlerBehavior.ThrowException) != 0)
            {
                AdkException exc = new AdkException("Errors Occurred", zone);
                throw exc;
            }
            if ((Behavior & HandlerBehavior.ThrowADKRetryException) != 0)
            {
                AdkException exc = new AdkException("Errors Occurred", zone);
                exc.Retry = true;
                throw exc;
            }
            if ((Behavior & HandlerBehavior.ThrowSIFRetryException) != 0)
            {
                AdkException exc =
                    new SifException(SifErrorCategoryCode.Transport, SifErrorCodes.GENERIC_GENERIC_ERROR_1,
                                     "Errors Occurred", zone);
                exc.Retry = true;
                throw exc;
            }
            if ((Behavior & HandlerBehavior.ThrowNullPointerException) != 0)
            {
                throw new NullReferenceException("Bogus!");
            }
        }
예제 #6
0
        /// <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;
        }
예제 #7
0
 private void logAndThrowRetry(String shortMessage, Exception exception)
 {
     if ( (Adk.Debug & AdkDebugFlags.Exceptions) != 0 )
     {
         fZone.Log.Error( shortMessage, exception );
     }
     SifException exToThrow = new SifException(
         SifErrorCategoryCode.Transport,
         SifErrorCodes.WIRE_GENERIC_ERROR_1,
         shortMessage,
         exception.StackTrace,
         fZone );
     if ( (Adk.Debug & AdkDebugFlags.Exceptions) != 0 )
     {
         fZone.Log.Error( "Translated to a SIFException that will force a retry", exToThrow );
     }
     throw exToThrow;
 }
예제 #8
0
        private void logAndThrowSIFException(String shortMessage, Exception exception)
        {
            if ( (Adk.Debug & AdkDebugFlags.Exceptions) != 0 )
            {
                fZone.Log.Error( shortMessage, exception );
            }


            SifException exToThrow = new SifException(
                SifErrorCategoryCode.Generic,
                SifErrorCodes.GENERIC_GENERIC_ERROR_1,
                shortMessage,
                exception.StackTrace,
                fZone, exception );
            if ( (Adk.Debug & AdkDebugFlags.Exceptions) != 0 )
            {
                fZone.Log.Error( "Translated to a SIFException", exToThrow );
            }
            throw exToThrow;
        }
예제 #9
0
        /**
	 * Sends a SIF_Ack in response to a pulled message
	 * @param sifGetMessageAck The original SIF_Ack from the SIF_GetMessage. This is sometimes null, when
	 * 						parsing fails
	 * @param pulledMEssage The message delivered inside of the above ack. NOTE that even if parsing fails,
	 *          the SIFParser tries to return what it can, and will return this message payload (in getParsed()),
	 *          instead of the above container message.
	 * @param ackStatus The status to ack (NOTE: This is ignored if the err property is set)
	 * @param err The error to set in the SIF_Ack
	 */
	private void sendPushAck(SIF_Ack sifGetMessageAck,
			SifMessagePayload pulledMEssage, int ackStatus, SifException err) {
		try
		{
			SIF_Ack ack2 = null;
			if( fAckAckOnPull && sifGetMessageAck != null){
				ack2 = sifGetMessageAck.ackStatus( ackStatus );
			} else {
				ack2 = pulledMEssage.ackStatus(ackStatus);
			}


			//  If an error occurred processing the message, return
			//  the details in the SIF_Ack
			if( err != null )
			{
				fZone.Log.Debug( "Handling exception by creating a SIF_Error", err );

				SIF_Error newErr = new SIF_Error();
				newErr.SIF_Category =  (int)err.ErrorCategory;
				newErr.SIF_Code = err.ErrorCode;
				newErr.SIF_Desc = err.ErrorDesc;
				newErr.SIF_ExtendedDesc = err.ErrorExtDesc;
				ack2.SIF_Error = newErr;

				//  Get rid of the <SIF_Status>
				SIF_Status status = ack2.SIF_Status;
				if( status != null ) {
					ack2.RemoveChild( status );
				}
			}

			//  Send the ack
			send(ack2);
		}
		catch( Exception ackEx )
		{
			fZone.Log.Debug( "Failed to send acknowledgement to pulled message: " + ackEx, ackEx );
		}
	}
예제 #10
0
        /// <summary>  Poll the ZIS for messages pending in the agent's queue.
        /// 
        /// This method is typically called by a ProtocolHandler thread to perform a
        /// periodic pull when the agent is running in pull mode. It may also be
        /// called by the framework to force a pull if the framework requires an
        /// immediate response to a message it has sent to the ZIS, such as a
        /// request for SIF_ZoneStatus.
        /// 
        /// 
        /// If a message is retrieved from the ZIS, it is dispatched through the
        /// Adk's usual message routing mechanism just as pushed messages are. Thus,
        /// there is no difference between push and pull mode once a message has
        /// been obtained from the ZIS. Because message routing is asynchronous (i.e.
        /// the MessageDispatcher will forward the message to the appropriate
        /// framework or agent code), this method does not return a value. If an
        /// error is returned in the SIF_Ack, the agent's FaultListener will be
        /// notified if one is registered. If an exception occurs, it is thrown to
        /// the caller.
        /// 
        /// 
        /// Each time this method is invoked it repeatedly sends SIF_GetMessage to
        /// the ZIS until no more messages are available, effectively emptying out
        /// the agent's queue.
        /// 
        /// </summary>
        /// <returns> zero if no messages were waiting in the agent's queue; 1 if a
        /// message was pulled from the agent's queue; -1 if the zone is sleeping
        /// </returns>
        public virtual int Pull()
        {
            //  Wait for fPullCanStart to be set to true by the ZoneImpl class once
            //  the zone is connected
            if (fPullCanStart != null)
            {
                lock (fPullCanStart)
                {
                    try
                    {
                        Monitor.Wait(fPullCanStart);
                    }
                    catch
                    {
                        // Do Nothing
                    }
                }
            }

            while (true)
            {
                if ((Adk.Debug & AdkDebugFlags.Messaging_Pull) != 0)
                {
                    fZone.Log.Debug("Polling for next message...");
                }

                //  Send a SIF_GetMessage, get a SIF_Ack
                SIF_SystemControl sys = new SIF_SystemControl();
                SIF_SystemControlData cmd = new SIF_SystemControlData();
                cmd.AddChild(new SIF_GetMessage());
                sys.SIF_SystemControlData = cmd;
                SIF_Ack ack = null;
                try
                {
                    ack = send(sys, true);
                }
                catch (PullMessageParseException pmpe)
                {
                    // Unable to parse the pulled message. Try sending the proper
                    // Error SIF_Ack to remove the message from the queue
                    if (pmpe.fSourceMessage != null)
                    {
                        fZone.Log.Debug("Handling exception by creating a SIF_Error", pmpe.fParseException);
                        // Try parsing out the SIF_OriginalMsgId so that we can remove the message
                        // from the queue.
                        // Ack either the SIF_Ack or the internal, embedded message, based on our setting
                        int startIndex = fAckAckOnPull ? 0 : 10;
                        int messageStart = pmpe.fSourceMessage.IndexOf("<SIF_Message", startIndex);
                        SifException sourceException = null;
                        if (pmpe.fParseException is SifException)
                        {
                            sourceException = (SifException)pmpe.fParseException;
                        }
                        else
                        {
                            sourceException = new SifException(
                                SifErrorCategoryCode.Xml,
                                SifErrorCodes.XML_GENERIC_ERROR_1,
                                "Unable to parse pulled SIF_Message",
                                pmpe.fParseException.Message,
                                fZone, pmpe.fParseException );
                        }
                        SIF_Ack errorAck = SIFPrimitives.ackError(pmpe.fSourceMessage.Substring(messageStart), sourceException, fZone);
                        errorAck.SifVersion = sys.SifVersion;
                        send( errorAck );
                        continue;
                    }
                }


                //
                //  Process the response. If status code 9 (no message), no
                //  action is taken. If status code 0 (success), the content of
                //  the SIF_Status / SIF_Data element is parsed and dispatched.
                //  If an error is reported in the ack, the agent's fault
                //  handler is called with a SifException describing the error
                //  if a fault handler has been registered.
                //
                if (ack.HasStatusCode(SifStatusCodes.NO_MESSAGES_9))
                {
                    if ((Adk.Debug & AdkDebugFlags.Messaging_Pull ) != 0)
                        fZone.Log.Debug( "No messages waiting in agent queue" );

                    return 0;
                }

                if(ack.HasError())
                {
                    SifException se = new SifException(ack, fZone);
                    fZone.Log.Debug("Unable to pull the next message from the queue: " + se.ToString());
                    AdkUtils._throw(se, fZone.Log);
                }

                if (ack.HasStatusCode(SifStatusCodes.SUCCESS_0))
                {
                    AdkException parseEx = null;
                    SifMessagePayload payload = getPullMessagePayload(ack);
                    if ((Adk.Debug & ( AdkDebugFlags.Messaging | AdkDebugFlags.Messaging_Pull ) ) != 0)
                    {
                        fZone.Log.Debug("Pulled a " + payload.ElementDef.Tag(payload.SifVersion) + " message (SIF " + payload.SifVersion + ")");
                    }

                    #region	Notify MessagingListeners...

                    bool cancelled = false;
                    ICollection<IMessagingListener> msgList = GetMessagingListeners(fZone);
                    if (msgList.Count > 0)
                    {
                        StringWriter tmp = new StringWriter();
                        SifWriter sifwriter = new SifWriter(tmp);
                        sifwriter.Write(payload);
                        sifwriter.Flush();
                        tmp.Flush();

                        StringBuilder xml = new StringBuilder();
                        xml.Append(tmp.ToString());

                        //	Determine message type before parsing
                        foreach (IMessagingListener listener in msgList)
                        {
                            try
                            {
                                SifMessageType pload =
                                    (SifMessageType)
                                    Adk.Dtd.GetElementType(payload.ElementDef.Name);
                                MessagingReturnCode code = listener.OnMessageReceived(pload, xml);
                                switch (code)
                                {
                                    case MessagingReturnCode.Discard:
                                        cancelled = true;
                                        break;

                                    case MessagingReturnCode.Reparse:
                                        {
                                            try
                                            {
                                                //	Reparse the XML into a new message
                                                payload =
                                                    (SifMessagePayload)
                                                    fParser.Parse(xml.ToString(), fZone);
                                            }
                                            catch (IOException ioe)
                                            {
                                                parseEx =
                                                    new AdkException
                                                        (
                                                        "Failed to reparse message that was modified by MessagingListener: " +
                                                        ioe, fZone);
                                            }
                                        }
                                        break;
                                }
                            }
                            catch (AdkException adke)
                            {
                                parseEx = adke;
                            }
                        }
                    }

                    #endregion

                    if (fQueue != null)
                    {
                        //  TODO: put message on agent local queue
                    }
                    else
                    {
                        if (parseEx != null)
                        {
                            throw parseEx;
                        }

                        int ackStatus = SifStatusCodes.IMMEDIATE_ACK_1;
                        SifException err = null;
                        bool acknowledge = true;

                        try
                        {
                            //  Dispatch the message
                            if (!cancelled)
                            {
                                ackStatus = dispatch(payload);
                            }
                        }
                        catch (LifecycleException)
                        {
                            throw;
                        }
                        catch (SifException se)
                        {
                            err = se;
                        }
                        catch (AdkException adke)
                        {
                            //  TODO: This needs to generate proper category/code based on payload

                            if (adke.HasSifExceptions())
                            {
                                //  Return the first exception
                                err = adke.SIFExceptions[0];
                            }
                            else
                            {
                                //  Build a SifException to describe this AdkException
                                err =
                                    new SifException
                                        (SifErrorCategoryCode.Generic,
                                          SifErrorCodes.GENERIC_GENERIC_ERROR_1, adke.Message, fZone);
                            }
                        }
                        catch (Exception thr)
                        {
                            //  Uncaught exception (probably an Adk internal error)
                            string txt =
                                "An unexpected error occurred while processing a pulled message: " +
                                thr;
                            fZone.Log.Debug(txt);

                            //  Build a SifException to describe this Throwable
                            err =
                                new SifException
                                    (SifErrorCategoryCode.System, SifErrorCodes.SYS_GENERIC_ERROR_1,
                                      thr.Message, thr.ToString(), fZone, thr);

                            fZone.Log.Debug(err);
                        }

                        if (acknowledge)
                        {
                            sendPushAck(ack, payload, ackStatus, err);
                        }
                        else
                            return 1;
                    }
                }
                else
                {
                    // We only get to here if there is no error and no success code
                    if (ack.HasStatusCode(SifStatusCodes.SLEEPING_8))
                    {
                        //  Zone is sleeping
                        return -1;
                    }
                    else
                    {
                        // Unknown condition
                        AdkUtils._throw(new SifException(ack, fZone), fZone.Log );
                    }
                }
            }
        }
예제 #11
0
        private void sendErrorResponse(SIF_Request req, SifException se, SifVersion renderAsVer, int maxBufSize)
        {

            DataObjectOutputStreamImpl outStream = DataObjectOutputStreamImpl.NewInstance();
            outStream.Initialize(fZone, (IElementDef[])null, req.SourceId, req.MsgId, renderAsVer, maxBufSize);

            SIF_Error err = new SIF_Error(
                (int)se.ErrorCategory,
                se.ErrorCode,
                se.ErrorDesc);
            err.SIF_ExtendedDesc = se.ErrorExtDesc;

            outStream.SetError(err);
            try
            {
                outStream.Close();
            }
            catch (Exception ignored)
            {
                fZone.Log.Warn("Ignoring exception in out.close()", ignored);
            }

            try
            {
                outStream.Commit();
            }
            catch (Exception ignored)
            {
                fZone.Log.Warn("Ignoring exception in out.commit()", ignored);
            }
        }
예제 #12
0
        /// <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();
            }
        }
예제 #13
0
        public void ProcessRequest(AdkHttpRequestContext context)
        {
            if ((Adk.Debug & AdkDebugFlags.Messaging) != 0)
            {
                Zone.Log.Debug
                    ("Received push message from " + context.Request.RemoteAddress + " (" +
                    context.Request.Url.Scheme + ")");
            }

            SIF_Ack           ack    = null;
            SifMessagePayload parsed = null;

            //Check request length and type
            if (!SifIOFormatter.IsValidContentLength(context.Request.ContentLength))
            {
                throw new AdkHttpException
                          (AdkHttpStatusCode.ClientError_400_Bad_Request,
                          "Content length Must be greater than zero");
            }

            if (!SifIOFormatter.IsValidContentMediaType(context.Request.ContentType))
            {
                throw new AdkHttpException(AdkHttpStatusCode.ClientError_415_Unsupported_Media_Type,
                                           "Content header does not support the specified media type: " + context.Request.ContentType);
            }

            //  Read raw content
            Stream        requestStream = context.Request.GetRequestStream();
            StringBuilder requestXml    = null;

            // If we need to convert the request stream to a string for either logging or messaging, do so
            if ((Adk.Debug & AdkDebugFlags.Message_Content) != 0)
            {
                requestXml = ConvertRequestToString(requestStream);
                Zone.Log.Debug
                    ("Received " + context.Request.ContentLength + " bytes:\r\n" +
                    requestXml.ToString());
            }

            TextReader requestReader = new StreamReader(requestStream, SifIOFormatter.ENCODING);

            Exception parseEx   = null;
            bool      reparse   = false;
            bool      cancelled = false;
            int       reparsed  = 0;

            do
            {
                try {
                    parseEx = null;

                    //  Parse content
                    parsed  = (SifMessagePayload)CreateParser().Parse(requestReader, Zone);
                    reparse = false;
                    parsed.LogRecv(Zone.Log);
                }
                catch (AdkParsingException adke) {
                    parseEx = adke;
                }
                catch (Exception ex) {
                    parseEx = ex;
                }

                //
                //	Notify listeners...
                //
                //	If we're asked to reparse the message, do so but do not notify
                //	listeners the second time around.
                //
                if (reparsed == 0)
                {
                    ICollection <IMessagingListener> msgList = MessageDispatcher.GetMessagingListeners(Zone);
                    if (msgList.Count > 0)
                    {
                        // Convert the stream to a string builder
                        if (requestXml == null)
                        {
                            requestXml = ConvertRequestToString(requestStream);
                        }

                        //	Determine message type before parsing
                        foreach (IMessagingListener listener in msgList)
                        {
                            try {
                                SifMessageType pload =
                                    Adk.Dtd.GetElementType(parsed.ElementDef.Name);
                                MessagingReturnCode code =
                                    listener.OnMessageReceived(pload, requestXml);
                                switch (code)
                                {
                                case MessagingReturnCode.Discard:
                                    cancelled = true;
                                    break;

                                case MessagingReturnCode.Reparse:
                                    requestReader = new StringReader(requestXml.ToString());
                                    reparse       = true;
                                    break;
                                }
                            }
                            catch (AdkException adke) {
                                parseEx = adke;
                            }
                        }
                    }
                }

                if (cancelled)
                {
                    return;
                }

                reparsed++;
            }while (reparse);

            if (parseEx != null)
            {
                //  TODO: Handle the case where SIF_OriginalSourceId and SIF_OriginalMsgId
                //  are not available because parsing failed. See SIFInfra
                //  Resolution #157.
                if (parseEx is SifException && parsed != null)
                {
                    //  Specific SIF error already provided to us by SIFParser
                    ack = parsed.AckError((SifException)parseEx);
                }
                else
                {
                    String errorMessage = null;
                    if (parseEx is AdkException)
                    {
                        errorMessage = parseEx.Message;
                    }
                    else
                    {
                        // Unchecked Throwable
                        errorMessage = "Could not parse message";
                    }

                    if (parsed == null)
                    {
                        SifException sifError = null;
                        if (parseEx is SifException)
                        {
                            sifError = (SifException)parseEx;
                        }
                        else
                        {
                            sifError = new SifException(
                                SifErrorCategoryCode.Xml,
                                SifErrorCodes.XML_GENERIC_ERROR_1,
                                "Could not parse message",
                                parseEx.ToString(),
                                this.Zone,
                                parseEx);
                        }
                        if (requestXml == null)
                        {
                            requestXml = ConvertRequestToString(requestStream);
                        }
                        ack = SIFPrimitives.ackError(
                            requestXml.ToString( ),
                            sifError,
                            this.Zone);
                    }
                    else
                    {
                        ack = parsed.AckError(
                            SifErrorCategoryCode.Generic,
                            SifErrorCodes.GENERIC_GENERIC_ERROR_1,
                            errorMessage,
                            parseEx.ToString());
                    }
                }

                if ((Adk.Debug & AdkDebugFlags.Messaging) != 0)
                {
                    Zone.Log.Warn
                        ("Failed to parse push message from zone \"" + Zone + "\": " + parseEx);
                }

                if (ack != null)
                {
                    //  Ack messages in the same version of SIF as the original message
                    if (parsed != null)
                    {
                        ack.SifVersion = parsed.SifVersion;
                    }
                    AckPush(ack, context.Response);
                }
                else
                {
                    //  If we couldn't build a SIF_Ack, returning an HTTP 500 is
                    //  probably the best we can do to let the server know that
                    //  we didn't get the message. Note this should cause the ZIS
                    //  to resend the message, which could result in a deadlock
                    //  condition. The administrator would need to manually remove
                    //  the offending message from the agent's queue.

                    if ((Adk.Debug & AdkDebugFlags.Messaging) != 0)
                    {
                        Zone.Log.Debug
                            ("Could not generate SIF_Ack for failed push message (returning HTTP/1.1 500)");
                    }
                    throw new AdkHttpException
                              (AdkHttpStatusCode.ServerError_500_Internal_Server_Error,
                              "Could not generate SIF_Ack for failed push message (returning HTTP/1.1 500)");
                }

                return;
            }

            //  Check SourceId to see if it matches this agent's SourceId
            String destId = parsed.DestinationId;

            if (destId != null && !destId.Equals(Zone.Agent.Id))
            {
                Zone.Log.Warn
                    ("Received push message for DestinationId \"" + destId +
                    "\", but agent is registered as \"" + Zone.Agent.Id + "\"");

                ack = parsed.AckError
                      (
                    SifErrorCategoryCode.Transport,
                    SifErrorCodes.WIRE_GENERIC_ERROR_1,
                    "Message not intended for this agent (SourceId of agent does not match DestinationId of message)",
                    "Message intended for \"" + destId + "\" but this agent is registered as \"" +
                    Zone.Agent.Id + "\"");

                AckPush(ack, context.Response);

                return;
            }

            //  Convert content to SIF message object and dispatch it
            ack = ProcessPush(parsed);

            //  Send SIF_Ack reply
            AckPush(ack, context.Response);
        }