def WriteProperty(self, obj, value, arrayIndex=None, priority=None, direct=False):
        if _debug:
            Property._debug("WriteProperty(%s) %s %r arrayIndex=%r priority=%r direct=%r",
                self.identifier, obj, value, arrayIndex, priority, direct
                )

        if direct:
            if _debug: Property._debug("    - direct write")
        else:
            # see if it must be provided
            if not self.optional and value is None:
                raise ValueError("%s value required" % (self.identifier,))

            # see if it can be changed
            if not self.mutable:
                if _debug: Property._debug("    - property is immutable")
                raise ExecutionError(errorClass='property', errorCode='writeAccessDenied')

            # if changing the length of the array, the value is unsigned
            if arrayIndex == 0:
                if not Unsigned.is_valid(value):
                    raise InvalidParameterDatatype("length of %s must be unsigned" % (
                            self.identifier,
                            ))

            # if it's atomic, make sure it's valid
            elif issubclass(self.datatype, AnyAtomic):
                if _debug: Property._debug("    - property is any atomic, checking value")
                if not isinstance(value, Atomic):
                    raise InvalidParameterDatatype("%s must be an atomic instance" % (
                            self.identifier,
                            ))

            elif issubclass(self.datatype, Atomic):
                if _debug: Property._debug("    - property is atomic, checking value")
                if not self.datatype.is_valid(value):
                    raise InvalidParameterDatatype("%s must be of type %s" % (
                            self.identifier, self.datatype.__name__,
                            ))

            # if it's an array, make sure it's valid regarding arrayIndex provided
            elif issubclass(self.datatype, Array):
                if _debug: Property._debug("    - property is array, checking subtype and index")

                # changing a single element
                if arrayIndex is not None:
                    # if it's atomic, make sure it's valid
                    if issubclass(self.datatype.subtype, Atomic):
                        if _debug: Property._debug("    - subtype is atomic, checking value")
                        if not self.datatype.subtype.is_valid(value):
                            raise InvalidParameterDatatype("%s must be of type %s" % (
                                    self.identifier, self.datatype.__name__,
                                    ))
                    # constructed type
                    elif not isinstance(value, self.datatype.subtype):
                        raise InvalidParameterDatatype("%s must be of type %s" % (
                                self.identifier, self.datatype.subtype.__name__
                                ))

                # replacing the array
                elif isinstance(value, list):
                    # check validity regarding subtype
                    for item in value:
                        # if it's atomic, make sure it's valid
                        if issubclass(self.datatype.subtype, Atomic):
                            if _debug: Property._debug("    - subtype is atomic, checking value")
                            if not self.datatype.subtype.is_valid(item):
                                raise InvalidParameterDatatype("elements of %s must be of type %s" % (
                                        self.identifier, self.datatype.subtype.__name__,
                                        ))
                        # constructed type
                        elif not isinstance(item, self.datatype.subtype):
                            raise InvalidParameterDatatype("elements of %s must be of type %s" % (
                                    self.identifier, self.datatype.subtype.__name__
                                    ))

                    # value is mutated into a new array
                    value = self.datatype(value)

            # if it's an array, make sure it's valid regarding arrayIndex provided
            elif issubclass(self.datatype, List):
                if _debug: Property._debug("    - property is list, checking subtype")

                # changing a single element
                if arrayIndex is not None:
                    raise ExecutionError(errorClass='property', errorCode='propertyIsNotAnArray')

                # replacing the array
                if not isinstance(value, list):
                    raise InvalidParameterDatatype("elements of %s must be of type %s" % (
                            self.identifier, self.datatype.subtype.__name__
                            ))

                # check validity regarding subtype
                for item in value:
                    # if it's atomic, make sure it's valid
                    if issubclass(self.datatype.subtype, Atomic):
                        if _debug: Property._debug("    - subtype is atomic, checking value")
                        if not self.datatype.subtype.is_valid(item):
                            raise InvalidParameterDatatype("elements of %s must be of type %s" % (
                                    self.identifier, self.datatype.subtype.__name__,
                                    ))
                    # constructed type
                    elif not isinstance(item, self.datatype.subtype):
                        raise InvalidParameterDatatype("elements of %s must be of type %s" % (
                                self.identifier, self.datatype.subtype.__name__
                                ))

                # value is mutated into a new list
                value = self.datatype(value)

            # some kind of constructed data
            elif not isinstance(value, self.datatype):
                if _debug: Property._debug("    - property is not atomic and wrong type")
                raise InvalidParameterDatatype("%s must be of type %s" % (
                        self.identifier, self.datatype.__name__,
                        ))

        # local check if the property is monitored
        is_monitored = self.identifier in obj._property_monitors

        if arrayIndex is not None:
            if not issubclass(self.datatype, Array):
                raise ExecutionError(errorClass='property', errorCode='propertyIsNotAnArray')

            # check the array
            arry = obj._values[self.identifier]
            if arry is None:
                raise RuntimeError("%s uninitialized array" % (self.identifier,))

            if is_monitored:
                old_value = _copy(arry)

            # seems to be OK, let the array object take over
            if _debug: Property._debug("    - forwarding to array")
            try:
                arry[arrayIndex] = value
            except IndexError:
                raise ExecutionError(errorClass='property', errorCode='invalidArrayIndex')
            except TypeError:
                raise ExecutionError(errorClass='property', errorCode='valueOutOfRange')

            # check for monitors, call each one with the old and new value
            if is_monitored:
                for fn in obj._property_monitors[self.identifier]:
                    if _debug: Property._debug("    - monitor: %r", fn)
                    fn(old_value, arry)

        else:
            if is_monitored:
                old_value = obj._values.get(self.identifier, None)

            # seems to be OK
            obj._values[self.identifier] = value

            # check for monitors, call each one with the old and new value
            if is_monitored:
                for fn in obj._property_monitors[self.identifier]:
                    if _debug: Property._debug("    - monitor: %r", fn)
                    fn(old_value, value)