protected List <RFCatalogKey> SaveDomain(RFGraphProcessorDomain domain, IRFProcessingContext context)
        {
            var updates    = new List <RFCatalogKey>();
            var domainType = domain.GetType();
            int numUpdates = 0;

            foreach (var propertyInfo in domainType.GetProperties())
            {
                var ioBehaviour = propertyInfo.GetCustomAttributes(typeof(RFIOBehaviourAttribute), true).FirstOrDefault() as RFIOBehaviourAttribute;
                if (ioBehaviour != null && (ioBehaviour.IOBehaviour == RFIOBehaviour.Output || ioBehaviour.IOBehaviour == RFIOBehaviour.State))
                {
                    var value = propertyInfo.GetValue(domain);
                    if (value != null)
                    {
                        foreach (var outputMapping in Config.IOMappings.Where(m => m.Property.Name == propertyInfo.Name))
                        {
                            var outputKey = outputMapping.Key.CreateForInstance(this.GraphInstance);
                            var options   = RFGraphInstance.ImplyOptions(outputMapping);
                            // by default date will be set from the graph instance
                            if (options.DateBehaviour == RFDateBehaviour.Dateless)
                            {
                                outputKey.GraphInstance.ValueDate = null;
                            }
                            bool isState    = (ioBehaviour.IOBehaviour == RFIOBehaviour.State);
                            var  hasUpdated = context.SaveEntry(new RFDocument
                            {
                                Content = value,
                                Key     = outputKey,
                                Type    = value.GetType().FullName
                            }, !isState);
                            if (hasUpdated)
                            {
                                updates.Add(outputKey);
                                numUpdates++;
                            }
                        }
                    }
                }
            }
            return(updates);
        }
        protected RFGraphProcessorDomain LoadDomain(IRFGraphProcessorInstance processor, IRFProcessingContext context, ref SortedSet <string> missingInputs)
        {
            var domain = processor.CreateDomain();

            domain.Instance = GraphInstance;
            var domainType = domain.GetType();

            var missingNames = new ConcurrentBag <string>();

            try
            {
                foreach (var propertyInfo in domainType.GetProperties())
                {
                    var ioBehaviour = propertyInfo.GetCustomAttributes(typeof(RFIOBehaviourAttribute), true).FirstOrDefault() as RFIOBehaviourAttribute;
                    if (ioBehaviour != null && (ioBehaviour.IOBehaviour == RFIOBehaviour.Input || ioBehaviour.IOBehaviour == RFIOBehaviour.State))
                    {
                        var inputMapping = Config.IOMappings.SingleOrDefault(m => m.Property.Name == propertyInfo.Name);
                        if (inputMapping != null)
                        {
                            var options = RFGraphInstance.ImplyOptions(inputMapping);
                            if (options.DateBehaviour == RFDateBehaviour.Range)
                            {
                                if (inputMapping.RangeRequestFunc == null)
                                {
                                    if (ioBehaviour.IsMandatory)
                                    {
                                        Context.SystemLog.Warning(this, "No range specified for mandatory ranged input {0} on process {1}", propertyInfo.FullName(), this.ProcessName);
                                    }
                                    continue;
                                }
                                var dateRange = inputMapping.RangeRequestFunc(GraphInstance);
                                options.DateBehaviour = RFDateBehaviour.Exact; // override to load one-by-one

                                var rangeInput = Activator.CreateInstance(propertyInfo.PropertyType) as IRFRangeInput;
                                foreach (var vd in dateRange)
                                {
                                    var inputKey = inputMapping.Key.CreateForInstance(GraphInstance.WithDate(vd));

                                    var item = context.LoadEntry(inputKey, options);
                                    if (item != null && item is RFDocument)
                                    {
                                        var content = (item as RFDocument).Content;
                                        if (content != null)
                                        {
                                            rangeInput.Add(vd, content);
                                        }
                                    }
                                }

                                try
                                {
                                    if (propertyInfo.PropertyType.IsAssignableFrom(rangeInput.GetType()))
                                    {
                                        propertyInfo.SetValue(domain, rangeInput);
                                    }
                                    else
                                    {
                                        Context.SystemLog.Warning(this, "Not assigning value of type {0} to property {1} of type {2} due to type mismatch [{3}]", rangeInput.GetType().FullName,
                                                                  propertyInfo.FullName(), propertyInfo.PropertyType.FullName, domain.Instance?.ValueDate);
                                    }
                                }
                                catch (Exception)
                                {
                                    Context.SystemLog.Info(this, "Domain mismatch on property {0} for vd {1} - stale data?", propertyInfo.FullName(), domain.Instance.ValueDate);
                                }
                            }
                            else
                            {
                                var inputKey = inputMapping.Key.CreateForInstance(GraphInstance);
                                var item     = context.LoadEntry(inputKey, options);
                                if (item != null && item is RFDocument)
                                {
                                    try
                                    {
                                        var content = (item as RFDocument).Content;
                                        if (content != null)
                                        {
                                            if (propertyInfo.PropertyType.IsAssignableFrom(content.GetType()))
                                            {
                                                propertyInfo.SetValue(domain, content);
                                            }
                                            else
                                            {
                                                Context.SystemLog.Warning(this, "Not assigning value of type {0} to property {1} of type {2} due to type mismatch [{3}]", content.GetType().FullName,
                                                                          propertyInfo.FullName(), propertyInfo.PropertyType.FullName, domain.Instance?.ValueDate);
                                            }
                                        }
                                    }
                                    catch (Exception)
                                    {
                                        Context.SystemLog.Info(this, "Domain mismatch on property {0} for vd {1} - stale data?", propertyInfo.FullName(), domain.Instance.ValueDate);
                                    }
                                }
                                else if (ioBehaviour.IsMandatory)
                                {
                                    missingNames.Add(propertyInfo.Name);
                                    // return null;// performance short circuit - only report one missing
                                }
                            }
                        }
                    }
                }
                missingInputs.UnionWith(missingNames);
                if (missingInputs.Count > 0)
                {
                    return(null);
                }
                return(domain);
            }
            catch (Exception ex)
            {
                Context.SystemLog.Exception(this, "Error loading domain", ex);
                return(null);
            }
        }