An Information Model defines a contract between OPC UA Applications. OPC UA Clients can rely on the mandatory parts defined in such an Information Model and OPC UA Servers are not required to provide more than the specified mandatory information.
Elements defined in an Information Model are qualified by their Namespace, which is a unique URI. When a new version of such an Information Model is defined, some rules need to be considered to re-use the existing Namespace. If those rules cannot be followed, the existing NamespaceUri should not be used. However, a new NamespaceUri implies that all information is new, that is, even using the same name and NodeId (without NamespaceIndex) for a type, OPC UA Applications will consider it to be a completely different Node with no relation to the one qualified by the old Namespace.
The next clauses describe the rules that must be followed to re-use the existing Namespace when versioning an Information Model.
It is not allowed to add new mandatory InstanceDeclarations using the ModellingRules Mandatory and MandatoryPlaceholder. To add a mandatory InstanceDeclaration, either create a new Subtype having the mandatory InstanceDeclaration, or a new type independent of the previous one. As alternative, make the new InstanceDeclaration optional but define a Profile requiring the new InstanceDeclaration.
This rule avoids the incompatibility when an OPC UA Client aware of the new version connects to an OPC UA Server only supporting the old version, and the OPC UA Client expects a new mandatory feature not provided by the OPC UA Server.
It is allowed to add new optional InstanceDeclarations using the ModellingRules Optional and OptionalPlaceholder.
Old OPC UA Servers will just not provide those, and new OPC UA Clients will not expect them to be available in all OPC UA Servers, since they are optional. Since OPC UA Servers are allowed to add anything to the instances, an old OPC UA Client can also easily connect to a new OPC UA Server, potentially just ignoring the new information.
It is allowed to add Interfaces to ObjectTypes as long as no new mandatory InstanceDeclarations are added to the ObjectType. That means, a new Interface can be defined based on an existing ObjectType by using some InstanceDeclarations of that ObjectType. Such an Interface may have mandatory InstanceDeclarations already defined in the ObjectType, and in that case the ObjectType can implement the Interface.
It is not allowed to add or remove values of an Enumeration DataType. It is allowed to limit the enumeration values, creating a subtype with a subset of the existing values defined by the supertype.
Old OPC UA Clients would not expect new values, and old OPC UA Servers might provide removed values to new OPC UA Clients that would not be able to interpret these based on their built-in knowledge.
If it is foreseeable that future specification versions would need to add or remove enumeration values, or that derived Companion Specifications would want to extend them, then one of the MultiState VariableTypes should be used instead of an Enumeration DataType.
It is not allowed to add or remove optional or mandatory fields of a Structured DataType or change the name or DataType (including ValueRank and ArrayDimensions) of a field.
This would change the encoding and OPC UA applications might not be able to encode / decode the information anymore with built-in knowledge.
It is not allowed to add or remove fields of a Union or change the DataType of a field.
This would change the allowed types and interoperability between two versions is not given anymore.
It is not allowed to add or remove entries of the OptionSetValues Property as it would change the interpretation of the DataType. It is allowed to change the text of an entry if the semantic is not changed, e.g. by fixing typos or improving the formulation.
It is not allowed to add or remove entries to the OptionSetValues Property. It is allowed to change the text of an entry if the semantic is not changed, e.g. by fixing typos or improving the formulation.
If a specification intends to deprecate a bit, it can require that the validBit shall always be set to false. Adding entries is forbidden, because subtypes might have been defined using those bits already.
If a specification intends to extend the OptionSet, it needs to define subtypes with additional bits. Subtypes may also refine the semantic of existing entries (see OPC 10000-3). Note that the initial defined length cannot be changed in any subtype (see OPC 10000-3).
It is allowed to add subtypes into the existing type hierarchy.
It is not recommended to insert new types inside the existing hierarchy, as shown in Figure 1. In the example, NewType is added as supertype of Subtype_B and Subtype_C.
If a new type is absolutely necessary, the following rules apply:
- The new type shall not add mandatory InstanceDeclarations unless they have been defined before on each subtype.
- The new type shall not define additional constraints (defined in the text of the specification), unless those constraints were already valid for all its subtypes before.
- The newly added type may be abstract or concrete.
In a nutshell, the new type shall not add anything to the subtypes that would not be allowed to be added to the subtypes directly.
It is not allowed to add new types inside the EventType hierarchy, i.e. in the part of the ObjectType hierarchy inheriting from the BaseEventType, as EventTypes are used for filtering, and new OPC UA Clients might use the new EventType as a filter in an old Server, which would not work.
Figure 1 – Example of adding types inside an existing type hierarchy
OPC UA Clients that are pre-programmed with knowledge of the type hierarchy do not need to browse the type hierarchy in the OPC UA Server. Therefore an old OPC UA Client would work with a new OPC UA Server, since all types that are built into the old OPC UA Client would exist. A new OPC UA Client would also work since the old OPC UA Server would not have any instances of the newly added types. An OPC UA Client has to expect that not all defined types will have instances.
It is allowed to add new subtypes of events that extend the existing types, but these subtypes have to maintain the concepts expressed by the parent type. A limit alarm could have a subtype that makes some of the limits mandatory or even adds more limits, but all subtypes would have to still be limit alarms.
It is allowed to create new subtypes of existing DataTypes.
It is not recommended to insert types inside the type hierarchy of DataTypes (similar to ObjectTypes and VariableTypes, see Figure 1). If absolutely necessary, the following rules apply:
- For all DataTypes no new constraints (written as text in the specification) should be added, but existing constraints common to all the subtypes can be added to the new supertype.
- For abstract DataTypes there are no additional rules.
- For simple DataTypes (using the encodings of the built-in DataTypes) there are no additional rules.
- For Enumeration DataTypes the new supertype may have more Enumeration Values than the subtypes. In that case, it shall have at least a union of all Enumeration values defined in any of its subtypes. If the numeric values would conflict, it is not possible to create such a supertype.
- For Structured DataTypes, the supertype shall only have fields that are already defined in all subtypes. It shall be legal to create all existing subtypes, considering DataType, ValueRank and ArrayDimensions.
It is not allowed to change the signature of a Method. Even adding new optional Arguments to an existing Method would change the signature, so this is not allowed.
It is allowed to add metadata to the existing arguments of a Method, e.g. the EngineeringUnits Property (done with HasArgumentDescription References, see section 5 for an example). This does not include changing arguments from mandatory to optional or vice versa.
It is also allowed to change the description text of a Method parameter as long as this does not change the semantics of the argument.
If the signature of a Method would change, new OPC UA Clients might call old OPC UA Servers with the wrong signature (e.g. if an argument has become optional), or old OPC UA Clients may call the new OPC UA Server with the wrong arguments (e.g. if an argument has become mandatory). OPC UA Clients with prior knowledge of the information model do not necessarily read the Method arguments from the OPC UA Server, and even if they would, their implementation to call the Method would not work anymore.
If the intention is to change the signature of a Method, then a new Method with a new signature and a new BrowseName shall be defined instead. A common practice for the new name is to add a number to the existing name, i.e. the new Refresh Method is Refresh2.
It is not allowed to change the DataType, ValueRank or ArrayDimensions of a Variable, neither for an InstanceDeclaration, nor for a standardized Variable like ServerStatus.
Even refining an existing DataType to a subtype is a breaking change. New OPC UA Clients connecting to an old OPC UA Server would expect the subtype but might get the supertype instead.
Changing the TypeDefinition of an InstanceDeclaration is not allowed unless it is being changed to a subtype of the already specified one. Using a subtype is only allowed if the subtype does not add any mandatory InstanceDeclarations or constraints (defined in the text of the specification), and does not refine the DataType (in case of a Variable).
ReferenceTypes typically restrict their usage by limiting which SourceNodes and TargetNodes are allowed. Currently such restrictions are only specified in text in specifications.
Changing the rules, either allowing more or fewer restrictions, should be avoided. However, OPC UA Clients should consider the results when following References (e.g., the ReferenceDescription containing NodeClass and TypeDefinition) and they should be able to handle unexpected results. Therefore, changing the rules is not forbidden, as long as it does not contradict other parts of the information model e.g., because a TypeDefinition is using the ReferenceType in a way that is no longer allowed in the new version.
It is allowed to add subtypes to the existing ReferenceType hierarchy. It is not allowed to move types in that Hierarchy, e.g. making a hierarchical ReferenceType a non-hierarchical ReferenceType, as the filtering would behave differently. It is also not allowed to add new ReferenceTypes inside the Hierarchy. This would work for old OPC UA Clients, since they would just not use those unknown ReferenceTypes for filtering, but not for new OPC UA Clients connecting to old OPC UA Servers, since they would expect the ReferenceType to be available and use it for filtering information available in the OPC UA Server.
It is highly recommended that Companion Specifications do not have breaking changes in new versions. There are strategies that can be used to avoid breaking changes:
- Create subtypes and add mandatory elements to the subtypes. Create new conformance units and profiles requiring the use of the subtypes. This approach only works to add new mandatory things, and is a compatible change, such that an old client works with a new server. A new client can be designed to also accept the old types, or it may not work with old servers. That is a decision of the client developer. Note that depending on what type gets subtyped by a new version, many other types using this type may need to be changed as well.
- Add optional components to existing types and make them mandatory by conformance units and profiles. This avoids creating subtypes which might require creating other subtypes, etc. Otherwise, the same logic as for approach 1 applies. Old clients will work with new servers, and new clients may work with old servers if they do not require the new mandatory things.
When it cannot be avoided to break something from an existing specification in a new version, there are different options:
- Create a new Namespace and thus define, conceptionally, a completely new information model. It is recommended to change the NamespaceUri and add a version number at the end (for example, V2 at the end for the second version). This is on one hand the cleanest solution; on the other hand, this is a completely incompatible change of the model. No old client will directly work with a new server and vice versa.
- Create new types independent of the old when needed, e.g. DeviceType2 for DeviceType. This allows also to remove mandatory things, that have been proven to be problematic. Depending on how many types have been changed, old clients may or may not be able to do reasonable things with new servers. If old servers should be supported, new clients have to be designed to support both types. Note that depending on what type gets exchanged by a new version, many other types using this type need to be changed as well.