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'
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
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
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)