.. _bag_book/trigger_resolver/triggers: I trigger di Bag ================ Le Bag sono dotate anche di un sistema di trigger, ovvero una parte di logica che gestisce l'invio e ricezione di eventi di notifica quando dei dati vengono scritti o modificati all'interno della Bag ad un dato *path* Questo sistema di trigger è basato sul concetto di *subscription* ovvero un collegamento tra un tipo di evento (update, insert, delete) ad un preciso *path* con una funzione di callback da invocare. I trigger possono essere definiti sia a livello di Bag he di BagNode usando in entrambi i casi il metodo ``subscribe`` Anche se si chiamano nello stesso modo hanno due signature differenti. - Bag.subscribe(update=callback1, insert=callback2, delete=callback3, any=callback4) - BagNode.subscribe(updval=callback1, updattr=callback2) Il metodo subscribe ------------------- La *subscription* di un tipo di evento significa che ogni volta che quell'evento avviene, una notifica viene propagata per tutti i livelli della bag e il gestore degli eventi provvederà ad invocare tutte le chiamate di callback interessate. >>> family = Bag() >>> family['Walt'] = Bag() >>> walt = family['Walt'] >>> walt['children'] = Bag() >>> walt['children.Mickey.weight'] = 32 >>> walt['children.Mickey.height'] = 53 >>> walt['children.Donald.height'] = 51 Ora definiamo delle funzioni di callback dette anche *eventhandler*. :: def onUpdate(node=None, pathlist=None, oldvalue=None, evt=None, **kwargs): if evt=='upd_value': print """My node at path: %s\n has been updated. Value changed from %s to %s \n""" %('.'.join(pathlist), oldvalue, node.getValue()) if evt=='upd_attrs': print 'My node at path: %s\n has been updated. attributes changed\n' def onDelete(node=None, pathlist=None, ind=None, **kwargs): print 'My node %s at path: %s\n has been deleted from position %i.\n' %(node.getLabel(), '.'.join(pathlist), ind) def onInsert(node=None, pathlist=None, **kwargs): print 'A new node has been inserted at path: %s \n' %('.'.join(pathlist)) Una funzione eventhandler deve ricevere i seguenti parametri +--------------------+------------------+-----------------------------------------------------------------+ | Parameter | Type | Description | +====================+==================+=================================================================+ | `node` | ``BagNode`` | Il nodo inserted/deleted/updated | +--------------------+------------------+-----------------------------------------------------------------+ | `pathlist` | ``list`` | Include the Bag subscribed's path linked to the node | | | | where the event was catched | +--------------------+------------------+-----------------------------------------------------------------+ | `oldvalue` | ``any`` | Negli updates il precedente valore del nodo | +--------------------+------------------+-----------------------------------------------------------------+ | `ind` | ``int`` | La posizione (index) del valore inserito o cancellato | +--------------------+------------------+-----------------------------------------------------------------+ | `evt` | ``string`` | Event type: insert, delete, upd_value, upd_attrs | +--------------------+------------------+-----------------------------------------------------------------+ Adesso usiamo il metodo subscribe per mettere insieme gli eventi ai metodi *eventhandler* >>> family.subscribe(update=onUpdate, insert=onInsert, delete=onDelete) >>> walt['children.Mickey.weight']=36 My node at path: Walt.children.Mickey.weight has been updated. Value changed from 32 to 36 >>> walt['children.Donald.weight']=31 A new node has been inserted at path: Walt.children.Donald >>> walt.delItem('children.Mickey.height') My node height at path: walt.children.Mickey has been deleted from position 2. Possiamo aggiungere quante sottoscrizioni vogliamo per lo stesso evento :: def onChange(node=None, evt=None, pathlist=None, **kwargs): print '%s on node %s at path %s'%(evt, node.getLabel(),('.'.join(pathlist) or 'nullpath')) >>> family.subscribe(any=onBagEvent) Il parametro"any" è equivalente ad impostare la stessa callback per tutti gli eventi. Ulteriori sottoscrizioni non vanno in override, questo significa che se per *update* assegno un'altra funzione ad ogni update vengono chiamate entrambe. >>> walt['children.Mickey.weight']=37 My node at path: Walt.children.Mickey.weight has been updated. Value changed from 32 to 37 update on node height at path Walt.children.Mickey.weight Dal momento che un evento è propagato lungo tutti i livelli gerarchici della bag, può innescare chiamate da tutte le Bag sottoscritte. :: def onNewChild(node=None, ind=None, **kwargs): print 'Greetings for %s, your son number %i \n' %(node.getLabel(), ind+1) >>> walt['children'].subscribe(insert=onNewChild) >>> walt['children.Goofy']=Bag() Greetings for Goofy, your son number 3 A new node has been inserted at path: Walt.children ins on node children at path Walt All the trigger functions are executed at different levels, as the event is catched. Unsubscribe Bag --------------- E' possibile annullare una subscription con il metodo unsubscribe() >>> Walt['children'].unsubscribe(insert=onNewChild) >>> family.unsubscribe(insert=onInsert) E così abbiamo eliminato la subscription agli eventi di inserimento. Trigger su BagNode ------------------- I trigger sulle Bag assumono che ciascun nodo si debba comportare come gli altri e a volte questo non basta. Ecco perché è possibile fare una *subscription* anche a livello di BagNode ottenendo una maggiore granularità. Dal momento che per aggiornamento di un nodo si può intendere sia di valore che di attributi è possibile specificare due diversi tipi di trigger -upd_value: quando viene aggiornato il valore -upd_attrs: quando vengono aggiornati gli attributi :: def onValueChange(node, info=None, evt=None): if evt == 'upd_value': print 'My value is changed from %s to %s \n' %(info, node.getValue()) if evt == 'upd_attrs': print 'My attributes: %s is/are changed \n' %(', '.join(info)) >>> Walt.getNode('children.Mickey.weight').subscribe(upd_value=onValueChange) >>> Walt['children.Mickey.weight']=55 My value is changed from 36 to 55 My node at path: Walt.children.Mickey.weight has been updated. Value changed from 36 to 55 .. sectionauthor:: Giovanni Porcari