Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable call of methods that are part of the types or super types of the objectId on which the method is called #1698

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
58 changes: 58 additions & 0 deletions Libraries/Opc.Ua.Server/Diagnostics/CustomNodeManager.cs
Expand Up @@ -463,6 +463,49 @@ public NodeState FindNodeInAddressSpace(NodeId nodeId)
}
return null;
}

/// <summary>
/// Find a method in the type or any of the supertypes of a provided objectId on which the method is called
/// </summary>
/// <param name="context"></param>
/// <param name="objectId"></param>
/// <param name="methodId"></param>
/// <returns></returns>
public MethodState FindMethodInType(
ServerSystemContext context,
NodeState objectId,
NodeId methodId)
{
MethodState methodState = null;
NodeState typeNode = FindNodeInAddressSpace(((BaseInstanceState)objectId).TypeDefinitionId);
if (typeNode != null)
{
methodState = typeNode.FindMethod(context, methodId);

// Search super types
if (methodState == null)
{
NodeId superTypeNid = ((BaseTypeState)typeNode).SuperTypeId;

while ((superTypeNid != null) && (superTypeNid != ObjectTypeIds.BaseObjectType))
{
typeNode = FindNodeInAddressSpace(superTypeNid);
if (typeNode != null)
{
methodState = typeNode.FindMethod(context, methodId);
if (methodState != null)
{
break;
}
}
superTypeNid = ((BaseTypeState)typeNode).SuperTypeId;
}

}
}

return methodState;
}
#endregion

#region INodeManager Members
Expand Down Expand Up @@ -2946,6 +2989,15 @@ private void CheckIfSemanticsHaveChanged(ServerSystemContext systemContext, Prop

// find the method.
method = source.FindMethod(systemContext, methodToCall.MethodId);
// if the found method is not the actual method tried to be called
// this might happen in case the method.MethodDeclarationId == methodToCall.MethodId
if ((method != null) &&
(method.NodeId != methodToCall.MethodId) &&
(method.MethodDeclarationId == methodToCall.MethodId))
{
// try to find the actual method to be called on the type hierarchy
method = FindMethodInType(systemContext, source, methodToCall.MethodId);
}

if (method == null)
{
Expand All @@ -2955,6 +3007,12 @@ private void CheckIfSemanticsHaveChanged(ServerSystemContext systemContext, Prop
method = (MethodState)FindPredefinedNode(methodToCall.MethodId, typeof(MethodState));
}

// check the type for method to call
if (method == null)
{
method = FindMethodInType(systemContext, source, methodToCall.MethodId);
}

if (method == null)
{
errors[ii] = StatusCodes.BadMethodInvalid;
Expand Down
53 changes: 53 additions & 0 deletions Tests/Opc.Ua.Server.Tests/ReferenceServerTest.cs
Expand Up @@ -28,6 +28,7 @@
* ======================================================================*/

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
Expand Down Expand Up @@ -408,6 +409,58 @@ public void TransferSubscription(bool sendInitialData, bool useSecurity)
SecureChannelContext.Current = securityContext;
}
}

/// <summary>
/// Call Method.
/// </summary>
[Test]
[Benchmark]
public void CallMethodFromTypeOnTypeInstance()
{
// Create an instance of FileDirectoryType under the Server node
NodeId objectId = m_server.CurrentInstance.DiagnosticsNodeManager.CreateNode(m_server.CurrentInstance.DefaultSystemContext,
ObjectIds.Server,
ReferenceTypeIds.HasComponent,
"fileDirectoryInstance",
new FileDirectoryState(null));

NodeId methodId = MethodIds.FileDirectoryType_CreateDirectory;

// Implement the CreateDirectory method belonging to the FileDirectoryType type instance
MethodState methodStateInstance = (MethodState)m_server.CurrentInstance.DiagnosticsNodeManager.FindPredefinedNode(methodId,
typeof(MethodState));

// Flag a successfull call of the implemented method
bool methodCalled = false;
methodStateInstance.OnCallMethod += (
ISystemContext context,
MethodState method,
IList<object> inputArguments,
IList<object> outputArguments) => {
methodCalled = true;
return ServiceResult.Good; };

// Call the implemented type method on the object instance
var requestHeader = m_requestHeader;
requestHeader.Timestamp = DateTime.UtcNow;
var nodesToCall = new CallMethodRequestCollection();

nodesToCall.Add(new CallMethodRequest() { ObjectId = objectId,
MethodId = methodId,
InputArguments = new VariantCollection() { new Variant("testString") }});
var response = m_server.Call(requestHeader,
nodesToCall,
out var results,
out var diagnosticInfos);

Assert.IsTrue(methodCalled);

ServerFixtureUtils.ValidateResponse(response);
ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, results);
}



#endregion
}
}