Opc.Ua.Server.CoreNodeManager.Write C# (CSharp) Method

Write() private method

private Write ( OperationContext context, IList nodesToWrite, IList errors ) : void
context OperationContext
nodesToWrite IList
errors IList
return void
        public void Write(
            OperationContext     context,
            IList<WriteValue>    nodesToWrite, 
            IList<ServiceResult> errors)
        {
            if (context == null)      throw new ArgumentNullException("context");
            if (nodesToWrite == null) throw new ArgumentNullException("nodesToWrite");
            if (errors == null)       throw new ArgumentNullException("errors");
            
            #if LEGACY_CORENODEMANAGER 
            Dictionary<NodeId,ILocalNode> nodes = new Dictionary<NodeId,ILocalNode>();
            Dictionary<IWriteDataSource,List<RequestHandle>> datasources = new Dictionary<IWriteDataSource,List<RequestHandle>>();
            #endif
            
            try
            {
                m_lock.Enter();

                for (int ii = 0; ii < nodesToWrite.Count; ii++)
                {
                    WriteValue nodeToWrite = nodesToWrite[ii];

                    // skip items that have already been processed.
                    if (nodeToWrite.Processed)
                    {
                        continue;
                    }
                    
                    // look up the node.
                    ILocalNode node = GetLocalNode(nodeToWrite.NodeId) as ILocalNode;

                    if (node == null)
                    {
                        continue;
                    }
                    
                    // owned by this node manager.
                    nodeToWrite.Processed = true;

                    if (!node.SupportsAttribute(nodeToWrite.AttributeId))
                    {
                        errors[ii] = StatusCodes.BadAttributeIdInvalid;
                        continue;
                    }
                    
                    // fetch the node metadata.
                    NodeMetadata metadata = GetNodeMetadata(context, node, BrowseResultMask.All);
                    
                    // check access.
                    bool writeable = true;
                    ServiceResult error = null;

                    // determine access rights.
                    switch (nodeToWrite.AttributeId)
                    {
                        case Attributes.NodeId:
                        case Attributes.NodeClass:
                        case Attributes.AccessLevel:
                        case Attributes.UserAccessLevel:
                        case Attributes.Executable:
                        case Attributes.UserExecutable:
                        case Attributes.EventNotifier:
                        {
                            writeable = false;
                            break;
                        }

                        case Attributes.Value:
                        {
                            writeable = ((metadata.AccessLevel & AccessLevels.CurrentWrite)!= 0);
                            break;
                        }

                        default:
                        {
                            writeable = (metadata.WriteMask & Attributes.GetMask(nodeToWrite.AttributeId)) != 0;
                            break;
                        }
                    }

                    // error if not writeable.
                    if (!writeable)
                    {
                        errors[ii] = StatusCodes.BadNotWritable;
                        continue;
                    }

                    // determine expected datatype and value rank.
                    NodeId expectedDatatypeId = metadata.DataType;
                    int expectedValueRank = metadata.ValueRank;
                    
                    if (nodeToWrite.AttributeId != Attributes.Value)
                    {
                        expectedDatatypeId = Attributes.GetDataTypeId(nodeToWrite.AttributeId);

                        DataValue value = nodeToWrite.Value;

                        if (value.StatusCode != StatusCodes.Good || value.ServerTimestamp != DateTime.MinValue || value.SourceTimestamp != DateTime.MinValue)
                        {
                            errors[ii] = StatusCodes.BadWriteNotSupported;
                            continue;
                        }

                        expectedValueRank = ValueRanks.Scalar;

                        if (nodeToWrite.AttributeId == Attributes.ArrayDimensions)
                        {
                            expectedValueRank = ValueRanks.OneDimension;
                        }
                    }

                    // check whether value being written is an instance of the expected data type.
                    object valueToWrite = nodeToWrite.Value.Value;

                    TypeInfo typeInfo = TypeInfo.IsInstanceOfDataType(
                        valueToWrite,
                        expectedDatatypeId,
                        expectedValueRank,
                        m_server.NamespaceUris,
                        m_server.TypeTree);

                    if (typeInfo == null)
                    {
                        errors[ii] = StatusCodes.BadTypeMismatch;
                        continue;
                    }

                    // check index range.
                    if (nodeToWrite.ParsedIndexRange.Count > 0)
                    {                            
                        // check index range for scalars.
                        if (typeInfo.ValueRank < 0)
                        {
                            errors[ii] = StatusCodes.BadIndexRangeInvalid;
                            continue;
                        }
                            
                        // check index range for arrays.
                        else
                        {
                            Array array = (Array)valueToWrite;

                            if (nodeToWrite.ParsedIndexRange.Count != array.Length)
                            {
                                errors[ii] = StatusCodes.BadIndexRangeInvalid;
                                continue;
                            }
                        }
                    }
                            
                    #if LEGACY_CORENODEMANAGER 
                    // check if the node must be handled by an external datasource.
                    if (CheckSourceHandle(node, typeof(IWriteDataSource), ii, datasources))
                    {
                        nodes[nodeToWrite.NodeId] = node;
                        continue;
                    }
                    #endif
                                      
                    // write the default value.
                    error = node.Write(nodeToWrite.AttributeId, nodeToWrite.Value);

                    if (ServiceResult.IsBad(error))
                    {
                        errors[ii] = error;
                        continue;
                    }
                }
            }
            finally
            {
                m_lock.Exit();
            }
            
            #if LEGACY_CORENODEMANAGER 
            // check if nothing more to do.
            if (datasources.Count == 0)
            {
                return;
            }

            // call the datasources.
            foreach (KeyValuePair<IWriteDataSource,List<RequestHandle>> entry in datasources)
            { 
                try
                {
                    entry.Key.Write(
                        context,
                        entry.Value,
                        nodesToWrite,
                        errors);                   
                
                    // write to the default value if the source did not handle the write.
                    foreach (RequestHandle handle in entry.Value)
                    {
                        ServiceResult error = errors[handle.Index];

                        if (error == null)
                        {
                            continue;
                        }

                        if (error.Code == StatusCodes.GoodCallAgain)
                        {
                            WriteValue nodeToWrite = nodesToWrite[handle.Index];

                            ILocalNode node = null;

                            if (!nodes.TryGetValue(nodeToWrite.NodeId, out node))
                            {
                                errors[handle.Index] = StatusCodes.BadNodeIdUnknown;
                                continue;
                            }
            
                            errors[handle.Index] = node.Write(nodeToWrite.AttributeId, nodeToWrite.Value);
                        }
                    }
                }
                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
        }