public void Read(
OperationContext context,
double maxAge,
IList<ReadValueId> nodesToRead,
IList<DataValue> values,
IList<ServiceResult> errors)
{
if (context == null) throw new ArgumentNullException("context");
if (nodesToRead == null) throw new ArgumentNullException("nodesToRead");
if (values == null) throw new ArgumentNullException("values");
if (errors == null) throw new ArgumentNullException("errors");
#if LEGACY_CORENODEMANAGER
Dictionary<IReadDataSource,List<RequestHandle>> datasources = new Dictionary<IReadDataSource,List<RequestHandle>>();
#endif
try
{
m_lock.Enter();
for (int ii = 0; ii < nodesToRead.Count; ii++)
{
ReadValueId nodeToRead = nodesToRead[ii];
// skip items that have already been processed.
if (nodeToRead.Processed)
{
continue;
}
// look up the node.
ILocalNode node = GetLocalNode(nodeToRead.NodeId) as ILocalNode;
if (node == null)
{
continue;
}
DataValue value = values[ii] = new DataValue();
value.Value = null;
value.ServerTimestamp = DateTime.UtcNow;
value.SourceTimestamp = DateTime.MinValue;
value.StatusCode = StatusCodes.BadAttributeIdInvalid;
// owned by this node manager.
nodeToRead.Processed = true;
// read the default value (also verifies that the attribute id is valid for the node).
ServiceResult error = node.Read(context, nodeToRead.AttributeId, value);
if (ServiceResult.IsBad(error))
{
errors[ii] = error;
continue;
}
// always use default value for base attributes.
bool useDefault = false;
switch (nodeToRead.AttributeId)
{
case Attributes.NodeId:
case Attributes.NodeClass:
case Attributes.BrowseName:
{
useDefault = true;
break;
}
}
if (useDefault)
{
errors[ii] = error;
continue;
}
#if LEGACY_CORENODEMANAGER
// check if an external data source needs to be called.
if (CheckSourceHandle(node, typeof(IReadDataSource), ii, datasources))
{
continue;
}
// use default value if no datasource found.
#endif
// apply index range to value attributes.
if (nodeToRead.AttributeId == Attributes.Value)
{
object defaultValue = value.Value;
error = nodeToRead.ParsedIndexRange.ApplyRange(ref defaultValue);
if (ServiceResult.IsBad(error))
{
value.Value = null;
errors[ii] = error;
continue;
}
// apply data encoding.
if (!QualifiedName.IsNull(nodeToRead.DataEncoding))
{
error = EncodeableObject.ApplyDataEncoding(Server.MessageContext, nodeToRead.DataEncoding, ref defaultValue);
if (ServiceResult.IsBad(error))
{
value.Value = null;
errors[ii] = error;
continue;
}
}
value.Value = defaultValue;
// don't replace timestamp if it was set in the NodeSource
if (value.SourceTimestamp == DateTime.MinValue)
{
value.SourceTimestamp = DateTime.UtcNow;
}
}
}
#if LEGACY_CORENODEMANAGER
// check if nothing more to do.
if (datasources.Count == 0)
{
return;
}
#endif
}
finally
{
m_lock.Exit();
}
#if LEGACY_CORENODEMANAGER
// call the datasources.
foreach (KeyValuePair<IReadDataSource,List<RequestHandle>> entry in datasources)
{
try
{
entry.Key.Read(
context,
maxAge,
entry.Value,
nodesToRead,
values,
errors);
}
catch (Exception e)
{
ServiceResult error = ServiceResult.Create(e, StatusCodes.BadUnexpectedError, "Unexpected error while calling the IDatasource for the Node.");
foreach (RequestHandle handle in entry.Value)
{
errors[handle.Index] = error;
}
}
}
#endif
}