Title: E81 CSE 532S: Advanced Multi-Paradigm Software Development
1E81 CSE 532S Advanced Multi-Paradigm Software
Development
Interceptor Pattern
Venkita Subramonian, Christopher Gill, Morgan
Deters, Anand Krishnan Department of Computer
Science and Engineering Washington University,
St. Louis cdgill_at_cse.wustl.edu
2Overview
The Interceptor architectural pattern allows
services to be added transparently to a framework
and triggered automatically when certain events
occur.
- Abstraction
- Genericity
- Conformity
- Extensibility
- Reusability
- Modularity
- Flexibility
3Motivation
int send_data(Buffer buf, size_t n) log(buf,
n) if(!check_security(buf, n) return 0
encrypt(buf, n) // etc... finally_actually_se
nd_data(buf, n) return 1
- Simple client/server
- add logging features
- add security checks
- add encryption
- add QoS/prioritization
- add special-case or exception handling
- E.g., traffic overload, administrator access,
etc. - Want to add new processing for existing events
- Code easily becomes tangled and unmanageable
- Want to add new processing for new events
- Adding a new interception point is error-prone
4Problem
- Fundamental concern
- How to integrate out-of-band tasks
- with in-band tasks?
- Straightforward (and all to common) approach
- Paste the out-of-band logic wherever its needed
- May be multiple places to paste it
- Brittle, tedious, error-prone, time/space (e.g.,
inlining) - Is there a better and more general approach?
Out-of-Band (Admin)
In-Band (Client)
In-Band (Server)
5Interceptor Solution Approach
- Our goal is to find a general mechanism to
integrate out-of-band tasks with in-band tasks - In-band tasks
- Processed as usual via framework
- Out-of-band tasks
- register with framework via special interfaces
- are triggered by framework on certain events
- Some events are generated by in-band processing
- are provided access to framework internals (i.e.,
context) via specific interfaces
6Interceptor Interaction diagram
Application
Concrete Framework
Concrete Interceptor
Dispatcher
create
create
attach
Concrete Interceptor
event
create
Context Object
callback
iterate_list
Context object
callback
get_value
access_internals
7Interceptor Pattern Structure
8Implementation
- Model internal behavior of concrete framework
- Identify and model interception points
- Identify concrete framework state transitions
- Partition interception points into reader/writer
sets - Integrate them into state machine model
- Partition them into disjoint interception groups
- Specify the context object
- semantics
- number of context object types
- strategy for passing context objects to
interceptors - per-registration vs. per-event
9Implementation (continued)
- Specify the interceptors
- Specify the dispatchers
- interceptor registration interface
- dispatcher callback interface
- Implement call-back mechanisms in concrete
framework - Implement concrete interceptors
10Example Pattern Language Sketch
- Data streams need transparent security protection
- Apply an Interceptor to encode and decode stream
(insert an object into a path of the
system) - Smart adversary might learn en/decoding in use
- Apply ACT to identify new en/decoding schemes at
run-time - Triggering changes may complicate threading
- Apply Reactor for in-and-out-of-band processing
- Need to trigger changes on remote applications
- Apply Acceptor/Connector to set up connection to
a remote interceptor dispatcher - Any point in the code might detect a need to
change - Apply Singleton to interceptor dispatcher
- Make these dispatchers remote Observers of one
another
11Design Outline
- Multi-threaded and/or reactive concurrency with
streams of text (as in lab assignments) - Add encode/decode interceptor capabilities
- XOR, k, -k, k, /k, rotate(k), IDEA, RSA
- Design the interceptors out-of-band interfaces
- ACTs for encoding/decoding function and argument
- Initial encoding function and argument
- Design interceptor dispatcher and registry
- Singleton for all interceptors in a process
- Event handler for reactor, also an acceptor
- How to federate across distribution boundaries?
12Dynamic Interceptor Variant
- Base Interceptor
- virtual apply_XXX()
- Concrete Interceptors
- Logging
- Checksum
- Statistics
- Encrypt
- security checks
class Interceptor public virtual void
apply_encode(string) 0 virtual void
apply_decode(string) 0
13The Data_Endpoint class
- Abstraction for sending and receiving data
- Two Data_Endpoints connect then send
- send_data() and receive_data() both dispatch to
interceptors - add_interceptor() registers new concrete
interceptors
14Dynamic Interceptor (1/3)
// A simple Interceptor Function class that
rot13's a message.class Rot13_Interceptor
public Interceptor class Rot13 public
unary_functionltchar, chargt public char
operator()(char c) if(islower(c)) return
c ((c gt 'a' 13) ? -13 13)
if(isupper(c)) return c ((c gt 'A' 13) ? -13
13) return c public void
apply_encode(string s) transform(s.begin(),
s.end(), s.begin(), Rot13()) void
apply_decode(string s) transform(s.begin(),
s.end(), s.begin(), Rot13())
15Dynamic Interceptor (2/3)
class Data_Endpoint Data_Endpoint peer_
string data_ typedef vectorltInterceptorgt
Interceptor_List Interceptor_List
interceptors_ // public // void
send_data(const string s) // not mt-safe!
Encode_Dispatcher dispatch(s)
for_each(interceptors_.begin(),
interceptors_.end(), dispatch) string t
dispatch.get_result() //send data to
peer_ cout ltlt "Data_Endpoint_at_" ltlt this ltlt "
sent '" ltlt t ltlt "' on the wire" ltlt
endl //
16Dynamic Interceptor (3/3)
class Encode_Dispatcher public
unary_functionltInterceptor, voidgt string
s_public Encode_Dispatcher(string s) s_(s)
void operator()(Interceptor i)
i-gtapply_encode(s_) string get_result(void)
return s_
17Using Dynamic Interceptor
- Data_Endpoint foo Data_Endpoint bar
Print_Interceptor pf new Print_Interceptor
Rot13_Interceptor rot13 new Rot13_Interceptor
foo.add_interceptor(pf) foo.add_interceptor(
rot13) foo.add_interceptor(pf)
bar.add_interceptor(pf) bar.add_interceptor(rot
13) bar.add_interceptor(pf)
foo.connect(bar) foo.send_data(a string)
18Analysis of Dynamic Interceptor
- apply_XXX() design is fragile
- To add a new interception type
- add pure virtual apply_foo() to base
- implement in all existing concrete interceptors
- or refactor to have a single apply() with a
switch - May not need all of this flexibility
- may not need per-event context objects
- may not need to reorder or add interceptors at
runtime
19Consequences
- Separation of Concerns
- (Future) Flexibility
- Reusability/Portability
- - Efficiency/Heterogenity
- - Evil Interceptors
20Interceptors using Generics
- Interceptor instances may not be needed
(stateless) - No context objects
- Note one interceptor
- Cant do both checksum and encrypt directly here
- Could compose both functions into interceptor
- Or, could publish trigger event which other
interceptors can handle
Can specialize!
template ltclass Interceptorgt class Data_Endpoint
public send() ...
Interceptor()(Send_Event()) ...
... class Logging_Interceptor public
void operator()(...) ...
21Potential Problems
- Data_Endpoint incompatibility
- arises from instantiating the Data_Endpoint
template with different types - connect() and send() no longer work
- Solution
- template ltclass Other_Interceptorgt
- friend class Data_Endpoint
- Single Interceptor only
- Can use Typelists to extend this approach!
22Typelists
- List of types using templates
- No inherent runtime overhead
- Allows arbitrary number of Interceptors
template ltclass T, class Ugtstruct Typelist
typedef T Head typedef U Tail
TypelistltLogging_Interceptor,
TypelistltChecksum_Interceptor, NullTypegt gt
Andrei Alexandrescu, Modern C Design Generic
Programming and Design Patterns Applied
23More on Typelists
- Telescoping Typelist definitions awkward
- typelist.h defines
- Mechanism includes various algorithms
- Length, TypeAt (index), Append, Erase (type from
Typelist), Replace (type with type),
DerivedToFront - all for free evaluated at compile time!
define TYPELIST_1(T1) TypelistltT1,NullTypegt defi
ne TYPELIST_2(T1,T2) TypelistltT1,TYPELIST_1(T2)
gt define TYPELIST_3(T1,T2,T3) TypelistltT1,TYPELIS
T_2(T2,T3) gt ... up to TYPELIST_50(...)
24Using Generic Interceptors
- Data_EndpointltChain_Interceptorlt
- TYPELIST_3(Print_Interceptor,
- Rot13_Interceptor,
- Print_Interceptor)gt gt foo
- Data_EndpointltChain_Interceptorlt
- TYPELIST_1(Rot13_Interceptor)gt gt bar
- foo.connect(bar)
- foo.send_data(Hello world)
25Analysis of Generic Interceptors
- No runtime modification of Interceptors
- BUT efficient (inlined) dispatch
- Performance vs. Flexibility
- Because of template use, its compile-time
configurable and flexible - easy to change Interceptor attachment
- but must recompile