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

Call() private method

private Call ( OperationContext context, IList methodsToCall, IList results, IList errors ) : void
context OperationContext
methodsToCall IList
results IList
errors IList
return void
        public void Call(
            OperationContext         context,
            IList<CallMethodRequest> methodsToCall,
            IList<CallMethodResult>  results,
            IList<ServiceResult>     errors)
        {
            if (context == null)       throw new ArgumentNullException("context");
            if (methodsToCall == null) throw new ArgumentNullException("methodsToCall");
            if (results == null)       throw new ArgumentNullException("results");
            if (errors == null)        throw new ArgumentNullException("errors");
                         
            #if LEGACY_CORENODEMANAGER
            List<CallRequest> callables = new List<CallRequest>();
            #endif
            
            try
            {
                m_lock.Enter();

                for (int ii = 0; ii < methodsToCall.Count; ii++)
                {
                    CallMethodRequest methodToCall = methodsToCall[ii];

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

                    if (node == null)
                    {
                        continue;
                    }
                    
                    methodToCall.Processed = true;                                      
                                        
                    // look up the method.
                    ILocalNode method = GetLocalNode(methodToCall.MethodId) as ILocalNode;

                    if (method == null)
                    {
                        errors[ii] = ServiceResult.Create(StatusCodes.BadMethodInvalid, "Method is not in the address space.");
                        continue;
                    }

                    // check that the method is defined for the object.
                    if (!node.References.Exists(ReferenceTypeIds.HasComponent, false, methodToCall.MethodId, true, m_server.TypeTree))
                    {
                        errors[ii] = ServiceResult.Create(StatusCodes.BadMethodInvalid, "Method is not a component of the Object.");
                        continue;
                    } 
                             
                    #if LEGACY_CORENODEMANAGER  
                    // find object to call.
                    ICallable callable = method as ICallable;

                    SourceHandle handle = method.Handle as SourceHandle;

                    if (handle != null)
                    {
                        callable = handle.Source as ICallable;
                    }

                    if (callable == null)
                    { 
                        errors[ii] = ServiceResult.Create(StatusCodes.BadNotImplemented, "Method does not have a source registered.");
                        continue;
                    }
                                                 
                    // get the input arguments.
                    IVariable argumentNode = GetLocalNode(method.NodeId, ReferenceTypes.HasProperty, false, false, BrowseNames.InputArguments) as IVariable;
                    
                    // extract the arguments from the node.
                    Argument[] arguments = null;

                    if (argumentNode != null)
                    {
                        Array value = argumentNode.Value as Array;

                        if (value != null)
                        {
                            arguments = ExtensionObject.ToArray(value, typeof(Argument)) as Argument[];
                        }
                    }

                    // validate the input arguments.
                    bool argumentError = false;

                    List<ServiceResult> argumentErrors = new List<ServiceResult>();

                    object[] validatedArguments = new object[methodToCall.InputArguments.Count];
                    
                    // check if the argument is expected.
                    if ((arguments == null && methodToCall.InputArguments.Count > 0) || (methodToCall.InputArguments.Count != arguments.Length))
                    {
                        errors[ii] = StatusCodes.BadArgumentsMissing;
                        continue;
                    }

                    for (int jj = 0; jj < methodToCall.InputArguments.Count; jj++)
                    {                
                        // can't do anything if the argument definition is missing.
                        Argument argumentDefinition = arguments[jj];

                        if (argumentDefinition == null)
                        {
                            argumentErrors.Add(ServiceResult.Create(StatusCodes.BadConfigurationError, "Server does not have a defintion for argument."));
                            argumentError = true;
                            continue;
                        }

                        // a null value can be used for optional arguments.
                        object argumentValue = methodToCall.InputArguments[jj].Value;

                        if (argumentValue == null)
                        {
                            argumentErrors.Add(ServiceResult.Create(StatusCodes.BadInvalidArgument, "Argument cannot be null."));
                            argumentError = true;
                            continue;
                        }                                                          
      
                        // get the datatype.
                        if (!m_server.TypeTree.IsEncodingFor(argumentDefinition.DataType, argumentValue))
                        {
                            argumentErrors.Add(ServiceResult.Create(StatusCodes.BadTypeMismatch, "Expecting value with datatype '{0}'.", argumentDefinition.DataType));
                            argumentError = true;
                            continue;
                        }

                        // check the array size.
                        Array array = argumentValue as Array;
                        
                        if (array != null)
                        {
                            if (argumentDefinition.ValueRank == ValueRanks.Scalar)
                            {
                                argumentErrors.Add(ServiceResult.Create(StatusCodes.BadTypeMismatch, "Expecting a scalar value."));
                                argumentError = true;
                                continue;
                            }
                            
                            if (argumentDefinition.ValueRank > 0 && array.Length != argumentDefinition.ValueRank)
                            {
                                argumentErrors.Add(ServiceResult.Create(StatusCodes.BadTypeMismatch, "Expecting an array with length {0}.", argumentDefinition.ValueRank));
                                argumentError = true;
                                continue;
                            }
                        }
                        else
                        {
                            if (argumentDefinition.ValueRank >= 0)
                            {
                                argumentErrors.Add(ServiceResult.Create(StatusCodes.BadTypeMismatch, "Expecting an array value."));
                                argumentError = true;
                                continue;
                            }
                        }

                        // argument passed initial validation.
                        validatedArguments[jj] = argumentValue;
                        argumentErrors.Add(null);
                    }
                    #else
                    errors[ii] = StatusCodes.BadNotImplemented;
                    #endif

                    #if LEGACY_CORENODEMANAGER  
                    CallRequest request = new CallRequest();

                    request.Callable           = callable;
                    request.Index              = ii;
                    request.MethodId           = method.NodeId;
                    request.MethodHandle       = (handle != null)?handle.Handle:null;
                    request.ObjectId           = node.NodeId;
                    request.InputArguments     = validatedArguments;
                    request.ArgumentErrors     = argumentErrors;
                    request.HasInvalidArgument = argumentError;

                    callables.Add(request);
                    #endif
                }
            }
            finally
            {
                m_lock.Exit();
            }
            
            #if LEGACY_CORENODEMANAGER
            // check if nothing to do.
            if (callables.Count == 0)
            {
                return;
            }                    

            // call the methods.
            foreach (CallRequest callable in callables)
            {       
                // call method if no errors occurred.
                List<object> outputArguments = new List<object>();

                if (!callable.HasInvalidArgument)
                {
                    try
                    {
                        errors[callable.Index] = callable.Callable.Call(
                            context,
                            callable.MethodId,
                            callable.MethodHandle,
                            callable.ObjectId,
                            callable.InputArguments,
                            callable.ArgumentErrors,
                            outputArguments);
                    }
                    catch (Exception e)
                    {
                        errors[callable.Index] = ServiceResult.Create(e, StatusCodes.BadUnexpectedError, "Error occurred invoking method.");
                    }
                }
                else
                {
                    errors[callable.Index] = ServiceResult.Create(StatusCodes.BadInvalidArgument, "One or more arguments were not valid.");
                }

                // create the result item.
                CallMethodResult result = results[callable.Index] = new CallMethodResult();

                // process argument errors.
                bool errorExists = false;

                foreach (ServiceResult argumentError in callable.ArgumentErrors)
                {
                    if (ServiceResult.IsBad(argumentError))
                    {
                        result.InputArgumentResults.Add(argumentError.Code);

                        DiagnosticInfo diagnosticInfo = null;

                        if ((context.DiagnosticsMask & DiagnosticsMasks.OperationAll) != 0)
                        {
                            diagnosticInfo = ServerUtils.CreateDiagnosticInfo(m_server, context, argumentError);
                            errorExists = true;
                        }

                        result.InputArgumentDiagnosticInfos.Add(diagnosticInfo);
                    }
                    else
                    {
                        result.InputArgumentResults.Add(StatusCodes.Good);
                    }
                }

                if (!errorExists)
                {
                    result.InputArgumentDiagnosticInfos.Clear();
                }

                // copy output arguments into result.
                result.OutputArguments.Clear();

                foreach (object outputArgument in outputArguments)
                {
                    result.OutputArguments.Add(new Variant(outputArgument));
                }                
            }
            #endif
        }