File: LocalProvider\LocalCallDescriptor.cs
Web Access
Project: ..\..\..\src\Deprecated\Engine\Microsoft.Build.Engine.csproj (Microsoft.Build.Engine)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
// THE ASSEMBLY BUILT FROM THIS SOURCE FILE HAS BEEN DEPRECATED FOR YEARS. IT IS BUILT ONLY TO PROVIDE
// BACKWARD COMPATIBILITY FOR API USERS WHO HAVE NOT YET MOVED TO UPDATED APIS. PLEASE DO NOT SEND PULL
// REQUESTS THAT CHANGE THIS FILE WITHOUT FIRST CHECKING WITH THE MAINTAINERS THAT THE FIX IS REQUIRED.
 
using System;
using System.Collections;
using System.Threading;
using System.IO;
using System.Runtime.Serialization.Formatters.Binary;
using Microsoft.Build.BuildEngine.Shared;
 
namespace Microsoft.Build.BuildEngine
{
    /// <summary>
    /// This call is used to contain, serialize and deserialize arguments for call
    /// made via INodeProvider and IEngineCallback interfaces. To make calls via these
    /// interfaces asyncronous the parameters are queued up for a IO thread which
    /// reads/writes the shared memory buffer to transfer these parameters cross
    /// process.
    /// </summary>
    internal abstract class LocalCallDescriptor
    {
        #region Constructors
        internal LocalCallDescriptor()
        {
        }
 
        internal LocalCallDescriptor(LocalCallType callType)
        {
            this.callType = callType;
            this.callNumber = Interlocked.Increment(ref lastUsedCallNumber);
        }
        #endregion
 
        // For testing
        #region Properties
        internal int CallNumber
        {
            get
            {
                return this.callNumber;
            }
        }
        internal LocalCallType CallType
        {
            get
            {
                return this.callType;
            }
        }
        internal virtual bool NeedsReply
        {
            get
            {
                return false;
            }
        }
        internal virtual bool IsReply
        {
            get
            {
                return false;
            }
        }
        #endregion
 
        #region Methods
        /// <summary>
        /// Appropriate action to take if this event is received on the parent process
        /// </summary>
        internal virtual void HostAction(IEngineCallback engineCallback, LocalNodeProvider nodeProvider, int nodeId)
        {
            ErrorUtilities.VerifyThrow(false, "This description doesn't support this operation");
        }
 
        /// <summary>
        /// Appropriate action to take if this event is received on the child process
        /// </summary>
        internal virtual void NodeAction(Node node, LocalNode localNode)
        {
            ErrorUtilities.VerifyThrow(false, "This description doesn't support this operation");
        }
 
        /// <summary>
        /// This method constructs a reply to the node if appropriate
        /// </summary>
        /// <returns>The call descriptor to be sent back to the node</returns>
        internal virtual LocalReplyCallDescriptor ReplyFromHostAction()
        {
            ErrorUtilities.VerifyThrow(false, "This description doesn't support this operation");
            return null;
        }
 
        internal virtual object GetReplyData()
        {
            ErrorUtilities.VerifyThrow(false, "This description doesn't support this operation");
            return null;
        }
        #endregion
 
        #region Data
        private int callNumber;
        protected LocalCallType callType;
        // A counter used to provide unique Id's to all calls, is not serialized as it is static
        private static int lastUsedCallNumber = 0;
        #endregion
 
        #region CustomSerializationToStream
        internal virtual void WriteToStream(BinaryWriter writer)
        {
            writer.Write((byte)callType);
            writer.Write((Int32)callNumber);
        }
 
        internal virtual void CreateFromStream(BinaryReader reader)
        {
            callType = (LocalCallType)reader.ReadByte();
            callNumber = reader.ReadInt32();
        }
        #endregion
    }
 
    #region Wrapper for LocalReplyCallDescriptor
    internal class LocalReplyCallDescriptor : LocalCallDescriptor
    {
        #region Constructors
        internal LocalReplyCallDescriptor()
        {
            //Do Nothing
        }
 
        internal LocalReplyCallDescriptor(int requestingCallNumber, object replyData)
            : base(LocalCallType.GenericSingleObjectReply)
        {
            this.requestingCallNumber = requestingCallNumber;
            this.replyData = replyData;
        }
        #endregion
 
        #region Properties
        internal override bool IsReply
        {
            get
            {
                return true;
            }
        }
 
        internal virtual int RequestingCallNumber
        {
            get
            {
                return requestingCallNumber;
            }
        }
 
        internal object ReplyData
        {
            get
            {
                return replyData;
            }
        }
        #endregion
 
        #region Methods
        internal override void NodeAction(Node node, LocalNode localNode)
        {
            // No node action here, we do our thing in GetReplyData
        }
 
        internal override object GetReplyData()
        {
            return this.replyData;
        }
        #endregion
 
        #region Data
        private int requestingCallNumber;
        private object replyData;
        private static BinaryFormatter formatter = new BinaryFormatter();
        #endregion
 
        #region CustomSerializationToStream
        internal override void WriteToStream(BinaryWriter writer)
        {
            base.WriteToStream(writer);
            writer.Write((Int32)requestingCallNumber);
            if (replyData == null)
            {
                writer.Write((byte)0);
            }
            else
            {
                writer.Write((byte)1);
 
                if (replyData is CacheEntry[])
                {
                    writer.Write((byte)0);
                    CacheEntry[] cacheArray = (CacheEntry[])replyData;
                    writer.Write((Int32)cacheArray.Length);
                    for (int i = 0; i < cacheArray.Length; i++)
                    {
                        if (cacheArray[i] == null)
                        {
                            writer.Write((byte)0);
                        }
                        else
                        {
                            writer.Write((byte)1);
                            CacheEntryCustomSerializer.WriteToStream(cacheArray[i], writer);
                        }
                    }
                }
                else
                {
                    writer.Write((byte)1);
                    formatter.Serialize(writer.BaseStream, replyData);
                }
            }
        }
 
        internal override void CreateFromStream(BinaryReader reader)
        {
            base.CreateFromStream(reader);
            requestingCallNumber = reader.ReadInt32();
 
            if (reader.ReadByte() == 0)
            {
                replyData = null;
            }
            else
            {
                if (reader.ReadByte() == 0)
                {
                    int numberOfEntries = reader.ReadInt32();
                    CacheEntry[] cacheArray = new CacheEntry[numberOfEntries];
 
                    for (int i = 0; i < numberOfEntries; i++)
                    {
                        if (reader.ReadByte() == 0)
                        {
                            cacheArray[i] = null;
                        }
                        else
                        {
                            cacheArray[i] = CacheEntryCustomSerializer.CreateFromStream(reader);
                        }
                    }
                    replyData = cacheArray;
                }
                else
                {
                    replyData = formatter.Deserialize(reader.BaseStream);
                }
            }
        }
        #endregion
    }
    #endregion
 
    #region Wrapper for PostBuildRequests
    internal class LocalCallDescriptorForPostBuildRequests : LocalCallDescriptor
    {
        #region Constructors
        internal LocalCallDescriptorForPostBuildRequests()
        {
        }
 
        internal LocalCallDescriptorForPostBuildRequests(BuildRequest[] buildRequests)
            : base(LocalCallType.PostBuildRequests)
        {
            this.buildRequests = buildRequests;
        }
 
        internal LocalCallDescriptorForPostBuildRequests(BuildRequest buildRequest)
            : base(LocalCallType.PostBuildRequests)
        {
            this.buildRequests = new BuildRequest[1];
            this.buildRequests[0] = buildRequest;
        }
 
        #endregion
 
        #region Methods
        internal override void HostAction(IEngineCallback engineCallback, LocalNodeProvider nodeProvider, int nodeId)
        {
            engineCallback.PostBuildRequestsToHost(buildRequests);
        }
 
        /// <summary>
        /// Appropriate action to take if this event is received on the child process
        /// </summary>
        internal override void NodeAction(Node node, LocalNode localNode)
        {
            for (int i = 0; i < buildRequests.Length; i++)
            {
                node.PostBuildRequest(buildRequests[i]);
            }
        }
        #endregion
 
        #region Data
        private BuildRequest[] buildRequests;
        #endregion
 
        // For testing
        #region Properties
        internal BuildRequest[] BuildRequests
        {
            get
            {
                return buildRequests;
            }
        }
        #endregion
 
        #region CustomSerializationToStream
        internal override void WriteToStream(BinaryWriter writer)
        {
            ErrorUtilities.VerifyThrow(buildRequests != null, "buildRequests should not be null");
            base.WriteToStream(writer);
            writer.Write(buildRequests.Length);
            foreach (BuildRequest request in buildRequests)
            {
                request.WriteToStream(writer);
            }
        }
 
        internal override void CreateFromStream(BinaryReader reader)
        {
            base.CreateFromStream(reader);
            int numberOfBuildRequests = reader.ReadInt32();
            buildRequests = new BuildRequest[numberOfBuildRequests];
            for (int i = 0; i < numberOfBuildRequests; i++)
            {
                buildRequests[i] = BuildRequest.CreateFromStream(reader);
            }
        }
        #endregion
    }
    #endregion
 
    #region Wrapper for PostBuildResult
    internal class LocalCallDescriptorForPostBuildResult : LocalCallDescriptor
    {
        #region Constructors
 
        internal LocalCallDescriptorForPostBuildResult()
        {
        }
 
        internal LocalCallDescriptorForPostBuildResult(BuildResult buildResult)
            : base(LocalCallType.PostBuildResult)
        {
            this.buildResult = buildResult;
        }
 
        #endregion
 
        #region Methods
        internal override void HostAction(IEngineCallback engineCallback, LocalNodeProvider nodeProvider, int nodeId)
        {
            engineCallback.PostBuildResultToHost(buildResult);
        }
 
        /// <summary>
        /// Appropriate action to take if this event is received on the child process
        /// </summary>
        internal override void NodeAction(Node node, LocalNode localNode)
        {
            node.PostBuildResult(buildResult);
        }
        #endregion
 
        #region Data
        private BuildResult buildResult;
        #endregion
 
        // For testing
        #region Properties
        internal BuildResult ResultOfBuild
        {
            get
            {
                return buildResult;
            }
        }
        #endregion
 
        #region CustomSerializationToStream
        internal override void WriteToStream(BinaryWriter writer)
        {
            ErrorUtilities.VerifyThrow(buildResult != null, "buildResult should not be null");
            base.WriteToStream(writer);
            buildResult.WriteToStream(writer);
        }
 
        internal override void CreateFromStream(BinaryReader reader)
        {
            base.CreateFromStream(reader);
            buildResult = BuildResult.CreateFromStream(reader);
        }
        #endregion
    }
    #endregion
 
    #region Wrapper for PostLoggingMessagesToHost
    internal class LocalCallDescriptorForPostLoggingMessagesToHost : LocalCallDescriptor
    {
        #region Constructors
        internal LocalCallDescriptorForPostLoggingMessagesToHost()
        {
        }
 
        internal LocalCallDescriptorForPostLoggingMessagesToHost(NodeLoggingEvent[] buildEvents)
            : base(LocalCallType.PostLoggingMessagesToHost)
        {
            this.buildEvents = buildEvents;
        }
        #endregion
 
        #region Methods
        internal override void HostAction(IEngineCallback engineCallback, LocalNodeProvider nodeProvider, int nodeId)
        {
            engineCallback.PostLoggingMessagesToHost(nodeId, buildEvents);
        }
        #endregion
 
        #region Data
        private NodeLoggingEvent[] buildEvents;
        #endregion
 
        // For testing
        #region Properties
        internal NodeLoggingEvent[] BuildEvents
        {
            get
            {
                return buildEvents;
            }
        }
        #endregion
 
        #region CustomSerializationToStream
        internal void WriteToStream(BinaryWriter writer, Hashtable loggingTypeCache)
        {
            ErrorUtilities.VerifyThrow(buildEvents != null, "buildRequests should not be null");
            base.WriteToStream(writer);
 
            writer.Write((Int32)buildEvents.Length);
            foreach (NodeLoggingEvent nodeEvent in buildEvents)
            {
                if (nodeEvent.GetType() == typeof(NodeLoggingEvent))
                {
                    writer.Write((byte)0);
                }
                else
                {
                    writer.Write((byte)1);
                }
                nodeEvent.WriteToStream(writer, loggingTypeCache);
            }
        }
 
        internal void CreateFromStream(BinaryReader reader, Hashtable loggingTypeCache)
        {
            base.CreateFromStream(reader);
 
            int numberOfNodeEvents = reader.ReadInt32();
            buildEvents = new NodeLoggingEvent[numberOfNodeEvents];
 
            for (int i = 0; i < numberOfNodeEvents; i++)
            {
                NodeLoggingEvent e;
                if (reader.ReadByte() == 0)
                {
                    e = new NodeLoggingEvent();
                }
                else
                {
                    e = new NodeLoggingEventWithLoggerId();
                }
                e.CreateFromStream(reader, loggingTypeCache);
                buildEvents[i] = e;
            }
        }
        #endregion
 
    }
    #endregion
 
    #region Wrapper for UpdateNodeSettings
    internal class LocalCallDescriptorForUpdateNodeSettings : LocalCallDescriptor
    {
        #region Constructors
        internal LocalCallDescriptorForUpdateNodeSettings()
        {
        }
 
        internal LocalCallDescriptorForUpdateNodeSettings
        (
            bool enableLogOnlyCriticalEvents,
            bool enableCentralizedLogging,
            bool useBreadthFirstTraversal
        )
            : base(LocalCallType.UpdateNodeSettings)
        {
            this.logOnlyCriticalEvents = enableLogOnlyCriticalEvents;
            this.centralizedLogging = enableCentralizedLogging;
            this.useBreadthFirstTraversal = useBreadthFirstTraversal;
        }
        #endregion
 
        #region Methods
        /// <summary>
        /// UNDONE - need to verified after logging spec
        /// </summary>
        internal override void NodeAction(Node node, LocalNode localNode)
        {
            ErrorUtilities.VerifyThrowArgumentNull(node, "node is null");
            node.UpdateNodeSettings(logOnlyCriticalEvents, centralizedLogging, useBreadthFirstTraversal);
        }
        #endregion
 
        #region Data
        private bool logOnlyCriticalEvents;
        private bool centralizedLogging;
        private bool useBreadthFirstTraversal;
        #endregion
 
        // For testing
        #region Properties
        internal bool LogOnlyCriticalEvents
        {
            get
            {
                return logOnlyCriticalEvents;
            }
        }
 
        internal bool CentralizedLogging
        {
            get
            {
                return centralizedLogging;
            }
        }
 
        internal bool UseBreadthFirstTraversal
        {
            get
            {
                return useBreadthFirstTraversal;
            }
        }
        #endregion
 
        #region CustomSerializationToStream
        internal override void WriteToStream(BinaryWriter writer)
        {
            base.WriteToStream(writer);
            writer.Write(logOnlyCriticalEvents);
            writer.Write(centralizedLogging);
            writer.Write(useBreadthFirstTraversal);
        }
 
        internal override void CreateFromStream(BinaryReader reader)
        {
            base.CreateFromStream(reader);
            logOnlyCriticalEvents = reader.ReadBoolean();
            centralizedLogging = reader.ReadBoolean();
            useBreadthFirstTraversal = reader.ReadBoolean();
        }
        #endregion
 
    }
    #endregion
 
    #region Wrapper for ShutdownNode
    internal class LocalCallDescriptorForShutdownNode : LocalCallDescriptor
    {
        #region Constructors
        internal LocalCallDescriptorForShutdownNode()
        {
        }
 
        internal LocalCallDescriptorForShutdownNode(Node.NodeShutdownLevel shutdownLevel, bool exitProcess)
            : base(LocalCallType.ShutdownNode)
        {
            this.exitProcess = exitProcess;
            this.shutdownLevel = shutdownLevel;
        }
        #endregion
 
        #region Methods
        internal override void NodeAction(Node node, LocalNode localNode)
        {
            localNode.ShutdownNode(shutdownLevel, exitProcess, false);
        }
        #endregion
 
        #region Data
        private bool exitProcess;
        private Node.NodeShutdownLevel shutdownLevel;
        #endregion
 
        // For testing
        #region Properties
        internal bool ExitProcess
        {
            get
            {
                return exitProcess;
            }
        }
 
        internal Node.NodeShutdownLevel ShutdownLevel
        {
            get
            {
                return shutdownLevel;
            }
        }
        #endregion
 
        #region CustomSerializationToStream
        internal override void WriteToStream(BinaryWriter writer)
        {
            base.WriteToStream(writer);
            writer.Write(exitProcess);
            writer.Write((Int32)shutdownLevel);
        }
 
        internal override void CreateFromStream(BinaryReader reader)
        {
            base.CreateFromStream(reader);
            exitProcess = reader.ReadBoolean();
            shutdownLevel = (Node.NodeShutdownLevel)reader.ReadInt32();
        }
        #endregion
    }
    #endregion
 
    #region Wrapper for ShutdownComplete
    internal class LocalCallDescriptorForShutdownComplete : LocalCallDescriptor
    {
        #region Constructors
        internal LocalCallDescriptorForShutdownComplete()
        {
        }
 
        internal LocalCallDescriptorForShutdownComplete(Node.NodeShutdownLevel shutdownLevel, int totalTaskTime)
            : base(LocalCallType.ShutdownComplete)
        {
            this.shutdownLevel = shutdownLevel;
            this.totalTaskTime = totalTaskTime;
        }
        #endregion
 
        #region Methods
        internal override void HostAction(IEngineCallback engineCallback, LocalNodeProvider nodeProvider, int nodeId)
        {
            nodeProvider.RecordNodeResponse(nodeId, shutdownLevel, totalTaskTime);
        }
        #endregion
 
        #region Data
        private Node.NodeShutdownLevel shutdownLevel;
        private int totalTaskTime;
        #endregion
 
        // For testing
        #region Properties
        internal Node.NodeShutdownLevel ShutdownLevel
        {
            get
            {
                return shutdownLevel;
            }
        }
        #endregion
 
 
        #region CustomSerializationToStream
        internal override void WriteToStream(BinaryWriter writer)
        {
            base.WriteToStream(writer);
            writer.Write((Int32)shutdownLevel);
            writer.Write((Int32)totalTaskTime);
        }
 
        internal override void CreateFromStream(BinaryReader reader)
        {
            base.CreateFromStream(reader);
            shutdownLevel = (Node.NodeShutdownLevel)reader.ReadInt32();
            totalTaskTime = reader.ReadInt32();
        }
        #endregion
    }
    #endregion
 
    #region Wrapper for InitializeNode
    /// <summary>
    /// This class wraps a call to initialize a local node by passing it a new environment and an
    /// nodeid so that it can instantiate a node class.
    /// </summary>
    internal class LocalCallDescriptorForInitializeNode : LocalCallDescriptor
    {
        #region Constructors
        internal LocalCallDescriptorForInitializeNode()
        {
        }
 
        internal LocalCallDescriptorForInitializeNode
        (
            Hashtable environmentVariablesToSend,
            LoggerDescription[] nodeLoggers,
            int nodeId,
            BuildPropertyGroup parentGlobalProperties,
            ToolsetDefinitionLocations toolsetSearchLocations,
            int parentProcessId,
            string parentStartupDirectory
        )
            : base(LocalCallType.InitializeNode)
        {
            this.environmentVariables = environmentVariablesToSend;
            this.parentGlobalProperties = parentGlobalProperties;
            this.toolsetSearchLocations = toolsetSearchLocations;
            this.nodeLoggers = nodeLoggers;
            this.nodeId = nodeId;
            this.parentProcessId = parentProcessId;
            this.parentStartupDirectory = parentStartupDirectory;
        }
        #endregion
 
        #region Methods
        internal override void NodeAction(Node node, LocalNode localNode)
        {
            localNode.Activate(environmentVariables, nodeLoggers, nodeId, parentGlobalProperties,
                               toolsetSearchLocations, parentProcessId, parentStartupDirectory);
        }
        #endregion
 
        #region Data
        private Hashtable environmentVariables;
        private LoggerDescription[] nodeLoggers;
        private int nodeId;
        private BuildPropertyGroup parentGlobalProperties;
        private ToolsetDefinitionLocations toolsetSearchLocations;
        private int parentProcessId;
        private string parentStartupDirectory;
        #endregion
 
        // For testing
        #region Properties
        internal Hashtable EnvironmentVariables
        {
            get
            {
                return environmentVariables;
            }
        }
        internal LoggerDescription[] NodeLoggers
        {
            get
            {
                return nodeLoggers;
            }
        }
        internal int NodeId
        {
            get
            {
                return nodeId;
            }
        }
        internal BuildPropertyGroup ParentGlobalProperties
        {
            get
            {
                return parentGlobalProperties;
            }
        }
        internal ToolsetDefinitionLocations ToolsetSearchLocations
        {
            get
            {
                return toolsetSearchLocations;
            }
        }
        internal int ParentProcessId
        {
            get
            {
                return parentProcessId;
            }
        }
        #endregion
 
        #region CustomSerializationToStream
        internal override void WriteToStream(BinaryWriter writer)
        {
            base.WriteToStream(writer);
            #region EnvironmentVariables
            writer.Write((Int32)environmentVariables.Count);
            foreach (string key in environmentVariables.Keys)
            {
                writer.Write(key);
                writer.Write((string)environmentVariables[key]);
            }
            #endregion
            #region NodeLoggers
            if (nodeLoggers == null)
            {
                writer.Write((byte)0);
            }
            else
            {
                writer.Write((byte)1);
                writer.Write((Int32)nodeLoggers.Length);
                for (int i = 0; i < nodeLoggers.Length; i++)
                {
                    nodeLoggers[i].WriteToStream(writer);
                }
            }
            #endregion
            writer.Write((Int32)nodeId);
            writer.Write((Int32)parentProcessId);
            #region ParentGlobalProperties
            if (parentGlobalProperties == null)
            {
                writer.Write((byte)0);
            }
            else
            {
                writer.Write((byte)1);
                parentGlobalProperties.WriteToStream(writer);
            }
            #endregion
            writer.Write((byte)toolsetSearchLocations);
            writer.Write(parentStartupDirectory);
        }
 
        internal override void CreateFromStream(BinaryReader reader)
        {
            base.CreateFromStream(reader);
            #region EnvironmentVariables
            int numberOfVariables = reader.ReadInt32();
            environmentVariables = new Hashtable(numberOfVariables);
            for (int i = 0; i < numberOfVariables; i++)
            {
                string key = reader.ReadString();
                string variable = reader.ReadString();
                environmentVariables.Add(key, variable);
            }
            #endregion
            #region NodeLoggers
            if (reader.ReadByte() == 0)
            {
                nodeLoggers = null;
            }
            else
            {
                int numberOfLoggers = reader.ReadInt32();
                nodeLoggers = new LoggerDescription[numberOfLoggers];
                for (int i = 0; i < numberOfLoggers; i++)
                {
                    LoggerDescription logger = new LoggerDescription();
                    logger.CreateFromStream(reader);
                    nodeLoggers[i] = logger;
                }
            }
            #endregion
            nodeId = reader.ReadInt32();
            parentProcessId = reader.ReadInt32();
            #region ParentGlobalProperties
            if (reader.ReadByte() == 0)
            {
                parentGlobalProperties = null;
            }
            else
            {
                parentGlobalProperties = new BuildPropertyGroup();
                parentGlobalProperties.CreateFromStream(reader);
            }
            #endregion
            toolsetSearchLocations = (ToolsetDefinitionLocations)reader.ReadByte();
            parentStartupDirectory = (string)reader.ReadString();
        }
        #endregion
    }
    #endregion
 
    #region Wrapper for InitializationComplete
    internal class LocalCallDescriptorForInitializationComplete : LocalCallDescriptor
    {
        #region Constructors
        internal LocalCallDescriptorForInitializationComplete()
        {
        }
 
        internal LocalCallDescriptorForInitializationComplete(int processId)
            : base(LocalCallType.InitializationComplete)
        {
            this.processId = processId;
        }
        #endregion
 
        #region Methods
        internal override void HostAction(IEngineCallback engineCallback, LocalNodeProvider nodeProvider, int nodeId)
        {
            nodeProvider.SetNodeProcessId(processId, nodeId);
        }
        #endregion
 
        #region Data
        private int processId = 0;
        #endregion
 
        //For Testing
        #region Properties
        internal int ProcessId
        {
            get
            {
                return processId;
            }
        }
        #endregion
 
        #region CustomSerializationToStream
        internal override void WriteToStream(BinaryWriter writer)
        {
            base.WriteToStream(writer);
            writer.Write((Int32)processId);
        }
 
        internal override void CreateFromStream(BinaryReader reader)
        {
            base.CreateFromStream(reader);
            processId = reader.ReadInt32();
        }
        #endregion
    }
    #endregion
 
    #region Wrapper for RequestStatus
    internal class LocalCallDescriptorForRequestStatus : LocalCallDescriptor
    {
        #region Constructors
        internal LocalCallDescriptorForRequestStatus()
        {
        }
 
        internal LocalCallDescriptorForRequestStatus(int requestId)
            : base(LocalCallType.RequestStatus)
        {
            this.requestId = requestId;
        }
        #endregion
 
        #region Methods
        internal override void NodeAction(Node node, LocalNode localNode)
        {
            node.RequestStatus(requestId);
        }
        #endregion
 
        #region Data
        private int requestId = 0;
        #endregion
 
        // For testing
        #region Properties
        internal int RequestId
        {
            get
            {
                return requestId;
            }
        }
        #endregion
 
        #region CustomSerializationToStream
        internal override void WriteToStream(BinaryWriter writer)
        {
            base.WriteToStream(writer);
            writer.Write((Int32)requestId);
        }
 
        internal override void CreateFromStream(BinaryReader reader)
        {
            base.CreateFromStream(reader);
            requestId = reader.ReadInt32();
        }
        #endregion
    }
    #endregion
 
    #region Wrapper for PostStatus
    internal class LocalCallDescriptorForPostStatus : LocalCallDescriptor
    {
        #region Constructors
        internal LocalCallDescriptorForPostStatus()
        {
        }
 
        internal LocalCallDescriptorForPostStatus(NodeStatus nodeStatus)
            : base(LocalCallType.PostStatus)
        {
            this.nodeStatus = nodeStatus;
        }
        #endregion
 
        #region Methods
        internal override void HostAction(IEngineCallback engineCallback, LocalNodeProvider nodeProvider, int nodeId)
        {
            engineCallback.PostStatus(nodeId, nodeStatus, false);
        }
        #endregion
 
        #region Data
        private NodeStatus nodeStatus;
        #endregion
 
        // For testing
        #region Properties
        internal NodeStatus StatusOfNode
        {
            get
            {
                return nodeStatus;
            }
        }
        #endregion
 
        #region CustomSerializationToStream
        internal override void WriteToStream(BinaryWriter writer)
        {
            base.WriteToStream(writer);
            if (nodeStatus == null)
            {
                writer.Write((byte)0);
            }
            else
            {
                writer.Write((byte)1);
                nodeStatus.WriteToStream(writer);
            }
        }
 
        internal override void CreateFromStream(BinaryReader reader)
        {
            base.CreateFromStream(reader);
            if (reader.ReadByte() == 0)
            {
                nodeStatus = null;
            }
            else
            {
                nodeStatus = NodeStatus.CreateFromStream(reader);
            }
        }
        #endregion
    }
    #endregion
 
    #region Wrapper for PostIntrospectorCommand
    internal class LocalCallDescriptorForPostIntrospectorCommand : LocalCallDescriptor
    {
        #region Constructors
        internal LocalCallDescriptorForPostIntrospectorCommand(TargetInProgessState child, TargetInProgessState parent)
            : base(LocalCallType.PostIntrospectorCommand)
        {
            this.child = child;
            this.parent = parent;
        }
        #endregion
 
        #region Methods
        internal override void NodeAction(Node node, LocalNode localNode)
        {
            node.Introspector.BreakCycle(child, parent);
        }
        #endregion
 
        #region Data
        private TargetInProgessState child;
        private TargetInProgessState parent;
        #endregion
 
        #region CustomSerializationToStream
        internal override void WriteToStream(BinaryWriter writer)
        {
            base.WriteToStream(writer);
            child.WriteToStream(writer);
            parent.WriteToStream(writer);
        }
 
        internal override void CreateFromStream(BinaryReader reader)
        {
            base.CreateFromStream(reader);
            child = new TargetInProgessState();
            child.CreateFromStream(reader);
            parent = new TargetInProgessState();
            parent.CreateFromStream(reader);
        }
        #endregion
    }
    #endregion
 
    #region Wrapper for PostCacheEntriesToHost
    internal class LocalCallDescriptorForPostingCacheEntriesToHost : LocalCallDescriptor
    {
        #region Constructors
        internal LocalCallDescriptorForPostingCacheEntriesToHost()
        {
        }
 
        internal LocalCallDescriptorForPostingCacheEntriesToHost(CacheEntry[] entries, string scopeName, BuildPropertyGroup scopeProperties, string scopeToolsVersion, CacheContentType cacheContentType)
            : base(LocalCallType.PostCacheEntriesToHost)
        {
            this.entries = entries;
            this.scopeName = scopeName;
            this.scopeProperties = scopeProperties;
            this.scopeToolsVersion = scopeToolsVersion;
            this.cacheContentType = cacheContentType;
            this.exception = null;
        }
        #endregion
 
        // For testing
        #region Properties
        internal override bool NeedsReply
        {
            get
            {
                return true;
            }
        }
 
        internal CacheEntry[] Entries
        {
            get
            {
                return entries;
            }
        }
        internal string ScopeName
        {
            get
            {
                return scopeName;
            }
        }
        internal CacheContentType ContentType
        {
            get
            {
                return cacheContentType;
            }
        }
        internal BuildPropertyGroup ScopeProperties
        {
            get
            {
                return scopeProperties;
            }
        }
        internal string ScopeToolsVersion
        {
            get
            {
                return scopeToolsVersion;
            }
        }
        #endregion
 
        #region Methods
        internal override void HostAction(IEngineCallback engineCallback, LocalNodeProvider nodeProvider, int nodeId)
        {
            exception = engineCallback.PostCacheEntriesToHost(nodeId, this.entries, this.scopeName, this.scopeProperties, this.scopeToolsVersion, this.cacheContentType);
        }
 
        internal override LocalReplyCallDescriptor ReplyFromHostAction()
        {
            return new LocalReplyCallDescriptor(this.CallNumber, this.exception);
        }
        #endregion
 
        #region Data
        private CacheEntry[] entries;
        private string scopeName;
        private string scopeToolsVersion;
        private BuildPropertyGroup scopeProperties;
        private CacheContentType cacheContentType;
        private Exception exception;
        #endregion
 
        #region CustomSerializationToStream
        internal override void WriteToStream(BinaryWriter writer)
        {
            base.WriteToStream(writer);
            #region Entries
            if (entries == null)
            {
                writer.Write((byte)0);
            }
            else
            {
                writer.Write((byte)1);
                writer.Write((Int32)entries.Length);
                for (int i = 0; i < entries.Length; i++)
                {
                    CacheEntryCustomSerializer.WriteToStream(entries[i], writer);
                }
            }
            #endregion
            #region ScopeName
            if (scopeName == null)
            {
                writer.Write((byte)0);
            }
            else
            {
                writer.Write((byte)1);
                writer.Write(scopeName);
            }
            #endregion
            #region ScopeProperties
            if (scopeProperties == null)
            {
                writer.Write((byte)0);
            }
            else
            {
                writer.Write((byte)1);
                scopeProperties.WriteToStream(writer);
            }
            #endregion
            #region ScopeToolsVersion
            if (scopeToolsVersion == null)
            {
                writer.Write((byte)0);
            }
            else
            {
                writer.Write((byte)1);
                writer.Write(scopeToolsVersion);
            }
            #endregion
            writer.Write((byte)cacheContentType);
        }
 
        internal override void CreateFromStream(BinaryReader reader)
        {
            base.CreateFromStream(reader);
            #region Entries
            if (reader.ReadByte() == 0)
            {
                entries = null;
            }
            else
            {
                int numberOfEntries = reader.ReadInt32();
                entries = new CacheEntry[numberOfEntries];
                for (int i = 0; i < entries.Length; i++)
                {
                    entries[i] = CacheEntryCustomSerializer.CreateFromStream(reader);
                }
            }
            #endregion
            #region ScopeName
            if (reader.ReadByte() == 0)
            {
                scopeName = null;
            }
            else
            {
                scopeName = reader.ReadString();
            }
            #endregion
            #region ScopeProperties
            if (reader.ReadByte() == 0)
            {
                scopeProperties = null;
            }
            else
            {
                scopeProperties = new BuildPropertyGroup();
                scopeProperties.CreateFromStream(reader);
            }
            #endregion
            #region ScopeToolsVersion
            if (reader.ReadByte() == 0)
            {
                scopeToolsVersion = null;
            }
            else
            {
                scopeToolsVersion = reader.ReadString();
            }
            #endregion
            cacheContentType = (CacheContentType)reader.ReadByte();
        }
        #endregion
    }
    #endregion
 
    #region Wrapper for GetCacheEntriesFromHost
    internal class LocalCallDescriptorForGettingCacheEntriesFromHost : LocalCallDescriptor
    {
        #region Constructors
        internal LocalCallDescriptorForGettingCacheEntriesFromHost()
        {
        }
 
        internal LocalCallDescriptorForGettingCacheEntriesFromHost(string[] names, string scopeName, BuildPropertyGroup scopeProperties, string scopeToolsVersion, CacheContentType cacheContentType)
            : base(LocalCallType.GetCacheEntriesFromHost)
        {
            this.names = names;
            this.scopeName = scopeName;
            this.scopeProperties = scopeProperties;
            this.scopeToolsVersion = scopeToolsVersion;
            this.cacheContentType = cacheContentType;
        }
        #endregion
 
        // For testing
        #region Properties
        internal override bool NeedsReply
        {
            get
            {
                return true;
            }
        }
        internal string[] Names
        {
            get
            {
                return names;
            }
        }
        internal string ScopeName
        {
            get
            {
                return scopeName;
            }
        }
 
        internal BuildPropertyGroup ScopeProperties
        {
            get
            {
                return scopeProperties;
            }
        }
 
        internal CacheContentType ContentType
        {
            get
            {
                return cacheContentType;
            }
        }
 
        internal string ScopeToolsVersion
        {
            get
            {
                return scopeToolsVersion;
            }
        }
 
        #endregion
 
        #region Methods
        internal override void HostAction(IEngineCallback engineCallback, LocalNodeProvider nodeProvider, int nodeId)
        {
            entries = engineCallback.GetCachedEntriesFromHost(nodeId, this.names, this.scopeName, this.scopeProperties, this.scopeToolsVersion, this.cacheContentType);
        }
 
        internal override LocalReplyCallDescriptor ReplyFromHostAction()
        {
            return new LocalReplyCallDescriptor(this.CallNumber, this.entries);
        }
        #endregion
 
        #region Data
        private string[] names;
        private string scopeName;
        private string scopeToolsVersion;
        private BuildPropertyGroup scopeProperties;
        private CacheContentType cacheContentType;
        // The actual reply value is only serialized in the reply call descriptor, no need to serialize it here.
        private CacheEntry[] entries;
        #endregion
 
        #region CustomSerializationToStream
        internal override void WriteToStream(BinaryWriter writer)
        {
            base.WriteToStream(writer);
            #region Names
            if (names == null)
            {
                writer.Write((byte)0);
            }
            else
            {
                writer.Write((byte)1);
                writer.Write((Int32)names.Length);
                for (int i = 0; i < names.Length; i++)
                {
                    if (names[i] == null)
                    {
                        writer.Write((byte)0);
                    }
                    else
                    {
                        writer.Write((byte)1);
                        writer.Write(names[i]);
                    }
                }
            }
            #endregion
            #region ScopeName
            if (scopeName == null)
            {
                writer.Write((byte)0);
            }
            else
            {
                writer.Write((byte)1);
                writer.Write(scopeName);
            }
            #endregion
            #region ScopeProperties
            if (scopeProperties == null)
            {
                writer.Write((byte)0);
            }
            else
            {
                writer.Write((byte)1);
                scopeProperties.WriteToStream(writer);
            }
            #endregion
            #region ScopeToolsVersion
            if (scopeToolsVersion == null)
            {
                writer.Write((byte)0);
            }
            else
            {
                writer.Write((byte)1);
                writer.Write(scopeToolsVersion);
            }
            #endregion
            writer.Write((byte)cacheContentType);
        }
        internal override void CreateFromStream(BinaryReader reader)
        {
            base.CreateFromStream(reader);
            #region Names
            if (reader.ReadByte() == 0)
            {
                names = null;
            }
            else
            {
                int numberOfEntries = reader.ReadInt32();
                names = new string[numberOfEntries];
                for (int i = 0; i < names.Length; i++)
                {
                    if (reader.ReadByte() != 0)
                    {
                        names[i] = reader.ReadString();
                    }
                    else
                    {
                        names[i] = null;
                    }
                }
            }
            #endregion
            #region ScopeName
            if (reader.ReadByte() == 0)
            {
                scopeName = null;
            }
            else
            {
                scopeName = reader.ReadString();
            }
            #endregion
            #region ScopeProperties
            if (reader.ReadByte() == 0)
            {
                scopeProperties = null;
            }
            else
            {
                scopeProperties = new BuildPropertyGroup();
                scopeProperties.CreateFromStream(reader);
            }
            #endregion
            #region ScopeToolsVersion
            if (reader.ReadByte() == 0)
            {
                scopeToolsVersion = null;
            }
            else
            {
                scopeToolsVersion = reader.ReadString();
            }
            #endregion
            cacheContentType = (CacheContentType)reader.ReadByte();
        }
        #endregion
 
    }
    #endregion
 
    #region Enums
 
    /// <summary>
    /// This enum describes the call types used in the local node provider
    /// </summary>
    internal enum LocalCallType
    {
        /// <summary>
        /// This call type corresponds to an array of build requests
        /// </summary>
        PostBuildRequests = 0,
        /// <summary>
        /// This call type corresponds to a single build result
        /// </summary>
        PostBuildResult = 1,
        /// <summary>
        /// This call type corresponds to an array of messages
        /// from which messages originated
        /// </summary>
        PostLoggingMessagesToHost = 2,
        /// <summary>
        /// Call type to update the settings one the node
        /// </summary>
        UpdateNodeSettings = 3,
        /// <summary>
        /// Call type for request status from the node
        /// </summary>
        RequestStatus = 4,
        /// <summary>
        /// Call type for request status from the node
        /// </summary>
        PostStatus = 5,
        /// <summary>
        /// Call type for initializing the node
        /// </summary>
        InitializeNode = 6,
        /// <summary>
        /// Call type for the node to indicate that it has initialized successfully
        /// </summary>
        InitializationComplete = 7,
        /// <summary>
        /// Call type for shutting down the node
        /// </summary>
        ShutdownNode = 8,
        /// <summary>
        /// Call type for the node to indicate that it has shutdown
        /// </summary>
        ShutdownComplete = 9,
        /// <summary>
        /// Call type to post an introspector command
        /// </summary>
        PostIntrospectorCommand = 10,
        /// <summary>
        /// This call type corresponds to a single string send from parent to child
        /// </summary>
        GenericSingleObjectReply = 11,
        /// <summary>
        /// Call type for posting cache entries to a node
        /// </summary>
        PostCacheEntriesToHost = 12,
        /// <summary>
        /// Call type for retrieving cache entries from a node
        /// </summary>
        GetCacheEntriesFromHost = 13
    }
    #endregion
}