/// <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();
            }
        }
        private void SetRequestPolicy( SIF_Request request, IZone zone )
        {
            SIF_Query query = request.SIF_Query;
            if( query == null ) {
            // SIF_ExtendedQuery and SIF_Example are not supported by ADK Policy yet
            return;
            }

            //
            // Object Request Policy
            //
            // Determine if there is policy in effect for this Query
            //
            String objectName = query.SIF_QueryObject.ObjectName;
            ObjectRequestPolicy requestPolicy = fPolicyFactory.GetRequestPolicy( zone, objectName );
            if( requestPolicy != null ){

            //
            // SIF_Request/SIF_Version policy
            //
            String requestVersions = requestPolicy.RequestVersion;
            if( requestVersions != null ){
                if( (Adk.Debug & AdkDebugFlags.Policy ) > 0 ){
                    zone.Log.Info( "POLICY: Setting SIF_Request/SIF_Version to " + requestVersions );
                }
                // Clear the list of SIF Versions
                foreach( SIF_Version existingVersion in request.GetSIF_Versions() ){
                    request.RemoveChild( existingVersion );
                }

                // The version will be a comma-delimited list. Set each of these
                // as SIF_Version elements, but also try to derive the most logical
                // version element to set the SIF Message/@Version attribute to
                // NOTE: Someone could theoretically set versions incorrectly, such
                // as "1.1,1.5r1". Multiple SIF_Version elements are not supported in
                // SIF 1.x, but we won't bother with validating incorrect settings. Policy
                // is power in the configurator's hands to use or abuse.

                String[] versions = requestVersions.Split( ',' );
                String lowestVersion = versions[0];
                foreach( String version in versions ){
                    String ver = version.Trim();
                    request.AddSIF_Version(new SIF_Version(ver));
                    if (lowestVersion.CompareTo(ver) > 0)
                    {
                        lowestVersion = ver;
                    }
                }

                // Determine how the SIF_Message/@Version should be set to
                //  * If the policy is set to a single version, use it
                //  * If a list, use the lowest
                //  * If *, ignore
                //  * if [major].*, use the lowest version supported
                if( lowestVersion.Length > 0  ){
                    SifVersion newMsgVersion = null;
                    if( lowestVersion.EndsWith( "*" ) ){
                        try
                        {
                            // 2.*, requests go out with a message version of 2.0r1
                            int major = int.Parse(  lowestVersion.Substring( 0, 1 ) );
                            newMsgVersion = SifVersion.GetEarliest( major );

                        } catch( FormatException iae ){
                            zone.Log.Warn(
                                    "POLICY: Error parsing ObjectRequestPolicy version '" +
                                    requestVersions + "' : " +
                                    iae.Message, iae );
                        }

                    } else {
                        try
                        {
                            newMsgVersion = SifVersion.Parse( lowestVersion );
                        } catch( FormatException iae ){
                            zone.Log.Warn(
                                    "POLICY: Error parsing ObjectRequestPolicy version '" +
                                    requestVersions + "' : " +
                                    iae.Message, iae );
                        }
                    }
                    if( newMsgVersion != null ){
                        if( (Adk.Debug & AdkDebugFlags.Policy ) > 0 ){
                            zone.Log.Info( "POLICY: Setting SIF_Messaage/@Version to " + newMsgVersion );
                        }
                        request.SifVersion = newMsgVersion;
                    }
                }
            }

            //
            // SIF_DestinationID policy
            //
            String requestSourceId = requestPolicy.RequestSourceId ;
            if( requestSourceId != null ){
                if( (Adk.Debug & AdkDebugFlags.Policy) > 0 ){
                    zone.Log.Info( "POLICY: Setting SIF_Request SIF_DestinationID to " + requestPolicy.RequestSourceId );
                }
                request.SIF_Header.SIF_DestinationId = requestSourceId;
            }
            }
        }