public void CreateMonitoredItems(
OperationContext context,
uint subscriptionId,
double publishingInterval,
TimestampsToReturn timestampsToReturn,
IList<MonitoredItemCreateRequest> itemsToCreate,
IList<ServiceResult> errors,
IList<MonitoringFilterResult> filterErrors,
IList<IMonitoredItem> monitoredItems,
ref long globalIdCounter)
{
if (context == null) throw new ArgumentNullException("context");
if (itemsToCreate == null) throw new ArgumentNullException("itemsToCreate");
if (errors == null) throw new ArgumentNullException("errors");
if (monitoredItems == null) throw new ArgumentNullException("monitoredItems");
try
{
m_lock.Enter();
for (int ii = 0; ii < errors.Count; ii++)
{
MonitoredItemCreateRequest itemToCreate = itemsToCreate[ii];
// skip items that have already been processed.
if (itemToCreate.Processed)
{
continue;
}
// look up the node.
ILocalNode node = this.GetLocalNode(itemToCreate.ItemToMonitor.NodeId) as ILocalNode;
if (node == null)
{
continue;
}
// owned by this node manager.
itemToCreate.Processed = true;
if (!node.SupportsAttribute(itemToCreate.ItemToMonitor.AttributeId))
{
errors[ii] = StatusCodes.BadAttributeIdInvalid;
continue;
}
// fetch the metadata for the node.
NodeMetadata metadata = GetNodeMetadata(context, node, BrowseResultMask.All);
if (itemToCreate.ItemToMonitor.AttributeId == Attributes.Value)
{
if ((metadata.AccessLevel & AccessLevels.CurrentRead) == 0)
{
errors[ii] = StatusCodes.BadNotReadable;
continue;
}
}
// check value rank against index range.
if (itemToCreate.ItemToMonitor.ParsedIndexRange != NumericRange.Empty)
{
int valueRank = metadata.ValueRank;
if (itemToCreate.ItemToMonitor.AttributeId != Attributes.Value)
{
valueRank = Attributes.GetValueRank(itemToCreate.ItemToMonitor.AttributeId);
}
if (valueRank == ValueRanks.Scalar)
{
errors[ii] = StatusCodes.BadIndexRangeInvalid;
continue;
}
}
bool rangeRequired = false;
// validate the filter against the node/attribute being monitored.
errors[ii] = ValidateFilter(
metadata,
itemToCreate.ItemToMonitor.AttributeId,
itemToCreate.RequestedParameters.Filter,
out rangeRequired);
if (ServiceResult.IsBad(errors[ii]))
{
continue;
}
// lookup EU range if required.
Range range = null;
if (rangeRequired)
{
errors[ii] = ReadEURange(context, node, out range);
if (ServiceResult.IsBad(errors[ii]))
{
continue;
}
}
// create a globally unique identifier.
uint monitoredItemId = Utils.IncrementIdentifier(ref globalIdCounter);
// limit the sampling rate for non-value attributes.
double minimumSamplingInterval = m_defaultMinimumSamplingInterval;
if (itemToCreate.ItemToMonitor.AttributeId == Attributes.Value)
{
// use the MinimumSamplingInterval attribute to limit the sampling rate for value attributes.
IVariable variableNode = node as IVariable;
if (variableNode != null)
{
minimumSamplingInterval = variableNode.MinimumSamplingInterval;
// use the default if the node does not specify one.
if (minimumSamplingInterval < 0)
{
minimumSamplingInterval = m_defaultMinimumSamplingInterval;
}
}
}
// create monitored item.
MonitoredItem monitoredItem = m_samplingGroupManager.CreateMonitoredItem(
context,
subscriptionId,
publishingInterval,
timestampsToReturn,
monitoredItemId,
node,
itemToCreate,
range,
minimumSamplingInterval);
// save monitored item.
m_monitoredItems.Add(monitoredItem.Id, monitoredItem);
// update monitored item list.
monitoredItems[ii] = monitoredItem;
#if LEGACY_CORENODEMANAGER
// subscribe to the variable
if (minimumSamplingInterval == 0)
{
VariableSource variable = node as VariableSource;
if (variable != null)
{
variable.Subscribe(monitoredItem);
}
}
#endif
// read the initial value.
DataValue initialValue = new DataValue();
initialValue.ServerTimestamp = DateTime.UtcNow;
initialValue.StatusCode = StatusCodes.BadWaitingForInitialData;
ServiceResult error = node.Read(context, itemToCreate.ItemToMonitor.AttributeId, initialValue);
if (ServiceResult.IsBad(error))
{
initialValue.Value = null;
initialValue.StatusCode = error.StatusCode;
}
monitoredItem.QueueValue(initialValue, error);
// errors updating the monitoring groups will be reported in notifications.
errors[ii] = StatusCodes.Good;
}
}
finally
{
m_lock.Exit();
}
// update all groups with any new items.
m_samplingGroupManager.ApplyChanges();
}