Upgrades this object to the type specified.

    AFF4 Objects can be upgraded on the fly to other type - As long as the new
    type is derived from the current type. This feature allows creation of
    placeholder objects which can later be upgraded to the fully featured
    object.

    Note: It is not allowed to downgrade an object if that would result in a
    loss of information (since the new object has a smaller schema). This method
    tries to store the new object with its new attributes and will fail if any
    attributes can not be mapped.

    Args:
       aff4_class: A string representing the new class.

    Returns:
       an instance of the new class with all the same attributes as this current
       object.

    Raises:
       ValueError: When the object to upgrade is locked.
       AttributeError: When the new object can not accept some of the old
       attributes.
       InstantiationError: When we cannot instantiate the object type class.

def Upgrade(self, aff4_class):
    """Upgrades this object to the type specified.

    AFF4 Objects can be upgraded on the fly to other type - As long as the new
    type is derived from the current type. This feature allows creation of
    placeholder objects which can later be upgraded to the fully featured
    object.

    Note: It is not allowed to downgrade an object if that would result in a
    loss of information (since the new object has a smaller schema). This method
    tries to store the new object with its new attributes and will fail if any
    attributes can not be mapped.

    Args:
       aff4_class: A string representing the new class.

    Returns:
       an instance of the new class with all the same attributes as this current
       object.

    Raises:
       ValueError: When the object to upgrade is locked.
       AttributeError: When the new object can not accept some of the old
       attributes.
       InstantiationError: When we cannot instantiate the object type class.
    """
    _ValidateAFF4Type(aff4_class)

    # We are already of the required type
    if self.__class__ == aff4_class:
      return self

    # Check that we have the right type.
    if not isinstance(aff4_class, type):
      raise InstantiationError("aff4_class=%s must be a type" % aff4_class)
    if not issubclass(aff4_class, AFF4Object):
      raise InstantiationError(
          "aff4_class=%s must be a subclass of AFF4Object." % aff4_class)

    # It's not allowed to downgrade the object
    if isinstance(self, aff4_class):
      # TODO(user): check what we should do here:
      #                 1) Nothing
      #                 2) raise
      #                 3) return self
      # Option 3) seems ok, but we need to be sure that we don't use
      # Create(mode='r') anywhere where code actually expects the object to be
      # downgraded.
      return self

    # NOTE: It is possible for attributes to become inaccessible here if the old
    # object has an attribute which the new object does not have in its
    # schema. The values of these attributes will not be available any longer in
    # the new object - usually because old attributes do not make sense in the
    # context of the new object.

    # Instantiate the class
    result = aff4_class(
        self.urn,
        mode=self.mode,
        clone=self,
        parent=self.parent,
        token=self.token,
        age=self.age_policy,
        object_exists=self.object_exists,
        follow_symlinks=self.follow_symlinks,
        aff4_type=self.aff4_type,
        mutation_pool=self.mutation_pool,
        transaction=self.transaction)
    result.symlink_urn = self.urn
    result.Initialize()

    return result