public virtual void HistoryRead(
OperationContext context,
ExtensionObject historyReadDetails,
TimestampsToReturn timestampsToReturn,
bool releaseContinuationPoints,
HistoryReadValueIdCollection nodesToRead,
out HistoryReadResultCollection results,
out DiagnosticInfoCollection diagnosticInfos)
{
// validate history details parameter.
if (ExtensionObject.IsNull(historyReadDetails))
{
throw new ServiceResultException(StatusCodes.BadHistoryOperationInvalid);
}
HistoryReadDetails details = historyReadDetails.Body as HistoryReadDetails;
if (details == null)
{
throw new ServiceResultException(StatusCodes.BadHistoryOperationUnsupported);
}
// create result lists.
bool diagnosticsExist = false;
results = new HistoryReadResultCollection(nodesToRead.Count);
diagnosticInfos = new DiagnosticInfoCollection(nodesToRead.Count);
// pre-validate items.
bool validItems = false;
for (int ii = 0; ii < nodesToRead.Count; ii++)
{
HistoryReadResult result = null;
DiagnosticInfo diagnosticInfo = null;
// pre-validate and pre-parse parameter.
ServiceResult error = HistoryReadValueId.Validate(nodesToRead[ii]);
// return error status.
if (ServiceResult.IsBad(error))
{
nodesToRead[ii].Processed = true;
result = new HistoryReadResult();
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
{
nodesToRead[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 < nodesToRead.Count; ii++)
{
errors.Add(null);
}
foreach (INodeManager nodeManager in m_nodeManagers)
{
nodeManager.HistoryRead(
context,
details,
timestampsToReturn,
releaseContinuationPoints,
nodesToRead,
results,
errors);
}
for (int ii = 0; ii < nodesToRead.Count; ii++)
{
HistoryReadResult result = results[ii];
// set an error code for nodes that were not handled by any node manager.
if (!nodesToRead[ii].Processed)
{
nodesToRead[ii].Processed = true;
result = results[ii] = new HistoryReadResult();
result.StatusCode = StatusCodes.BadNodeIdUnknown;
errors[ii] = results[ii].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 HistoryReadResult();
}
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);
}