public virtual void HistoryUpdate(
OperationContext context,
ExtensionObjectCollection historyUpdateDetails,
out HistoryUpdateResultCollection results,
out DiagnosticInfoCollection diagnosticInfos)
{
Type detailsType = null;
List<HistoryUpdateDetails> nodesToUpdate = new List<HistoryUpdateDetails>();
// verify that all extension objects in the list have the same type.
foreach (ExtensionObject details in historyUpdateDetails)
{
if (detailsType == null)
{
detailsType = details.Body.GetType();
}
if (!ExtensionObject.IsNull(details))
{
nodesToUpdate.Add(details.Body as HistoryUpdateDetails);
}
}
// create result lists.
bool diagnosticsExist = false;
results = new HistoryUpdateResultCollection(nodesToUpdate.Count);
diagnosticInfos = new DiagnosticInfoCollection(nodesToUpdate.Count);
// pre-validate items.
bool validItems = false;
for (int ii = 0; ii < nodesToUpdate.Count; ii++)
{
HistoryUpdateResult result = null;
DiagnosticInfo diagnosticInfo = null;
// check the type of details parameter.
ServiceResult error = null;
if (nodesToUpdate[ii].GetType() != detailsType)
{
error = StatusCodes.BadHistoryOperationInvalid;
}
// pre-validate and pre-parse parameter.
else
{
error = HistoryUpdateDetails.Validate(nodesToUpdate[ii]);
}
// return error status.
if (ServiceResult.IsBad(error))
{
nodesToUpdate[ii].Processed = true;
result = new HistoryUpdateResult();
result.StatusCode = error.Code;
// add diagnostics if requested.
if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0)
{
diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, error);
diagnosticsExist = true;
}
}
// found at least one valid item.
else
{
nodesToUpdate[ii].Processed = false;
validItems = true;
}
results.Add(result);
diagnosticInfos.Add(diagnosticInfo);
}
// call each node manager.
if (validItems)
{
List<ServiceResult> errors = new List<ServiceResult>(results.Count);
for (int ii = 0; ii < nodesToUpdate.Count; ii++)
{
errors.Add(null);
}
foreach (INodeManager nodeManager in m_nodeManagers)
{
nodeManager.HistoryUpdate(
context,
detailsType,
nodesToUpdate,
results,
errors);
}
for (int ii = 0; ii < nodesToUpdate.Count; ii++)
{
HistoryUpdateResult result = results[ii];
// set an error code for nodes that were not handled by any node manager.
if (!nodesToUpdate[ii].Processed)
{
nodesToUpdate[ii].Processed = true;
result = results[ii] = new HistoryUpdateResult();
result.StatusCode = StatusCodes.BadNodeIdUnknown;
errors[ii] = result.StatusCode;
}
// update the diagnostic info and ensure the status code in the result is the same as the error code.
if (errors[ii] != null && errors[ii].Code != StatusCodes.Good)
{
if (result == null)
{
result = results[ii] = new HistoryUpdateResult();
}
result.StatusCode = errors[ii].Code;
// add diagnostics if requested.
if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0)
{
diagnosticInfos[ii] = ServerUtils.CreateDiagnosticInfo(m_server, context, errors[ii]);
diagnosticsExist = true;
}
}
}
}
// clear the diagnostics array if no diagnostics requested or no errors occurred.
UpdateDiagnostics(context, diagnosticsExist, ref diagnosticInfos);
}