Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
166 changes: 139 additions & 27 deletions NodeSetToAML.cs
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ public class NodeSetToAML
private const string ReversePrefix = "r";
private const string RoleClassPrefix = "rc";
private const string Enumeration = "Enumeration";
private const string KeepExternalInterfaceAttribute = "KeepExternalInterface";
private ModelManager m_modelManager;
private CAEXDocument m_cAEXDocument;
private AttributeTypeLibType m_atl_temp;
Expand Down Expand Up @@ -148,6 +149,9 @@ public class NodeSetToAML
private bool _runningInstances = false;
private NonHierarchicalReferences _nonHierarchicalReferences = null;

Dictionary<NodeId, List<ReferenceInfo>> m_multipleReferences = new Dictionary<NodeId, List<ReferenceInfo>>();
Dictionary<NodeId, InternalElementType> m_instances = new Dictionary<NodeId, InternalElementType>();

public NodeSetToAML(ModelManager modelManager)
{
m_modelManager = modelManager;
Expand Down Expand Up @@ -2133,8 +2137,12 @@ private void CompareLinksToExternaInterfaces(SystemUnitClassType child, SystemUn

if (!found)
{
checkIt.ExternalInterface.RemoveElement(externalInterface);
deleted = true;
AttributeType theAttribute = externalInterface.Attribute[KeepExternalInterfaceAttribute];
if ( theAttribute == null )
{
checkIt.ExternalInterface.RemoveElement(externalInterface);
deleted = true;
}
}
}
}
Expand Down Expand Up @@ -2333,33 +2341,39 @@ private void RebuildExternalInterfaces(
Dictionary<string, string> oldIdToNewName = new Dictionary<string, string>();
Dictionary<string,string>oldToNewName = new Dictionary<string, string>();
Dictionary<string, ExternalInterfaceType> newTypes = new Dictionary<string, ExternalInterfaceType>();
List<ExternalInterfaceType> reInsert = new List<ExternalInterfaceType>();

foreach ( ExternalInterfaceType externalInterface in systemUnitClass.ExternalInterface )
{
AttributeType sourceType = externalInterface.Attribute["IsSource"];
if ( sourceType != null )
if ( sourceType != null && sourceType.Value != null && sourceType.Value.Equals("true"))
{
if(sourceType.Value.Equals("true"))
string[] splitName = externalInterface.Name.Split(":");
if (splitName.Length > 0)
{
string[] splitName = externalInterface.Name.Split(":");
if ( splitName.Length > 0 )
string newName = splitName[0];
if (!oldToNewName.ContainsKey(externalInterface.Name))
{
string newName = splitName[0];
if (!oldToNewName.ContainsKey(externalInterface.Name) )
oldIdToNewName.Add(externalInterface.ID, newName);
oldToNewName.Add(externalInterface.Name, newName);
if (!newTypes.ContainsKey(newName))
{
oldIdToNewName.Add(externalInterface.ID, newName);
oldToNewName.Add(externalInterface.Name, newName);
if (!newTypes.ContainsKey(newName))
{
ExternalInterfaceType replace = (ExternalInterfaceType)externalInterface.Copy(deepCopy: true);
replace.Name = newName;
replace.ID = WebUtility.UrlEncode(newName + named);
newTypes.Add(newName, replace);
}
ExternalInterfaceType replace = (ExternalInterfaceType)externalInterface.Copy(deepCopy: true);
replace.Name = newName;
replace.ID = WebUtility.UrlEncode(newName + named);
newTypes.Add(newName, replace);
}
}
}
}
else
{
AttributeType keepAttribute = externalInterface.Attribute[KeepExternalInterfaceAttribute];
if (keepAttribute != null)
{
reInsert.Add(externalInterface);
}
}
}

foreach( InternalLinkType internalLink in systemUnitClass.InternalLink)
Expand All @@ -2381,6 +2395,10 @@ private void RebuildExternalInterfaces(
{
systemUnitClass.ExternalInterface.Insert( externalInterface, asFirst: false, asIs: true );
}
foreach (ExternalInterfaceType externalInterface in reInsert)
{
systemUnitClass.ExternalInterface.Insert(externalInterface, asFirst: false, asIs: true);
}
}

private void UpdateIsAbstract( UANode targetNode, SystemUnitClassType systemUnitClass )
Expand Down Expand Up @@ -3708,12 +3726,59 @@ private Variant LocalizedTextArrayAsVariant(NodeSet.LocalizedText[] array )
private void CreateInstances()
{
// add an InstanceHierarchy to the ROOT CAEXFile element
var myIH = m_cAEXDocument.CAEXFile.New_InstanceHierarchy("OPC UA Instance Hierarchy");
InstanceHierarchyType myIH = m_cAEXDocument.CAEXFile.New_InstanceHierarchy("OPC UA Instance Hierarchy");
AddLibraryHeaderInfo(myIH);

var RootNode = FindNode<UANode>(RootNodeId);
UANode RootNode = FindNode<UANode>(RootNodeId);

Dictionary<NodeId, List<ReferenceInfo>> instanceReferences =
new Dictionary<NodeId, List<ReferenceInfo>>();

// Issue 143. Need to go through and find multiple Target NodeIds, and respect
// those in the instance creation routine
BuildInstanceReferences(instanceReferences, RootNode);
MinimizeInstanceReferences(instanceReferences);

RecursiveAddModifyInstance<InstanceHierarchyType>(ref myIH, RootNode, false);
}

private void BuildInstanceReferences(Dictionary<NodeId, List<ReferenceInfo>> instanceReferences,
UANode toAdd )
{
List<ReferenceInfo> references = m_modelManager.FindReferences(toAdd.DecodedNodeId);

foreach (ReferenceInfo reference in references)
{
if (reference.IsForward == true)
{
if (m_modelManager.IsTypeOf(reference.ReferenceTypeId, HierarchicalNodeId) == true)
{
UANode targetNode = FindNode<UANode>(reference.TargetId);
if (reference.TargetId != TypesFolderNodeId)
{
if (!instanceReferences.ContainsKey(reference.TargetId))
{
instanceReferences[reference.TargetId] = new List<ReferenceInfo>();
}

instanceReferences[reference.TargetId].Add(reference);

BuildInstanceReferences(instanceReferences, targetNode);
}
}
}
}
}

private void MinimizeInstanceReferences(Dictionary<NodeId, List<ReferenceInfo>> instanceReferences )
{
foreach (KeyValuePair<NodeId, List<ReferenceInfo>> pair in instanceReferences)
{
if (pair.Value.Count > 1)
{
m_multipleReferences.Add(pair.Key, pair.Value);
}
}
}

InternalElementType RecursiveAddModifyInstance<T>(ref T parent, UANode toAdd, bool serverDiagnostics) where T : IInternalElementContainer
Expand All @@ -3726,7 +3791,7 @@ InternalElementType RecursiveAddModifyInstance<T>(ref T parent, UANode toAdd, bo
Utils.LogTrace( "Add Instance {0} [{1}] Start", prefix, decodedNodeId );

//first see if node already exists
var ie = parent.InternalElement[toAdd.DecodedBrowseName.Name];
InternalElementType ie = parent.InternalElement[toAdd.DecodedBrowseName.Name];
if (ie == null)
{
SystemUnitFamilyType suc;
Expand All @@ -3745,12 +3810,10 @@ InternalElementType RecursiveAddModifyInstance<T>(ref T parent, UANode toAdd, bo
}
Debug.Assert(suc != null);

// check if instance already exists before adding a new one #11
ie = (InternalElementType)m_cAEXDocument.FindByID(amlId);
if( ie != null )
InternalElementType existingInternalElement = FindInstanceInternalElement(toAdd);
if (existingInternalElement != null)
{
Utils.LogTrace( "Add Instance {0} [{1}] Already Added", prefix, decodedNodeId );
return ie;
return existingInternalElement;
}

if ( prefix.StartsWith("http://"))
Expand All @@ -3761,7 +3824,19 @@ InternalElementType RecursiveAddModifyInstance<T>(ref T parent, UANode toAdd, bo
ie = CreateClassInstanceWithIDReplacement(prefix + "_", suc);

parent.Insert(ie);

m_instances.Add( toAdd.DecodedNodeId, ie);
}
else
{
if (ie.ID != amlId)
{
InternalElementType existingInternalElement = FindInstanceInternalElement(toAdd);
if (existingInternalElement != null)
{
parent.InternalElement.RemoveElement(ie);
ie = existingInternalElement;
}
}
}
Debug.Assert(ie != null);

Expand Down Expand Up @@ -3833,7 +3908,6 @@ InternalElementType RecursiveAddModifyInstance<T>(ref T parent, UANode toAdd, bo

if (reference.TargetId != TypesFolderNodeId)
{

var childIE = RecursiveAddModifyInstance<InternalElementType>(ref ie, targetNode,
serverDiagnostics);
foundInternalElements.Add(childIE.Name);
Expand All @@ -3843,6 +3917,21 @@ InternalElementType RecursiveAddModifyInstance<T>(ref T parent, UANode toAdd, bo
ReferenceTypeNode.DecodedBrowseName.Name + "]/[" + sourceInterface.Attribute["InverseName"].Value,
targetNode.DecodedNodeId);

if ( m_multipleReferences.TryGetValue(targetNode.DecodedNodeId,
out List<ReferenceInfo> multipleReferences))
{
foreach (ReferenceInfo saveReference in multipleReferences)
{
if ( saveReference.Equals(reference))
{
OverrideBooleanAttribute(destInterface.Attribute,
KeepExternalInterfaceAttribute,
value: true, typeOnly: true);
break;
}
}
}

FindOrAddInternalLink(ref ie, sourceInterface.ID, destInterface.ID, targetNode.DecodedBrowseName.Name);
}
}
Expand Down Expand Up @@ -3914,6 +4003,29 @@ InternalElementType RecursiveAddModifyInstance<T>(ref T parent, UANode toAdd, bo
return ie;
}

InternalElementType FindInstanceInternalElement(UANode node)
{
InternalElementType internalElement = null;

/*
* Previously, this was accomplished by using the document.FindById method.
* However due to Issue 143 - a duplication issue, this added a substantial performance hit
* Adding a LookupService actual increments the performance hit to an unusable level.
* Adding a ServiceLocater.QueryService and using ILookupUpTable to load the table does
* improve the performance to an acceptable level, but it is optimized for ReadOnly document
* access. This converter needs Read/Write access, which makes using the ILookUpTable not feasible.
* A local dictionary is used instead.
*/

if (m_instances.TryGetValue(node.DecodedNodeId, out internalElement))
{
Utils.LogTrace("Add Instance {0} [{1}] Previously Added",
node.DecodedBrowseName.Name, node.DecodedNodeId);
}

return internalElement;
}

// add an internal link if it does not already exist
InternalLinkType FindOrAddInternalLink(ref InternalElementType ie, string sourceID, string destinationID, string linkName)
{
Expand Down
Loading