public virtual void Read(
OperationContext context,
double maxAge,
TimestampsToReturn timestampsToReturn,
ReadValueIdCollection nodesToRead,
out DataValueCollection values,
out DiagnosticInfoCollection diagnosticInfos)
{
if (nodesToRead == null) throw new ArgumentNullException("nodesToRead");
if (maxAge < 0)
{
throw new ServiceResultException(StatusCodes.BadMaxAgeInvalid);
}
if (timestampsToReturn < TimestampsToReturn.Source || timestampsToReturn > TimestampsToReturn.Neither)
{
throw new ServiceResultException(StatusCodes.BadTimestampsToReturnInvalid);
}
bool diagnosticsExist = false;
values = new DataValueCollection(nodesToRead.Count);
diagnosticInfos = new DiagnosticInfoCollection(nodesToRead.Count);
// create empty list of errors.
List<ServiceResult> errors = new List<ServiceResult>(values.Count);
for (int ii = 0; ii < nodesToRead.Count; ii++)
{
errors.Add(null);
}
// add placeholder for each result.
bool validItems = false;
Utils.Trace(
(int)Utils.TraceMasks.ServiceDetail,
"MasterNodeManager.Read - Count={0}",
nodesToRead.Count);
for (int ii = 0; ii < nodesToRead.Count; ii++)
{
DataValue value = null;
DiagnosticInfo diagnosticInfo = null;
// pre-validate and pre-parse parameter.
errors[ii] = ReadValueId.Validate(nodesToRead[ii]);
// return error status.
if (ServiceResult.IsBad(errors[ii]))
{
nodesToRead[ii].Processed = true;
}
// found at least one valid item.
else
{
nodesToRead[ii].Processed = false;
validItems = true;
}
values.Add(value);
diagnosticInfos.Add(diagnosticInfo);
}
// call each node manager.
if (validItems)
{
for (int ii = 0; ii < m_nodeManagers.Count; ii++)
{
Utils.Trace(
(int)Utils.TraceMasks.ServiceDetail,
"MasterNodeManager.Read - Calling NodeManager {0} of {1}",
ii,
m_nodeManagers.Count);
m_nodeManagers[ii].Read(
context,
maxAge,
nodesToRead,
values,
errors);
}
}
// process results.
for (int ii = 0; ii < nodesToRead.Count; ii++)
{
DataValue value = values[ii];
// set an error code for nodes that were not handled by any node manager.
if (!nodesToRead[ii].Processed)
{
value = values[ii] = new DataValue(StatusCodes.BadNodeIdUnknown, DateTime.UtcNow);
errors[ii] = new ServiceResult(values[ii].StatusCode);
}
// update the diagnostic info and ensure the status code in the data value is the same as the error code.
if (errors[ii] != null && errors[ii].Code != StatusCodes.Good)
{
if (value == null)
{
value = values[ii] = new DataValue(errors[ii].Code, DateTime.UtcNow);
}
value.StatusCode = errors[ii].Code;
if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0)
{
diagnosticInfos[ii] = ServerUtils.CreateDiagnosticInfo(m_server, context, errors[ii]);
diagnosticsExist = true;
}
}
// apply the timestamp filters.
if (timestampsToReturn != TimestampsToReturn.Server && timestampsToReturn != TimestampsToReturn.Both)
{
value.ServerTimestamp = DateTime.MinValue;
}
if (timestampsToReturn != TimestampsToReturn.Source && timestampsToReturn != TimestampsToReturn.Both)
{
value.SourceTimestamp = DateTime.MinValue;
}
}
// clear the diagnostics array if no diagnostics requested or no errors occurred.
UpdateDiagnostics(context, diagnosticsExist, ref diagnosticInfos);
}