def decode_result(path, rawdata, content_type):
    # TODO: rst rawdata can not be handled in the program, i.e. GSCL register
    # if content_type not in ("application/xml", "application/json"):
    #     return RetrieveResponseConfirmation(rawdata,
    #                                         content_type=content_type)
    if not rawdata:
        return None, None

    try:
        serializer = get_serializer(content_type)
    except SCLBadRequest:
        # TODO: kca: here we assume that this means a partial retrieve on the
        # content of a contentInstance. need a better check for that
        return rawdata, content_type
    try:
        data = serializer.load(rawdata)
        """:type : dict """
    except SCLValueError:
        # TODO: kca: here we assume that this means a partial retrieve on the
        # content of a contentInstance. need a better check for that
        # TODO: kca: theoretically this case should be handled by
        # the check above, but XML serializer is very picky
        return rawdata, content_type

    try:
        data = serializer.parse_representation(data)
        """:type : Resource"""
    except ModelTypeError:
        # TODO: kca: here we assume that ModelTypeError means we did a partial
        # retrieve. need a better check for that
        pass
    else:
        # data is a resource
        data.path = path
    return data, None
def encode_request_indication_payload(request_indication,
                                      target_content_type=None):
    # TODO: pretty handling

    logger.debug("Encoding request indication: %s", request_indication)

    data = request_indication.resource

    if data is None:
        return None, None

    content_type = request_indication.content_type
    if content_type:
        return content_type, data

    target_content_type = target_content_type or openmtc_scl.api.config[
        "etsi"]["default_content_type"]

    serializer = get_serializer(target_content_type)

    data = serializer.encode_values(request_indication.typename,
                                    data,
                                    filter_none=True)

    return target_content_type + "; charset=utf-8", data
    def _parse_pa_content(self, request_indication, resource):
        if request_indication.content_type:
            data = request_indication.resource

            serializer = get_serializer(request_indication.content_type)
            data = serializer.load_pa_content(data)

            request_indication.resource = data
            request_indication.content_type = None
def decode_content(request_indication):
    resource = request_indication.resource
    try:
        resource = request_indication.resource = resource.read()
    except AttributeError:
        pass

    serializer = get_serializer(request_indication.content_type)
    # TODO: kca: properly handle encodings
    return serializer.decode_resource_values(resource)
def serialize_generic_result(result,
                             accept=None,
                             pretty=False,
                             prefer_xml=False):
    try:
        data = result.payload
    except:
        data = None

    if data is None:
        return None, None

    try:
        content_type = result.content_type
        fields = None
    except AttributeError:
        content_type = None
        fields = result.fields

    if content_type:
        # TODO: still honor accept header here
        return content_type, data

    # TODO: optimize
    if accept:
        parsed_accept_header = parse_accept_header(accept, OpenMTCAccept)
        """:type : Accept"""
        supported = get_supported_content_types()
        accepted_type = parsed_accept_header.best_match(supported)
        if not accepted_type:
            raise SCLNotAcceptable(
                "%s is not supported. "
                "Supported content types are: %s" %
                (accept, ', '.join(get_supported_content_types())))
    elif prefer_xml:
        # TODO: use config["default_content_type"]
        accepted_type = "application/xml"
    else:
        accepted_type = "application/json"

    serializer = get_serializer(accepted_type)

    data = serializer.encode(data, pretty=pretty, fields=fields)

    return accepted_type + "; charset=utf-8", data
            def cb(respconf, correlationID, contactURI):
                # This implies HTTP makes a second request
                self.logger.debug(
                    "MethodDomain is called back, storing req "
                    "with correlationID %s", correlationID)
                if contactURI:
                    self.logger.debug("Contact uri detected %s", contactURI)
                    # Send a notify with the resp encapsulated
                    try:
                        # TODO: check with Alex if this will work!
                        resource = respconf.resource
                        content_type = respconf.content_type
                    except AttributeError:
                        # removed content type, makes no sense without resource
                        # but: does it make sense to send an empty notify in
                        # this case?
                        resource = None
                        content_type = None
                    else:
                        if not content_type:
                            # only serialize if needed
                            # does it make sense to use default ct?
                            content_type = self.default_content_type
                            serializer = get_serializer(content_type)
                            resource = serializer.encode(resource)

                    # TODO : Add statusCode in Notify Request
                    #  (cf TS 102 921, C.4.8)
                    notify_request = NotifyRequestIndication(
                        path=contactURI,
                        resource=resource,
                        content_type=content_type)
                    notify_request.correlationID = correlationID
                    # Hack to make a difference between this notify and an saf one.
                    # (They both include a correlationID)
                    notify_request.contactURI = "final_result"
                    self._api.send_request_indication(notify_request)
                else:
                    # Add the response to the reply queue
                    # self.req_storage[correlationID] = respconf
                    self.save_resp(correlationID, respconf)
def encode_error(error, accept=None, pretty=False):
    # TODO: optimize
    if accept:
        parsed_accept_header = parse_accept_header(accept, OpenMTCAccept)
        """:type : Accept"""
        supported = get_supported_content_types()
        accepted_type = parsed_accept_header.best_match(supported)
        if not accepted_type:
            raise SCLNotAcceptable(
                "%s is not supported. "
                "Supported content types are: %s" %
                (accept, ', '.join(get_supported_content_types())))
    else:
        # even if no accept header was found, default-encode to json
        # TODO: use config["default_content_type"]
        accepted_type = "application/json"

    serializer = get_serializer(accepted_type)

    data = serializer.encode_error(error, pretty=pretty)
    return accepted_type, data
    def _handle_aggregate(self, request_indication):
        base_to_remove = "/m2m/aggregate"
        path = request_indication.path[len(base_to_remove):]
        self.logger.debug("aggregated path: %s", path)

        ct = request_indication.content_type
        if ct:
            serializer = get_serializer(ct)

            typename, resource = serializer.decode(request_indication.resource)
            self.logger.debug("decoded resource: %s - %s", resource, typename)

            data = resource
            data["requestingEntity"] = request_indication.requestingEntity

        else:
            data = request_indication.resource
            data["requestingEntity"] = request_indication.requestingEntity

        p = Promise()

        # TODO: use dict.get()
        if path in aggregate_data.ncolmap and \
                len(aggregate_data.ncolmap[path]) > 0:
            aggregate_data.ncolmap[path].append(data)
            aggregate_data.ncolpromises[path].append(p)
            self.logger.debug("added notification to database, size: %s",
                              len(aggregate_data.ncolmap[path]))
        else:
            self.logger.debug("no pending notifies for %s", path)
            aggregate_data.ncolmap[path] = [data]
            aggregate_data.ncolpromises[path] = [p]
            try:
                dtol = aggregate_data.ncoldelaytolerance[path]
            except KeyError:
                # FIXME put default delay tolerance somewhere
                dtol = 10

            def dtol_handler():
                self.logger.debug("dtol_handler FIRING")
                # payload = NotifyCollection()

                payload = list(aggregate_data.ncolmap[path])

                promises = list(aggregate_data.ncolpromises[path])

                # remove path from maps
                aggregate_data.ncolmap.pop(path, None)
                aggregate_data.ncolpromises.pop(path, None)

                notify_req_ind = NotifyRequestIndication(
                    path, {"notify": payload}, typename="notifyCollection")

                self.logger.debug("dtol_handler sends collection: %s", payload)

                def finished(response):
                    result = NotifyResponseConfirmation()
                    for pending_p in promises:
                        pending_p.fulfill(result)

                return self._api.send_request_indication(notify_req_ind) \
                    .then(finished)

            self.logger.debug("starting dtol_handler, countdown: %s seconds",
                              dtol)
            self._api.set_timer(dtol, dtol_handler)

        return p