# HG changeset patch # User Paul Boddie # Date 1455023872 -3600 # Node ID bb1b8e13ef4dfe075199bf69181da1e0f2e4a5fc # Parent f517090b2d2111561deaddba43dbdf4670c88c56 Removed explicit confirmation and retraction function usage, instead employing scheduling functions to obtain confirmation, retraction, locking and unlocking functions, with each distinct invocation occurring only once. diff -r f517090b2d21 -r bb1b8e13ef4d docs/wiki/Preferences --- a/docs/wiki/Preferences Tue Feb 09 12:19:13 2016 +0100 +++ b/docs/wiki/Preferences Tue Feb 09 14:17:52 2016 +0100 @@ -110,33 +110,6 @@ .. all event details }}} -=== confirmation_function === - - Default:: (none) - Alternatives:: (see below) - -Indicates the confirmation functions used by [[../Resources|resources]] to be -invoked when an event is scheduled. Such functions support certain scheduling -functions that require a record of scheduling activity. - -The `imiptools.handlers.scheduling` module contains the built-in confirmation -functions which include the following: - -{{{#!table -`add_to_quota` || add the details of an event to quota - .. records for the indicated quota group -== -`add_to_quota` ''`quota-group`'' -== -`add_to_quota_freebusy` || add the details of an event to - .. free/busy records stored by the indicated quota - .. group -== -`add_to_quota_freebusy` ''`quota-group`'' -}}} - -See also `retraction_function` and `scheduling_function`. - === event_refreshing === Default:: `never` @@ -294,33 +267,6 @@ minute values that correspond to permitted values in this participant's own time zone. -=== retraction_function === - - Default:: (none) - Alternatives:: (see below) - -Indicates the retraction functions used by [[../Resources|resources]] to be -invoked when an event is cancelled. Such functions support certain scheduling -functions that require a record of scheduling activity. - -The `imiptools.handlers.scheduling` module contains the built-in retraction -functions which include the following: - -{{{#!table -`remove_from_quota` || remove the details of an event from - .. quota records for the indicated quota group -== -`remove_from_quota` ''`quota-group`'' -== -`remove_from_quota_freebusy` || remove the details of an event - .. from free/busy records stored by the - .. indicated quota group -== -`remove_from_quota_freebusy` ''`quota-group`'' -}}} - -See also `confirmation_function` and `scheduling_function`. - === scheduling_function === Default:: `schedule_in_freebusy` @@ -373,5 +319,3 @@ The scheduling mechanism can be extended by implementing additional scheduling functions or by extending the handler framework directly. - -See also `confirmation_function` and `retraction_function`. diff -r f517090b2d21 -r bb1b8e13ef4d docs/wiki/Resources --- a/docs/wiki/Resources Tue Feb 09 12:19:13 2016 +0100 +++ b/docs/wiki/Resources Tue Feb 09 14:17:52 2016 +0100 @@ -17,92 +17,6 @@ <> -== Confirmation and Retraction Functions == - -Confirmation and retraction functions are used to update other resources and -systems with the details of scheduled events. When an event is successfully -scheduled (according to the scheduling functions), all registered confirmation -functions are invoked to perform such notifications. Similarly, when an event -is cancelled, all registered retraction functions are invoked to inform other -components of the removal of the event from schedules. - -The [[../Preferences#confirmation_function|confirmation_function]] and -[[../Preferences#retraction_function|retraction_function]] settings indicate -the behaviour of a resource when such circumstances arise. By themselves, -these settings do no more than keep a kind of journal of scheduling events, -but certain scheduling functions may build upon such journals to make -scheduling decisions. For example: - -{{{{#!table -'''All Functions''' || '''Decision Process''' -== - - -Scheduling functions: - -{{{ -check_quota -}}} - -Confirmation functions: - -{{{ -add_to_quota -}}} - -Retraction functions: - -{{{ -remove_from_quota -}}} - -|| - -{{{#!graphviz -//format=svg -//transform=notugly -digraph scheduling_decisions { - node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; - edge [tooltip="Scheduling decisions"]; - - subgraph { - rank=same; - mail [label="Incoming mail\nfrom vincent.vole@example.com",shape=folder,style=filled,fillcolor=cyan]; - cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; - } - - subgraph { - rank=same; - check_quota [label="Is allowed by quota?",shape=ellipse,style=filled,fillcolor=gold]; - quota [label="Quota for resource",shape=folder]; - quota_for_vole [label="...applying to\nvincent.vole@example.com",shape=folder]; - } - - schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; - - subgraph { - rank=same; - accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; - decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; - } - - add_to_quota [label="Add to quota",shape=ellipse,style=filled,fillcolor=darkorange]; - remove_from_quota [label="Remove from quota",shape=ellipse,style=filled,fillcolor=darkorange]; - - mail -> check_quota -> schedule -> accept; - check_quota -> decline [style=dashed]; - schedule -> add_to_quota -> quota; - quota -> quota_for_vole -> check_quota; - - cancel -> remove_from_quota -> quota; -} -}}} - -}}}} - -See the [[#Quota_Controls|quota controls]] documentation for more information -about applying quotas to resources. - == Scheduling Functions == The [[../Preferences#scheduling_function|scheduling_function]] setting @@ -441,10 +355,6 @@ === Quota Controls === -The [[#Confirmation_and_Retraction_Functions|confirmation and retraction functions]] -section provides an example of applying quotas to event participants. However, -this section describes the operation of the quota system in more detail. - In contrast to each user's stored information which consolidates information related to that user's own schedule, the quota system consolidates information related to the schedules of one or more resources, thus enabling observations @@ -515,9 +425,60 @@ The trivial case of applying quotas is to give a resource its own quota. This is achieved by not specifying any arguments to the `check_quota` scheduling -function or to the `add_to_quota` and `remove_from_quota` functions. See the -[[#Confirmation_and_Retraction_Functions|confirmation and retraction functions]] -section for an example of this. +function or to the `add_to_quota` and `remove_from_quota` functions. + +{{{{#!table +'''Scheduling Functions''' || '''Decision Process''' +== + + +{{{ +check_quota +}}} + +|| + +{{{#!graphviz +//format=svg +//transform=notugly +digraph scheduling_decisions { + node [shape=box,fontsize="13.0",fontname="Helvetica",tooltip="Scheduling decisions"]; + edge [tooltip="Scheduling decisions"]; + + subgraph { + rank=same; + mail [label="Incoming mail\nfrom vincent.vole@example.com",shape=folder,style=filled,fillcolor=cyan]; + cancel [label="Incoming cancellation",shape=folder,style=filled,fillcolor=cyan]; + } + + subgraph { + rank=same; + check_quota [label="Is allowed by quota?",shape=ellipse,style=filled,fillcolor=gold]; + quota [label="Quota for resource",shape=folder]; + quota_for_vole [label="...applying to\nvincent.vole@example.com",shape=folder]; + } + + schedule [label="Schedule event for resource",shape=ellipse,style=filled,fillcolor=gold]; + + subgraph { + rank=same; + accept [label="Accept",shape=folder,style=filled,fillcolor=cyan]; + decline [label="Decline",shape=folder,style=filled,fillcolor=cyan]; + } + + add_to_quota [label="Add to quota",shape=ellipse,style=filled,fillcolor=darkorange]; + remove_from_quota [label="Remove from quota",shape=ellipse,style=filled,fillcolor=darkorange]; + + mail -> check_quota -> schedule -> accept; + check_quota -> decline [style=dashed]; + schedule -> add_to_quota -> quota; + quota -> quota_for_vole -> check_quota; + + cancel -> remove_from_quota -> quota; +} +}}} + +}}}} ==== Common Resource Quotas ==== @@ -526,28 +487,14 @@ function invocations to pool their knowledge about their schedules. {{{{#!table -'''All Functions''' || '''Decision Process''' +'''Scheduling Functions''' || '''Decision Process''' == -Scheduling functions: - {{{ check_quota cars }}} -Confirmation functions: - -{{{ -add_to_quota cars -}}} - -Retraction functions: - -{{{ -remove_from_quota cars -}}} - || {{{#!graphviz @@ -611,28 +558,14 @@ scheduling decisions and are employed as follows: {{{{#!table -'''All Functions''' || '''Decision Process''' +'''Scheduling Functions''' || '''Decision Process''' == -Scheduling functions: - {{{ schedule_within_quota cars }}} -Confirmation functions: - -{{{ -add_to_quota_freebusy cars -}}} - -Retraction functions: - -{{{ -remove_from_quota_freebusy cars -}}} - || {{{#!graphviz diff -r f517090b2d21 -r bb1b8e13ef4d imiptools/handlers/resource.py --- a/imiptools/handlers/resource.py Tue Feb 09 12:19:13 2016 +0100 +++ b/imiptools/handlers/resource.py Tue Feb 09 14:17:52 2016 +0100 @@ -176,6 +176,13 @@ # Scheduling details. + def get_scheduling_functions(self): + + "Return the scheduling functions for the resource." + + return self.get_preferences().get("scheduling_function", + "schedule_in_freebusy").split("\n") + def schedule(self): """ @@ -185,39 +192,25 @@ invalid requests. """ - # Obtain a list of scheduling functions. - - functions = self.get_preferences().get("scheduling_function", - "schedule_in_freebusy").split("\n") - - return apply_scheduling_functions(functions, self) + return apply_scheduling_functions(self) def confirm_scheduling(self): "Confirm that this event has been scheduled." - functions = self.get_preferences().get("confirmation_function") - - if functions: - confirm_scheduling(functions.split("\n"), self) + confirm_scheduling(self) def finish_scheduling(self): "Finish the scheduling, unlocking resources where appropriate." - functions = self.get_preferences().get("scheduling_function", - "schedule_in_freebusy").split("\n") - - finish_scheduling(functions, self) + finish_scheduling(self) def retract_scheduling(self): "Retract this event from scheduling records." - functions = self.get_preferences().get("retraction_function") - - if functions: - retract_scheduling(functions.split("\n"), self) + retract_scheduling(self) class Event(ResourceHandler): diff -r f517090b2d21 -r bb1b8e13ef4d imiptools/handlers/scheduling/__init__.py --- a/imiptools/handlers/scheduling/__init__.py Tue Feb 09 12:19:13 2016 +0100 +++ b/imiptools/handlers/scheduling/__init__.py Tue Feb 09 14:17:52 2016 +0100 @@ -28,21 +28,21 @@ # Function application/invocation. -def apply_scheduling_functions(functions, handler): +def apply_scheduling_functions(handler): """ - Apply the given scheduling 'functions' in the current object of the given + Apply the scheduling functions for the current object of the given 'handler'. This function starts a transaction that should be finalised using the 'finish_scheduling' function. """ # First, lock the resources to be used. - start_scheduling(functions, handler) + start_scheduling(handler) # Obtain the actual scheduling functions with arguments. - schedulers = get_function_calls(functions, scheduling_functions) + schedulers = get_function_calls(handler.get_scheduling_functions(), scheduling_functions) # Then, invoke the scheduling functions. @@ -74,41 +74,40 @@ return response -def confirm_scheduling(functions, handler): +def confirm_scheduling(handler): """ - Confirm scheduling using the given listener 'functions' for the current - object of the given 'handler'. This function continues a transaction that - should be finalised using the 'finish_scheduling' function. + Confirm scheduling using confirmation functions for the current object of + the given 'handler'. This function continues a transaction that should be + finalised using the 'finish_scheduling' function. """ - # Obtain the actual listener functions with arguments. + # Obtain the actual confirmation functions with arguments. - functions = get_function_calls(functions, confirmation_functions) + functions = get_function_calls(handler.get_scheduling_functions(), confirmation_functions) apply_functions(functions, handler) -def retract_scheduling(functions, handler): +def retract_scheduling(handler): """ - Retract scheduling using the given listener 'functions' for the current - object of the given 'handler'. This function is a complete transaction in - itself. + Retract scheduling using retraction functions for the current object of the + given 'handler'. This function is a complete transaction in itself. """ # First, lock the resources to be used. - start_scheduling(functions, handler) + start_scheduling(handler) - # Obtain the actual listener functions with arguments. + # Obtain the actual retraction functions with arguments. - retractors = get_function_calls(functions, retraction_functions) - apply_functions(retractors, handler) + functions = get_function_calls(handler.get_scheduling_functions(), retraction_functions) + apply_functions(functions, handler) # Finally, unlock the resources. - finish_scheduling(functions, handler) + finish_scheduling(handler) -def start_scheduling(functions, handler): +def start_scheduling(handler): """ Apply locking functions for the given scheduling 'functions' and for the @@ -117,10 +116,10 @@ # Obtain functions to lock resources. - locks = get_function_calls(functions, locking_functions) - apply_functions(locks, handler) + functions = get_function_calls(handler.get_scheduling_functions(), locking_functions) + apply_functions(functions, handler) -def finish_scheduling(functions, handler): +def finish_scheduling(handler): """ Finish scheduling using the given scheduling 'functions' for the current @@ -129,24 +128,28 @@ # Obtain functions to unlock resources. - locks = get_function_calls(functions, unlocking_functions) - apply_functions(locks, handler) + functions = get_function_calls(handler.get_scheduling_functions(), unlocking_functions) + apply_functions(functions, handler) def apply_functions(functions, handler): """ Apply the given notification 'functions' for the current object of the given - 'handler'. + 'handler'. Where functions are provided more than once, they will be called + only once for each distinct set of arguments. """ + applied = set() + for fn, args in functions: # NOTE: Should signal an error for incorrectly configured resources. - if not fn: + if not fn or (fn, args) in applied: continue fn(handler, args) + applied.add((fn, args)) # Function lookup. @@ -169,7 +172,7 @@ for line in lines: parts = parse_line(line) - functions.append((registry.get(parts[0]), parts[1:])) + functions.append((registry.get(parts[0]), tuple(parts[1:]))) return functions diff -r f517090b2d21 -r bb1b8e13ef4d imiptools/handlers/scheduling/quota.py --- a/imiptools/handlers/scheduling/quota.py Tue Feb 09 12:19:13 2016 +0100 +++ b/imiptools/handlers/scheduling/quota.py Tue Feb 09 14:17:52 2016 +0100 @@ -340,28 +340,24 @@ locking_functions = { "check_quota" : lock_journal, - "remove_from_quota" : lock_journal, - "remove_from_quota_freebusy" : lock_journal, "schedule_across_quota" : lock_journal, } unlocking_functions = { "check_quota" : unlock_journal, - "remove_from_quota" : unlock_journal, - "remove_from_quota_freebusy" : unlock_journal, "schedule_across_quota" : unlock_journal, } # Registries of listener functions. confirmation_functions = { - "add_to_quota" : add_to_quota, - "add_to_quota_freebusy" : add_to_quota_freebusy, + "check_quota" : add_to_quota, + "schedule_across_quota" : add_to_quota_freebusy, } retraction_functions = { - "remove_from_quota" : remove_from_quota, - "remove_from_quota_freebusy" : remove_from_quota_freebusy, + "check_quota" : remove_from_quota, + "schedule_across_quota" : remove_from_quota_freebusy, } # vim: tabstop=4 expandtab shiftwidth=4 diff -r f517090b2d21 -r bb1b8e13ef4d tests/test_resource_invitation_constraints_quota.sh --- a/tests/test_resource_invitation_constraints_quota.sh Tue Feb 09 12:19:13 2016 +0100 +++ b/tests/test_resource_invitation_constraints_quota.sh Tue Feb 09 14:17:52 2016 +0100 @@ -18,12 +18,6 @@ schedule_in_freebusy check_quota $QUOTA EOF -cat > "$PREFS/$USER1/confirmation_function" < "$PREFS/$USER1/retraction_function" < "$PREFS/$USER2/TZID" @@ -32,12 +26,6 @@ schedule_in_freebusy check_quota $QUOTA EOF -cat > "$PREFS/$USER2/confirmation_function" < "$PREFS/$USER2/retraction_function" < "$JOURNAL/$QUOTA/limits" @@ -191,28 +179,12 @@ schedule_across_quota $QUOTA check_quota $QUOTA EOF -cat > "$PREFS/$USER1/confirmation_function" < "$PREFS/$USER1/retraction_function" < "$PREFS/$USER2/scheduling_function" < "$PREFS/$USER2/confirmation_function" < "$PREFS/$USER2/retraction_function" < "$PREFS/$USER/confirmation_function" < "$PREFS/$USER/retraction_function" < "$PREFS/$USER1/confirmation_function" < "$PREFS/$USER1/retraction_function" < "$PREFS/$USER2/TZID" @@ -37,12 +31,6 @@ schedule_in_freebusy check_quota $QUOTA EOF -cat > "$PREFS/$USER2/confirmation_function" < "$PREFS/$USER2/retraction_function" < "$JOURNAL/$QUOTA/limits" <