"""
DataDefinition classes
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright (c) 2015 VMware, Inc. All rights reserved.'
import logging
from vmware.vapi.data.type import Type
from vmware.vapi.data.value import data_value_factory
from vmware.vapi.exception import CoreException
from vmware.vapi.l10n.runtime import message_factory
from vmware.vapi.lib.visitor import VapiVisitor
from vmware.vapi.lib.constants import (MAP_ENTRY, OPERATION_INPUT)
logger = logging.getLogger(__name__)
[docs]class DataDefinition(object):
"""
Base class for all types in the vAPI run-time type system
:type type: :class:`str`
:ivar type: String representation of the type
"""
def __init__(self, data_type=None):
"""
Initialize the data definition instance
:type data_type: :class:`str`
:param data_type: String representation of the type
"""
self.type = data_type
[docs] def valid_instance_of(self, value):
"""
Validates that the specified :class:`vmware.vapi.data.value.DataValue` is an instance of
this data-definition
:type value: :class:`vmware.vapi.data.value.DataValue`
:param value: the data value to validate
:rtype: :class:`bool`
:return: true if the value is an instance of this data-definition,
false, otherwise
"""
return not self.validate(value)
[docs] def validate(self, value):
"""
Validates that the specified :class:`vmware.vapi.data.value.DataValue` is an instance of
this data-definition
:type value: :class:`vmware.vapi.data.value.DataValue`
:param value: the data value to validate
:rtype: :class:`list` of :class:`vmware.vapi.message.Message` or ``None``
:return: a stack of messages indicating why the value is not an instance
of this data-definition, or None if the value is an instance of
this data-definition
"""
if value is None:
msg = message_factory.get_message('vapi.data.validate.mismatch',
self.type,
'None')
return [msg]
if value.type != self.type:
msg = message_factory.get_message('vapi.data.validate.mismatch',
self.type,
value.type)
return [msg]
return None
[docs] def complete_value(self, value):
"""
Fill the optional fields of StructValues. Also
includes the StructValues present in other generic types: List
and Optional.
:type value: :class:`vmware.vapi.data.value.DataValue`
:param value: DataValue
"""
pass
[docs] def accept(self, visitor):
"""
Applies a visitor to this data-definition.
:type visitor: :class:`SimpleDefinitionVisitor`
:param visitor: the visitor operating on this data-definition
"""
visitor.visit(self)
def __eq__(self, other):
if not isinstance(other, DataDefinition):
return NotImplemented
return self.type == other.type
def __ne__(self, other):
if not isinstance(other, DataDefinition):
return NotImplemented
return not (self == other)
# Classes that override __eq__ should define __hash__ to make
# its instances usable in hashed collections
def __hash__(self):
return str(self).__hash__()
def __repr__(self):
return '%s()' % self.__class__.__name__
[docs]class SingletonDefinition(DataDefinition):
"""
Base class for all the primitive data definition classes. All the derived
classes of this class will have only one instance.
"""
_instance = None
def __init__(self, data_type):
"""
Initialize SingletonDefinition
:type data_type: :class:`vmware.vapi.data.type.Type`
:param data_type: Type of the DataDefinition
"""
DataDefinition.__init__(self, data_type)
def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(SingletonDefinition, cls).__new__(
cls, *args, **kwargs)
return cls._instance
[docs]class VoidDefinition(SingletonDefinition):
"""
DataDefinition class for void
"""
def __init__(self):
"""
Initialize VoidDefinition
"""
SingletonDefinition.__init__(self, Type.VOID)
[docs] def new_value(self):
"""
Create a new VoidValue
:rtype: :class:`vmware.vapi.data.value.VoidValue`
:return: Newly created VoidValue
"""
return data_value_factory(self.type)
[docs]class IntegerDefinition(SingletonDefinition):
"""
DataDefinition for long values
"""
def __init__(self):
"""
Initialize IntegerDefinition
"""
SingletonDefinition.__init__(self, Type.INTEGER)
[docs] def new_value(self, value=0):
"""
Create a new IntegerValue
:rtype: :class:`vmware.vapi.data.value.IntegerValue`
:return: Newly created IntegerValue
"""
return data_value_factory(self.type, value)
[docs]class DoubleDefinition(SingletonDefinition):
"""
DataDefinition for floats
"""
def __init__(self):
"""
Initialize DoubleDefinition
"""
SingletonDefinition.__init__(self, Type.DOUBLE)
[docs] def new_value(self, value=0.0):
"""
Create a new DoubleValue
:rtype: :class:`vmware.vapi.data.value.DoubleValue`
:return: Newly created DoubleValue
"""
return data_value_factory(self.type, value)
[docs]class StringDefinition(SingletonDefinition):
"""
DataDefinition for strings
"""
def __init__(self):
"""
Initialize StringDefinition
"""
SingletonDefinition.__init__(self, Type.STRING)
[docs] def new_value(self, value=""):
"""
Create a new StringValue
:rtype: :class:`vmware.vapi.data.value.StringValue`
:return: Newly created StringValue
"""
return data_value_factory(self.type, value)
[docs]class OpaqueDefinition(SingletonDefinition):
"""
DataDefinition for opaque
"""
def __init__(self):
"""
Initialize OpaqueDefinition
"""
SingletonDefinition.__init__(self, Type.OPAQUE)
[docs] def validate(self, value):
"""
The validation for OpaqueDefinition will succeed against
any DataValue. Only validates that supplied value is not None
:type value: :class:`vmware.vapi.data.value.DataValue`
:param value: DataValue to be validated
:rtype: :class:`list` of :class:`vmware.vapi.message.Message` or ``None``
:return: a stack of messages indicating why the value is not an instance
of this data-definition, or None if the value is an instance of
this data-definition
"""
if value is None:
msg = message_factory.get_message('vapi.data.validate.mismatch',
self.type,
'None')
return [msg]
return None
[docs]class DynamicStructDefinition(SingletonDefinition):
"""
DataDefinition for dynamic structs
"""
_valid_types = [Type.STRUCTURE, Type.ERROR]
def __init__(self):
"""
Initialize DynamicStructDefinition
"""
SingletonDefinition.__init__(self, Type.DYNAMIC_STRUCTURE)
[docs] def validate(self, value):
"""
The validation for DynamicStructDefinition will succeed against
any StructValue.
:type value: :class:`vmware.vapi.data.value.DataValue`
:param value: the data value to validate
:rtype: :class:`list` of :class:`vmware.vapi.message.Message` or ``None``
:return: a stack of messages indicating why the value is not an instance
of this data-definition, or None if the value is an instance of
this data-definition
"""
if value is None:
msg = message_factory.get_message(
'vapi.data.dynamicstruct.validate.mismatch',
self._valid_types,
'None')
return [msg]
if value.type not in self._valid_types:
msg = message_factory.get_message(
'vapi.data.dynamicstruct.validate.mismatch',
self._valid_types,
value.type)
return [msg]
return None
[docs]class AnyErrorDefinition(SingletonDefinition):
"""
DataDefinition for 'Exception' type in IDL
"""
def __init__(self):
"""
Initialize AnyErrorDefinition
"""
SingletonDefinition.__init__(self, Type.ANY_ERROR)
[docs] def validate(self, value):
"""
The validation for AnyErrorDefinition will succeed against
any ErrorValue.
:type value: :class:`vmware.vapi.data.value.DataValue`
:param value: the data value to validate
:rtype: :class:`list` of :class:`vmware.vapi.message.Message` or ``None``
:return: a stack of messages indicating why the value is not an instance
of this data-definition, or None if the value is an instance of
this data-definition
"""
if value is None:
msg = message_factory.get_message('vapi.data.validate.mismatch',
self.type,
'None')
return [msg]
if value.type != Type.ERROR:
msg = message_factory.get_message('vapi.data.validate.mismatch',
self.type,
value.type)
return [msg]
return None
[docs]class BlobDefinition(SingletonDefinition):
"""
DataDefinition for binary values
"""
def __init__(self):
"""
Initialize BlobDefinition
"""
SingletonDefinition.__init__(self, Type.BLOB)
[docs] def new_value(self, value=""):
"""
Create a new BlobValue
:rtype: :class:`vmware.vapi.data.value.BlobValue`
:return: Newly created BlobValue
"""
return data_value_factory(self.type, value)
[docs]class BooleanDefinition(SingletonDefinition):
"""
DataDefinition for bool values
"""
def __init__(self):
"""
Initialize BooleanDefinition
"""
SingletonDefinition.__init__(self, Type.BOOLEAN)
[docs] def new_value(self, value=False):
"""
Create a new BooleanValue
:rtype: :class:`vmware.vapi.data.value.BooleanValue`
:return: Newly created BooleanValue
"""
return data_value_factory(self.type, value)
[docs]class ListDefinition(DataDefinition):
"""
DataDefinition for lists
"""
def __init__(self, element_type):
"""
Initialize ListDefinition
:type element_type: :class:`DataDefinition`
:param element_type: DataDefinition of the elements inside ListDefinition
"""
if not element_type:
raise ValueError('ListDefinition requires element definition')
DataDefinition.__init__(self, Type.LIST)
self.element_type = element_type
[docs] def new_value(self, values=None):
"""
Create a new ListValue
:type values: :class:`list` of :class:`vmware.vapi.data.value.DataValue`
:param values: List of elements
:rtype: :class:`vmware.vapi.data.value.ListValue`
:return: Newly created ListValue
"""
return data_value_factory(self.type, values)
[docs] def validate(self, list_value):
"""
Apart from the validation checks specified in the validate
method of DataDefinition class, this method does some additional checks
Validation will fail if any element in the ListValue does not validate
against the DataDefinition of the elementType of this ListDefinition
:type other: :class:`vmware.vapi.data.value.ListValue`
:param other: ListValue to be validated
:rtype: :class:`list` of :class:`vmware.vapi.message.Message` or ``None``
:return: a stack of messages indicating why the value is not an instance
of this data-definition, or None if the value is an instance of
this data-definition
"""
errors = DataDefinition.validate(self, list_value)
if errors:
return errors
for index, value in enumerate(list_value):
errors = self.element_type.validate(value)
if errors:
msg = message_factory.get_message(
'vapi.data.list.invalid.entry',
str(value), index)
return [msg] + errors
return None
[docs] def complete_value(self, value):
"""
Fill the optional values inside StructValues
:type value: :class:`vmware.vapi.data.value.DataValue`
:param value: DataValue
"""
assert(value.type == Type.LIST)
for element in value:
self.element_type.complete_value(element)
def __eq__(self, other):
if not isinstance(other, ListDefinition):
return NotImplemented
return (DataDefinition.__eq__(self, other) and
self.element_type == other.element_type)
# Classes that override __eq__ should define __hash__ to make
# its instances usable in hashed collections
def __hash__(self):
return DataDefinition.__hash__(self)
def __repr__(self):
return 'ListDefinition(element_type=%s)' % repr(self.element_type)
[docs]class StructDefinition(DataDefinition):
"""
DataDefinition for structures
"""
def __init__(self, name, fields, data_type=Type.STRUCTURE):
"""
Initialize StructDefinition
:type name: :class:`str`
:param name: Name of the Structure
:type fields: :class:`tuple` of (:class:`str`, :class:`DataDefinition`)
:param fields: A tuple consisting of the field name and the field
definition for all the fields inside this StructDefinition
"""
if not name:
raise ValueError('Struct name may not be None or empty string')
DataDefinition.__init__(self, data_type)
self.name = name
self._keys = [k for (k, _) in fields]
self._dict = dict(fields)
[docs] def new_value(self):
"""
Create a new StructValue
:rtype: :class:`vmware.vapi.data.value.StructValue`
:return: Newly created StructValue
"""
return data_value_factory(self.type, self.name)
[docs] def get_field_names(self):
"""
Returns the list of field names in this struct definition. The ordering
of fields is not preserved.
:rtype: :class:`list` of :class:`str`
:return: List of field names in this struct definition
"""
return self._keys
[docs] def get_field(self, field):
"""
Returns the field definition of the specified field
:rtype: :class:`DataDefinition`
:return: field definition of the specified field
"""
return self._dict.get(field)
[docs] def validate(self, other):
"""
Apart from the validation checks specified in the validate
method of DataDefinition class, this method does some additional checks
Validation will fail if
- the name of the input StructValue does not match the name of this
StructDefinition.
- any of the fields (either required or optional) in this StructDefinition
are not present in the input StructValue
- the validation fails for any field value in the input StructValue with
its corresponding definition in this StructDefinition
The method performs inclusive validation. i.e. If there are any extra
fields in the input StructValue which are not present in the
StructDefinition, validation will not fail.
:type other: :class:`vmware.vapi.data.value.StructValue`
:param other: StructValue to be validated
:rtype: :class:`list` of :class:`vmware.vapi.message.Message` of ``None``
:return: a stack of messages indicating why the value is not an instance
of this data-definition, or None if the value is an instance of
this data-definition
"""
errors = DataDefinition.validate(self, other)
if errors:
return errors
if (other.name != self.name):
# Remove the following if condition in R28
# To handle old client talking to new server
if self.name in [MAP_ENTRY, OPERATION_INPUT]:
pass
else:
msg = message_factory.get_message(
'vapi.data.structure.name.mismatch',
self.name, other.name)
return [msg]
for field in self._keys:
if (not other.has_field(field) and
self._dict.get(field).type != Type.OPTIONAL):
msg = message_factory.get_message(
'vapi.data.structure.field.missing',
self.name, field)
return [msg]
field_def = self._dict.get(field)
field_val = other.get_field(field)
errors = field_def.validate(field_val)
if errors:
msg = message_factory.get_message(
'vapi.data.structure.field.invalid',
field, self.name)
return [msg] + errors
return None
[docs] def complete_value(self, value):
"""
Fill out all the unset optional fields in a structure
based on the StructDefinition
:type value: :class:`vmware.vapi.data.value.StructValue`
:param value: Input Struct Value
"""
assert(value.type == self.type)
assert(value is not None)
for field in self._keys:
field_def = self.get_field(field)
if value.has_field(field):
# Complete the optional values in elements as well
field_def.complete_value(value.get_field(field))
elif field_def.type == Type.OPTIONAL:
# If field is not present and it is optional, fill it
value.set_field(field, field_def.new_value())
def __eq__(self, other):
if not isinstance(other, StructDefinition):
return NotImplemented
if not (DataDefinition.__eq__(self, other) and other.name == self.name):
return False
for field in self._keys:
other_field_def = other.get_field(field)
if not other_field_def:
return False
field_def = self.get_field(field)
if field_def != other_field_def:
return False
return True
# Classes that override __eq__ should define __hash__ to make
# its instances usable in hashed collections
def __hash__(self):
return DataDefinition.__hash__(self)
def __repr__(self):
fields = ", ".join(["%s=%s" % (field, repr(self._dict.get(field)))
for field in sorted(self._keys)])
return '%s(name=%s, fields={%s})' % (self.__class__.__name__,
repr(self.name),
fields)
[docs]class StructRefDefinition(DataDefinition):
"""
Reference to a StructDefinition. If the reference is resolved, it is
bound to a specific StructDefinition target. If the reference is
unresolved, its target is None.
:type name: :class:`str`
:ivar name: Structure name
"""
def __init__(self, name, definition=None):
"""
Initialize StructRefDefinition
:type name: :class:`str`
:param name: Structure name
:type definition: :class:`DataDefinition`
:param definition: If definition is passed, it creates a resolved
reference
"""
if not name:
raise ValueError('Struct name may not be None or empty string')
self.name = name
self._definition = definition
DataDefinition.__init__(self, Type.STRUCTURE_REF)
@property
def target(self):
"""
Returns the target structure definition of this reference.
:rtype: :class:`DataDefinition` or ``None``
:return: The target of this reference. The value will be None for
unresolved reference
"""
return self._definition
@target.setter
[docs] def target(self, definition):
"""
Resolves the reference. An unresolved reference can be resolved exactly
once. A resolved reference cannot be re-resolved.
:type definition: :class:`DataDefinition`
:param definition: structure definition
:raise: :class:`vmware.vapi.exception.CoreException`: if the reference is
already resolved (already has) a target) or if the name of the
reference does not match the name of the definition
"""
if not definition:
raise ValueError('StructDefinition may not be None')
if self._definition:
msg = message_factory.get_message(
'vapi.data.structref.already.resolved', self.name)
logger.debug(msg)
raise CoreException(msg)
if self.name != definition.name:
msg = message_factory.get_message(
'vapi.data.structref.resolve.type.mismatch',
self.name, definition.name)
logger.debug(msg)
raise CoreException(msg)
self._definition = definition
[docs] def check_resolved(self):
"""
Check if the reference is resolved or not
"""
if self._definition is None:
msg = message_factory.get_message(
'vapi.data.structref.not.resolved',
self.name)
logger.debug(msg)
raise CoreException(msg)
[docs] def complete_value(self, value):
"""
Fill out all the unset optional fields in a structure
based on the resolved StructDefinition for this
StructRefDefinition.
:type value: :class:`vmware.vapi.data.value.StructValue`
:param value: Input StructValue
"""
self.check_resolved()
self._definition.complete_value(value)
[docs] def validate(self, other):
"""
Validate using the target if the reference is resolved
:type other: :class:`vmware.vapi.data.value.StructValue`
:param other: StructValue to be validated
:rtype: :class:`list` of :class:`vmware.vapi.message.Message` of ``None``
:return: a stack of messages indicating that the reference is not
resolved or why the value is not an instance of this
data-definition, or None if the value is an instance of
this data-definition
"""
try:
self.check_resolved()
except CoreException as err:
return err.messages
return self._definition.validate(other)
def __eq__(self, other):
if not isinstance(other, StructRefDefinition):
return NotImplemented
if not (DataDefinition.__eq__(self, other) and
other.name == self.name):
return False
return True
# Classes that override __eq__ should define __hash__ to make
# its instances usable in hashed collections
def __hash__(self):
return DataDefinition.__hash__(self)
def __repr__(self):
return 'StructRefDefinition(name=%s)' % self.name
[docs]class ErrorDefinition(StructDefinition):
"""
DataDefinition for errors
"""
def __init__(self, name, fields):
"""
Initialize ErrorDefinition
:type name: :class:`str`
:param name: Name of the Error
:type fields: :class:`tuple` of (:class:`str`, :class:`DataDefinition`)
:param fields: A tuple consisting of the field name and the field
definition for all the fields inside this
StructDefinition
"""
StructDefinition.__init__(self, name, fields, Type.ERROR)
[docs] def new_value(self):
"""
Create a new ErrorValue
:rtype: :class:`vmware.vapi.data.value.ErrorValue`
:return: Newly created ErrorValue
"""
return data_value_factory(self.type, self.name)
[docs]class OptionalDefinition(DataDefinition):
"""
An OptionalDefinition instance defines an optional type with a specified
element type
:type data_type: :class:`str`
:ivar type: String representation of the type
:type element_type: :class:`DataDefinition`
:ivar element_type: The type of the element that is optional
"""
def __init__(self, element_type):
"""
Initialize OptionalDefinition
:type element_type: :class:`vmware.vapi.data.type.Type`
:param element_type: Type of the DataDefinition
"""
if not element_type:
raise ValueError('Optional definition requires element definition')
DataDefinition.__init__(self, Type.OPTIONAL)
self.element_type = element_type
[docs] def new_value(self, value=None):
"""
Create and return a new :class:`OptionalValue` using this
optional-definition.
:type value: :class:`vmware.vapi.data.value.DataValue`
:param value: The element value
:rtype: :class:`vmware.vapi.data.value.OptionalValue`
:return: A new optional value using the given data-definition
"""
return data_value_factory(self.type, value)
[docs] def validate(self, value):
"""
Apart from the validation checks specified in the validate
method of DataDefinition class, this method does some additional checks.
Since this is an OptionalValue, validation will succeed if the
element value is None. If the element value is not None, validation
will fail if element in the OptionalValue does not validate against
the DataDefinition of the element_type of this OptionalDefinition.
:type other: :class:`vmware.vapi.data.value.OptionalValue`
:param other: OptionalValue to be validated
:rtype: :class:`list` of :class:`vmware.vapi.message.Message`
:return: a stack of messages indicating why the value is not an instance
of this data-definition, or None if the value is an instance of
this data-definition
"""
errors = DataDefinition.validate(self, value)
if errors:
return errors
if value.value is None:
# None is a valid value for optional
pass
elif value.is_set():
errors = self.element_type.validate(value.value)
if errors:
msg = message_factory.get_message('vapi.data.optional.validate')
return [msg] + errors
return None
[docs] def complete_value(self, value):
"""
Fill the optional values inside StructValues
:type value: :class:`vmware.vapi.data.value.OptionalValue`
:param value: DataValue
"""
assert(value.type == Type.OPTIONAL)
if value.is_set():
self.element_type.complete_value(value.value)
def __eq__(self, other):
if not isinstance(other, OptionalDefinition):
return NotImplemented
return (DataDefinition.__eq__(self, other) and
self.element_type == other.element_type)
# Classes that override __eq__ should define __hash__ to make
# its instances usable in hashed collections
def __hash__(self):
return DataDefinition.__hash__(self)
def __repr__(self):
return "OptionalDefinition(element_type=%s)" % repr(self.element_type)
[docs]class SecretDefinition(SingletonDefinition):
"""
DataDefinition for Secrets. Only strings are allowed to be secrets.
"""
def __init__(self):
"""
Initialize SecretDefinition
"""
SingletonDefinition.__init__(self, Type.SECRET)
[docs] def new_value(self, value=""):
"""
Create a new SecretValue
:rtype: :class:`vmware.vapi.data.value.SecretValue`
:return: Newly created SecretValue
"""
return data_value_factory(self.type, value)
[docs]class SimpleDefinitionVisitor(VapiVisitor):
"""
Base no-op implementation of a definition visitor
"""
def __init__(self):
VapiVisitor.__init__(self, 'Definition')
[docs] def visit_void(self, defn):
"""
Visit a VoidDefinition
:type defn: :class:`VoidDefinition`
:param defn: Data definition
"""
raise NotImplementedError
[docs] def visit_integer(self, defn):
"""
Visit a IntegerDefinition
:type defn: :class:`IntegerDefinition`
:param defn: Data definition
"""
raise NotImplementedError
[docs] def visit_double(self, defn):
"""
Visit a DoubleDefinition
:type defn: :class:`DoubleDefinition`
:param defn: Data definition
"""
raise NotImplementedError
[docs] def visit_string(self, defn):
"""
Visit a StringDefinition
:type defn: :class:`StringDefinition`
:param defn: Data definition
"""
raise NotImplementedError
[docs] def visit_opaque(self, defn):
"""
Visit a OpaqueDefinition
:type defn: :class:`OpaqueDefinition`
:param defn: Data definition
"""
raise NotImplementedError
[docs] def visit_blob(self, defn):
"""
Visit a BlobDefinition
:type defn: :class:`BlobDefinition`
:param defn: Data definition
"""
raise NotImplementedError
[docs] def visit_boolean(self, defn):
"""
Visit a BooleanDefinition
:type defn: :class:`BooleanDefinition`
:param defn: Data definition
"""
raise NotImplementedError
[docs] def visit_list(self, defn):
"""
Visit a ListDefinition
:type defn: :class:`ListDefinition`
:param defn: Data definition
"""
raise NotImplementedError
[docs] def visit_struct(self, defn):
"""
Visit a StructDefinition
:type defn: :class:`StructDefinition`
:param defn: Data definition
"""
raise NotImplementedError
[docs] def visit_error(self, defn):
"""
Visit an ErrorDefinition
:type defn: :class:`ErrorDefinition`
:param defn: Data definition
"""
raise NotImplementedError
[docs] def visit_optional(self, defn):
"""
Visit a OptionalDefinition
:type defn: :class:`OptionalDefinition`
:param defn: Data definition
"""
raise NotImplementedError
[docs] def visit_secret(self, defn):
"""
Visit a SecretDefinition
:type defn: :class:`SecretDefinition`
:param defn: Data definition
"""
raise NotImplementedError
[docs] def visit_struct_ref(self, defn):
"""
Visit a StructRefDefinition
:type defn: :class:`StructRefDefinition`
:param defn: StructRefDefinition object
"""
raise NotImplementedError
# vapi type name to vapi type definition map
data_type_to_definition_map = {
Type.INTEGER: IntegerDefinition,
Type.DOUBLE: DoubleDefinition,
Type.BOOLEAN: BooleanDefinition,
Type.STRING: StringDefinition,
Type.BLOB: BlobDefinition,
Type.LIST: ListDefinition,
Type.STRUCTURE: StructDefinition,
Type.OPTIONAL: OptionalDefinition,
Type.VOID: VoidDefinition,
Type.OPAQUE: OpaqueDefinition,
Type.SECRET: SecretDefinition,
Type.ERROR: ErrorDefinition,
Type.STRUCTURE_REF: StructRefDefinition,
Type.DYNAMIC_STRUCTURE: DynamicStructDefinition,
}
[docs]def data_definition_factory(data_type, *args, **kwargs):
"""
data definition factory
:type data_type: :class:`str`
:param data_type: Type name defined in vmware.vapi.data.type
:type args: :class:`set`
:param args: Positional arguments to data definition constructor
:type kwargs: :class:`dict`
:param kwargs: Dict arguments to data definition constructor
"""
constructor = data_type_to_definition_map.get(data_type)
return constructor(*args, **kwargs)
[docs]class ReferenceResolver(object):
"""
Resolves all the StructRefDefinition objects
"""
def __init__(self):
"""
Initialize ReferenceResolver
"""
self._definitions = {}
self._references = []
[docs] def add_definition(self, definition):
"""
Adds a new structure definition to the context
:type definition: :class:`StructDefinition`
:param definition: StructDefinition
"""
self._definitions[definition.name] = definition
[docs] def add_reference(self, reference):
"""
Adds a new structure refernce to the context
:type refernce: :class:`StructRefDefinition`
:param refernce: StructRefDefinition
"""
self._references.append(reference)
[docs] def is_defined(self, name):
"""
Determines whether the context contains a definition for the specified
structure
:rtype: :class:`bool`
:return: True if the structure is already defined, false otherwise
"""
return name in self._definitions
[docs] def get_definition(self, name):
"""
Determines whether the context contains a definition for the specified
structure
:rtype: :class:`StructDefinition`
:return: Definition if the structure if it is already defined, None otherwise
"""
if self.is_defined(name):
return self._definitions[name]
return None
[docs] def resolve(self):
"""
Traverses all references and resolves the unresolved ones.
"""
for reference in self._references:
if reference.target is None:
definition = self._definitions.get(reference.name)
if definition is None:
msg = message_factory.get_message(
'vapi.data.structref.structure.not.defined',
reference.name)
logger.debug(msg)
raise CoreException(msg)
reference.target = definition