Example #1
0
class FragmentRequest(DeliveryRequest):
    def __init__(self):
        """
        Prepares the pattern graph object which will store the one that is contained in the
        request
        """
        super(FragmentRequest, self).__init__()
        self.__request_graph = CGraph()
        self.__request_graph.bind('stoa', STOA)
        self.__preferred_labels = set([])
        self.__variable_labels = {}
        self._graph_pattern = GraphPattern()

        # Copy Agora prefixes to the pattern graph
        try:
            prefixes = agora_client.prefixes
            for p in prefixes:
                self.__request_graph.bind(p, prefixes[p])
        except Exception, e:
            raise EnvironmentError(e.message)
    def _build(self):
        log.debug('Building a response for request number {}'.format(self._request_id))
        result = self.result_set()
        enrichment = self.sink.enrichment_data
        object_links = {}

        for res in result:
            links = dict(map(lambda (l, v): (v.lstrip('?'), l), enrichment.links))
            for link in links:
                try:
                    object_link = URIRef(res[link])
                    if links[link] not in object_links:
                        object_links[links[link]] = set([])
                    object_links[links[link]].add(object_link)
                except KeyError:
                    pass

        graph = CGraph()
        resp_node = BNode('#response')
        graph.add((resp_node, RDF.type, STOA.EnrichmentResponse))
        graph.add((resp_node, STOA.messageId, Literal(str(uuid.uuid4()), datatype=TYPES.UUID)))
        graph.add((resp_node, STOA.responseTo, Literal(self.sink.message_id, datatype=TYPES.UUID)))
        graph.add((resp_node, STOA.responseNumber, Literal("1", datatype=XSD.unsignedLong)))
        graph.add((resp_node, STOA.targetResource, self.sink.enrichment_data.target))
        graph.add((resp_node, STOA.submittedOn, Literal(datetime.now())))
        curator_node = BNode('#curator')
        graph.add((resp_node, STOA.submittedBy, curator_node))
        graph.add((curator_node, RDF.type, FOAF.Agent))
        graph.add((curator_node, STOA.agentId, LIT_AGENT_ID))
        addition_node = BNode('#addition')
        graph.add((resp_node, STOA.additionTarget, addition_node))
        graph.add((addition_node, RDF.type, STOA.Variable))
        if object_links:
            for link, v in self.sink.enrichment_data.links:
                [graph.add((addition_node, link, o)) for o in object_links[link]]
        yield graph.serialize(format='turtle'), {'state': 'end', 'source': 'store',
                                                 'response_to': self.sink.message_id,
                                                 'submitted_on': calendar.timegm(datetime.now().timetuple()),
                                                 'submitted_by': self.sink.submitted_by,
                                                 'format': 'turtle'}

        self.sink.delivery = 'sent'
Example #3
0
def build_reply(template, reply_to, comment=None):
    """
    :param template: A specific message template graph
    :param reply_to: Recipient Agent UUID
    :param comment: Optional comment
    :return: The reply graph
    """
    reply_graph = CGraph()
    root_node = None
    for (s, p, o) in template:
        if o == STOA.Root:
            root_node = s
        else:
            reply_graph.add((s, p, o))

    reply_graph.add((root_node, STOA.responseTo, Literal(reply_to, datatype=TYPES.UUID)))
    reply_graph.set((root_node, STOA.submittedOn, Literal(datetime.now())))
    reply_graph.set((root_node, STOA.messageId, Literal(str(uuid.uuid4()), datatype=TYPES.UUID)))
    if comment is not None:
        reply_graph.set((root_node, RDFS.comment, Literal(comment, datatype=XSD.string)))
    for (prefix, ns) in template.namespaces():
        reply_graph.bind(prefix, ns)
    return reply_graph
Example #4
0
def _build_reply_templates():
    """
    :return: Accept and Failure message templates
    """
    accepted = CGraph()
    failure = CGraph()
    response_node = BNode()
    agent_node = BNode()
    accepted.add((response_node, RDF.type, STOA.Root))
    accepted.add((response_node, RDF.type, STOA.Accepted))
    accepted.add((agent_node, RDF.type, FOAF.Agent))
    accepted.add((response_node, STOA.responseNumber, Literal("0", datatype=XSD.unsignedLong)))
    accepted.add((response_node, STOA.submittedBy, agent_node))
    accepted.add(
        (agent_node, STOA.agentId, LIT_AGENT_ID))
    accepted.bind('types', TYPES)
    accepted.bind('stoa', STOA)
    accepted.bind('foaf', FOAF)

    for triple in accepted:
        failure.add(triple)
    failure.set((response_node, RDF.type, STOA.Failure))
    for (prefix, ns) in accepted.namespaces():
        failure.bind(prefix, ns)

    return accepted, failure
Example #5
0
class FragmentRequest(DeliveryRequest):
    def __init__(self):
        """
        Prepares the pattern graph object which will store the one that is contained in the
        request
        """
        super(FragmentRequest, self).__init__()
        self.__request_graph = CGraph()
        self.__request_graph.bind('stoa', STOA)
        self.__preferred_labels = set([])
        self.__variable_labels = {}
        self._graph_pattern = GraphPattern()

        # Copy Agora prefixes to the pattern graph
        try:
            prefixes = _agora_client.prefixes
            for p in prefixes:
                self.__request_graph.bind(p, prefixes[p])
        except Exception as e:
            raise EnvironmentError(e.message)

    def _extract_content(self, request_type=None):
        super(FragmentRequest, self)._extract_content(request_type)

        # Firstly, it looks for all Variables that are inside the request
        variables = set(self._graph.subjects(RDF.type, STOA.Variable))
        if not variables:
            raise SyntaxError('There are no variables specified for this request')
        _log.debug(
            'Found {} variables in the the fragment pattern'.format(len(variables)))

        # Secondly, try to identify all links between variables (avoiding cycles)
        visited = set([])
        for v in variables:
            self.__request_graph.add((v, RDF.type, STOA.Variable))
            self.__follow_variable(v, visited=visited)

        # Thirdly, the request graph is filtered and the request pattern only contains
        # the relevant nodes and their relations

        # Finally, an Agora-compliant Graph Pattern is created and offered as a property
        self.__build_graph_pattern()

        _log.debug('Extracted (fragment) pattern graph:\n{}'.format(self.__request_graph.serialize(format='turtle')))

        q_res = self._graph.query("""SELECT ?r ?ud ?ag ?ue WHERE {
                                OPTIONAL { ?r stoa:expectedUpdatingDelay ?ud }
                                OPTIONAL { ?r stoa:allowGeneralisation ?ag }
                                OPTIONAL { ?r stoa:updateOnEvents ?ue }
                             }""")
        q_res = list(q_res)
        if len(q_res) > 1:
            raise SyntaxError('Wrong number of parameters were defined')

        fragment_params = q_res.pop()
        if any(fragment_params):
            try:
                parent_node, updating_delay, allow_gen, update_events = fragment_params
                if parent_node != self._request_node:
                    raise SyntaxError('Invalid parent node for stoa:expectedUpdatingDelay')
                if updating_delay is not None:
                    self._fields['updating_delay'] = updating_delay.toPython()
                if allow_gen is not None:
                    self._fields['allow_gen'] = allow_gen.toPython()
                if update_events is not None:
                    self._fields['update_events'] = update_events.toPython()
            except IndexError:
                pass

    def __n3(self, elm):
        """
        :param elm: The element to be n3-formatted
        :return: The n3 representation of elm
        """
        return elm.n3(self.__request_graph.namespace_manager)

    def __follow_variable(self, variable_node, visited=None):
        """
        Recursively follows one variable node of the request graph
        :param variable_node: Starting node
        :param visited: Track of visited variable nodes
        :return:
        """

        def add_pattern_link(node, triple):
            type_triple = (node, RDF.type, STOA.Variable)
            condition = type_triple in self._graph
            if condition:
                self.__request_graph.add(type_triple)
            elif isinstance(node, URIRef):
                condition = True
            if condition:
                if triple not in self.__request_graph:
                    self.__request_graph.add(triple)
                    _log.debug('New pattern link: {}'.format(triple))
            return condition

        if visited is None:
            visited = set([])
        visited.add(variable_node)
        subject_pattern = self._graph.subject_predicates(variable_node)
        for (n, pr) in subject_pattern:
            if add_pattern_link(n, (n, pr, variable_node)) and n not in visited:
                self.__follow_variable(n, visited)

        object_pattern = self._graph.predicate_objects(variable_node)
        for (pr, n) in object_pattern:
            if add_pattern_link(n, (variable_node, pr, n)):
                if n not in visited:
                    self.__follow_variable(n, visited)
            elif n != STOA.Variable:
                self.__request_graph.add((variable_node, pr, n))

    def __build_graph_pattern(self):
        """
        Creates a GraphPattern with all the identified (Agora compliant) triple patterns
        in the request graph
        """

        def preferred_label():
            # Each variable may have a property STOA.label that specifies its desired label
            labels = list(self.__request_graph.objects(v, STOA.label))
            p_label = labels.pop() if len(labels) == 1 else ''
            if p_label:
                self.__preferred_labels.add(str(p_label))
            return p_label if p_label.startswith('?') else '?v{}'.format(i)

        # Populates a dictionary with all variables and their labels
        variables = self.__request_graph.subjects(RDF.type, STOA.Variable)
        for i, v in enumerate(variables):
            self.__variable_labels[v] = preferred_label()

        # For each variable, generates one triple pattern per relation with other nodes as either subject or object
        for v in self.__variable_labels.keys():
            v_in = self.__request_graph.subject_predicates(v)
            for (s, pr) in v_in:
                s_part = self.__variable_labels[s] if s in self.__variable_labels else self.__n3(s)
                self._graph_pattern.add(u'{} {} {}'.format(s_part, self.__n3(pr), self.__variable_labels[v]))
            v_out = self.__request_graph.predicate_objects(v)
            for (pr, o) in [_ for _ in v_out if _[1] != STOA.Variable and not _[0].startswith(STOA)]:
                o_part = self.__variable_labels[o] if o in self.__variable_labels else (
                    '"{}"'.format(o) if isinstance(o, Literal) else self.__n3(o))
                p_part = self.__n3(pr) if pr != RDF.type else 'a'
                self._graph_pattern.add(u'{} {} {}'.format(self.__variable_labels[v], p_part, o_part))

    @property
    def pattern(self):
        """
        :return: The request graph pattern
        """
        return self._graph_pattern

    @property
    def preferred_labels(self):
        """
        :return: The variable preferred labels
        """
        return self.__preferred_labels

    @property
    def variable_labels(self):
        """
        :return: All variable labels
        """
        return self.__variable_labels.values()

    def variable_label(self, n):
        label = self.__variable_labels.get(n, None)
        if isinstance(label, Literal):
            label = label.toPython()
        return label

    @property
    def updating_delay(self):
        return self._fields.get('updating_delay', None)

    @property
    def allow_generalisation(self):
        return self._fields.get('allow_gen', False)

    @property
    def update_on_events(self):
        return self._fields.get('update_events', False)