composition filter – part 2 איתי בן אליעזר נובמבר 2004
TRANSCRIPT
Composition Filter – Part 2
איתי בן אליעזר
2004 נובמבר
What’s next ?
Examples of the composition filter.
ComposeJ. Conclusions about the
composition filter. Composition filter vs. aspectJ and
HyperJ .
An example Suppose we have an agency that deals with disablement
insurance laws.
An example There are five tasks here:
RequestHandler create a document for clients. RequestDispatcher implements the evaluation and
distribution of the documents to the necessary tasks. MedicalCheck is responsible for evaluating the client’s
disablement. Payment is responsible for issuing bank orders. OutputHandler is responsible for communicating with
the clients.
Model Client’s request (Document)
For each client’s request ,a document is created. Depending on the document type and client's
data, the document is edited and sent to the appropriate tasks using a standard email system.
Class Document is the root class of all document types.
There are several classes which inherit from the class Document. For example, ClaimDocument is used to represent the claims of clients.
Document hierarchy
Model
Model How does the model work ?
A client wants to issue a claim. RequestHandler creates a ClaimDocument. It retrieves the client’s data and open the document’s
editor. The clerk enters the data to the RequestHandler. The operation forwardDocument prepares the document
and passes it as an argument to the operation processDocument on the next task.
The next task receives the document and goes on with the process.
Model’s improvement (1) Protecting Documents
In the initial position, a clerk could edit any field in a document. A request dispatcher clerk could, for instance, accidentally edit the medical data field.
To avoid this, the implementation of methods should be extended with some source code that verifies the identity of the caller.
Protecting Documents Inheritance-based solution
ProtectedClaimDocument inherits from ClaimDocument. Declares a new operation called activeTask that returns
the identity of the active task. 15 operations should be redefines in the new model. In the next page we can see the changes in the code.
Protecting Documents
Protecting Documents: CF-based solution
the operation ~> get every message except the ones that are specified on right-hand side.
A CF class aggregates zero or more internal classes.
Implementation of the class.
Protecting Documents: CF-based solution
concern ProtectedClaimDocument beginfilterinterface documentWithViews begininternals
document: ClaimDocument;externals // no externals defined by this classconditions
activeRH; activeRD; activeMC; activeP; activeOH;methods
activeTask();Inputfilters
protection: Error = { activeP => {putApprovedClaim, approvedClaim},activeMC => {putMedicalCheckData, medicalCheckData},… // etc. for the other views};
inh: Dispatch = { inner.* , document.* };end filterinterface DocumentWithViews;Implementation
// introduced in the next page End implementation
end concern ProtectedClaimDocument;
Internal objects are encapsulated within the CF object
External objects are references to objects outside the CF object, such asglobal objectsCondition and
Methods are defined in the implementation
<condition> => <message expressions>inner is a pseudo variable that refers to the implementation object
document was declared as internal object
Protecting Documents: CF-based solution
implementation in Java // for exampleclass ProtectedClaimDocument {
boolean activeRH() { return this.activeTask().class()!=RequestHandler };
boolean activeRD() { … };boolean activeMC() { … };boolean activeP() { … };boolean activeOH() { … };String activeTask() { … };}
end implementation
Model’s improvement (2) Adding workflow
In the previous implementation, the clerks had to decide which task to be executed next.
To enforce a process, class WorkFlowEngine is introduced.
The operation selectTask accepts a document as an argument and based on the workflow specification and the state of the document, returns the identity of the next task.
Adding workflow Inheritance-based solution
Adding a workflow to the system requires redefinition of forwardDocument for all task classes.
The forwardDocument first calls on selectTask of WorkFlowEngine, which returns the next task.
superimposition So far, we have shown only examples of behavior
that crosscuts a number of methods within a single object.
Now ,We need to deal with concerns crosscut multiple objects.
superimpositionThe declaration of a filterinterfacehas been separated from its instantiation and multiple declarations are allowed.
Multiple instantiations of filterinterfaces are possible.
Incoming and outgoing messages have to pass through all the instantiated filterinterfaces.
superimposition element specifies where filterinterfaces are superimposed: on the concern itself, or on other concerns.
Adding workflow: CF-based solution
concern WorkFlowEngine begin // introduces centralized workflow control filterinterface useWorkFlowEngine begin // this part declares the crosscutting code
externalswfEngine : WorkFlowEngine;
inputfiltersredirect : Meta =
{ [forwardDocument]wfEngine.selectTask }
end filterinterface useWorkFlowEngine;
filterinterface engine begin //defines the interface of the workflow engine objectmethodsselectTask(Message);setWorkFlow(WorkFlow);inputfiltersdisp : Dispatch = { inner.* }; // accept all methods implemented by myself
end filterinterface engine;
…
Declare a shared instance for the concern
Catch forwardDocument message , send it to wfEngine, as an argument to selectTask message.
selectTask determines the next task that should handle the document
Adding workflow : CF-based solution
…superimposition begin
selectorsallTasks = { *=RequestHandler, *=RequestDispatcher,
*=OutputHandler,*=MedicalCheck, *=Payment};
filterinterfacesself <- self::engine;allTasks <- self::useWorkFlowEngine;
end superimposition;implementation in Java;
class WorkFlowEngineClass{
WorkFlow workFlowRepr;void selectTask(mess Message) { … };void setWorkFlow(WorkFlow wf) { … };
} end implementation;end concern WorkFlowEngine;
Define allTasks as all the objects that are instances of this classes
Instances of WorkFlow Engine have engine filterinterface
The allTask instances have useWorkFlowEngine
How does it works? There is a useWorkFlowEngine filter on every task. When a task get a forwardDocumennt message,
the Meta filter send the message to wfEngine as an argument to the selectTask message.
wfEngine gets the message through the engine filter, manipulate it and fire it to the task.
Model’s improvement (3) Adding Document Queues
Each document in the process may require a different processing time.
To improve the average throughput, a document queue is defined for every task.
There is a buffer for every task class. The operation processDocument has to be
mutual exclusive.
Adding Document Queues
Inheritance-based solution The synchronization code must apply to every
task processor class. It is repeated within the implementation of
several methods of the “task processor” class. This is a typical example of crosscutting behavior.
Adding Document Queues : CF-based solution
concern MutEx begin // implements the mutual exclusion synchronization concernfilterinterface mutExSync begin
conditionsNoActiveThreads;
inputfiltersbuffer : Wait = { NoActiveThreads=>* };
end filterinterface mutExSync;
superimposition begin // not imposed anywhere; abstract concernend superimposition;
implementation in Java;class MutExSupport{
Boolean NoActiveThreads() { … };}
end implementation;end concern MutEx ;
If (NoActiveThreads == false) than it wait
Adding Document Queues : CF-based solution
concern ConcurrentDocumentProcessing begin // allows concurrency without interferencesuperimposition beginconditions
WorkFlowEngine::allTasks <- MutEx::NoActiveThreads;filterinterfaces
WorkFlowEngine:: allTasks <- MutEx::mutExSync;end superimposition superimposition;
end concern ConcurrentDocumentProcessing;
Every task calls the mutExSync filter if the NoActiveThreads is false
Model’s improvement (4) Adding logging
One of the important concerns of the workflow system is to monitor the process.
All the interactions among objects are registered.
Class Logger is introduced to register the interactions in the system.
Adding logging
Inheritance-based solution Adding a logging facility also requires
redefinition of all methods of task and document classes.
This is because before executing any call, the
operation log of Logger must be called.
Adding logging: CF-based solution
concern Logging begin // introduces centralized loggerfilterinterface notifyLogger begin
externalslogger : Logging;
internalslogOn : boolean;
methodsloggingOn(); logginOff(); log(Message);
conditionsLoggingEnabled;
inputfilterslogMessages : Meta = { LoggingEnabled=>[*]logger.log };dispLogMethods : Dispatch = { loggingOn, loggingOff };
end filterinterface notifyLogger;
Declare a global object logger
Used to enable and disable the logging of messages
Turn on and turn off the logOn field
This interface will be on all the instances except of logging
Get information from message and store it
When logOn is turned On ,pass it to logger as an argument
Pass the loggingOn and loggingOff methods
Adding logging: CF-based solution
filterinterface logger begin //defines the interface of the logger object itselfmethods
log(Message);inputfilters
disp : Dispatch = { inner.* }; end filterinterface logger;
superimposition beginselectorsallConcerns = { *!=Logging }; conditions
allConcerns <- LoggingEnabled;filterinterfaces
allConcerns <- notifyLogger;self <- logger;
end superimposition superimposition;
accept all methods implemented by myself
Every instances except instances of Logging will get notifylogger filter
The filter logger is on the logging instance
Adding logging: CF-based solution
implementation in Java;class LoggerClass {
boolean LoggingEnabled() { return logOn };void loggingOn() { logOn:=true; };void loggingOff() { logOn:=false; };void log(Message mess) { … };
}end implementation;
end concern Logging;
get information from message and store
Model’s improvement (5) Adding locking
It was found necessary to temporarily lock a task or document, for instance, for reallocating resources, debugging or for obtaining a snapshot of the system.
For every class in the system, the operations lock and unlock are introduced.
The operation lock queues all the requests unless unlock is invoked.
Adding locking
Inheritance-based solution If a the semaphore-like mechanism is used to
implement locking, every operation of a class has to be redefined.
Adding locking: CF-based solution
concern Locking begin // implements the locking synchronization concernfilterinterface lockBehavior begin
internalslockState : boolean;
methodslock();unlock();
conditionsunLocked;
inputfilterslockAll : Wait = { unlock, unLocked=>* };disp : Dispatch = { lock, unlock };
end filterinterface lockBehavior;
superimposition begin // this is an abstract concernend superimposition;
state is true when locked
Wait filter that blocks allmessages except the unlock message when the concern is in the locked state or messages when it isn’t locked.
Adding locking: CF-based solution
implementation in Java;{
class LockingSupport{void lock() { lockstate:=true };void unlock() { lockstate:=false };boolean UnLocked() { return !lockstate; };boolean Locked() { return lockstate; };
}end implementation;
end concern Locking;
Adding locking: CF-based solution
concern WorkflowLocking begin // applies the locking concern to the workflow appl.superimposition begin
selectorsapplObjects = {*:Document, *:TaskProcessor};
methodsapplObjects <- {Locking::lock, Locking::unlock};
conditionsapplObjects <- Locking::UnLocked;
filterinterfacesapplObjects <- Locking::lockBehavior;
end superimposition ;end concern WorkflowLocking;
selector includes all instances of TaskProcessor and Document
If (lockState==false)
It use the lockBehavior
ComposeJ
ComposeJ implements an extension of the java language that adds Composition Filters to Java classes through inlining .
The first prototype was created in 1999, as part of Hans Wichman's MSc.
ComposeJ implements the Error and dispatch filters.
The ComposeJ system is an add-on to a standard Java compiler.
The ComposeJ system is built for Java 1.1. However, the way it is designed and implemented, it can easily migrate to Java 1.2 or even Java 1.0 .
ComposeJ
ComposeJ is a compile time tool.
The main reason for this approach is the performance loss in a run-time approach.
ComposeJ translate the filters to an implementation where code is inlined in Java sources.
ComposeJ
The composition filter grammar was adapted to the Java grammar.
Processing a ComposeJ file
A ComposeJ file is processed by choosing the ‘Process Java with filters’ option from the Build menu.
Extensive information about the current state of the process is printed to the debug window.
When the processing finishes successfully, a new Java file is present in the same directory as the ComposeJ file.
The future of ComposeJ
A future work is necessary to extend the system with other filter types and functionality.
But the system requirements and the goal of the assignment have largely been met.
Composition filter - conclusions
The CF approach can decrease the amount of source code. In more complicated problems it can be even
more crucial.
Declarative concerns are specified declaratively in a simple
pattern matching language allowing various implementation strategies.
For example, ComposeJ is a compiler ,which adds inline filter code . The Sina language compiler implements filters as metaObjects.
Composition filter - conclusions
Open ended new kind of concern semantics can be
introduced as new filter types.
High level semantics The semantics of filter types are well defined
and highly expressive. We can see from the examples that the filters
can express effectively the different tasks.
Composition filter - conclusions
Strong encapsulation Superimpositions, objects ,methods ,and
conditions are restricted to the interface level. Therefore superimposed concerns do not relay
on the details of the implementation.
Modular Unifies OOP with AOP.
Composition filter vs. aspectJ and HyperJ
What are the common principle of aspectJ, hyperJ, and CF ? Crosscutting.
aspectJ use pointcuts. hyperJ use HyperModule and HyperSlice. Composition filter use the filterinterface and
superImposition.
Differences between CF and the other approaches.
But, they see the aspects in a different way. CF partitions ‘aspect’ specifications per
object, expressed in terms of message AspectJ uses a central aspect
specification, that is integrated with the class hierarchies by using a so-called aspectweaver (preprocessor).
In HyperJ, there are sets of Hyperslices that create a HyperMoudles.
Differences between CF and the other approaches.
Encapsulation In CF ,the implementation part is strongly
encapsulated object. CF deals only with the interface level.
AspectJ and HyperJ allow the crosscutting concerns (aspects) to 'break encapsulation', which makes the aspects less reusable and more vulnerable to implementation changes. They have structural and behavioral crosscutting.
Differences between CF and the other approaches.
Semantics The semantics of the filter types are well
defined and highly expressive. But there are only few filters.
AspectJ and HyperJ are more general-purpose approaches than Composition filter. The concerns are less semantics.
Reference
”Composition Multiple Concerns Using Composition Filters” by Lodewijk Bergmans & Mehmet Aksit ,
University of Twente. ComposeJ – master of science thesis by Johannes
Cornelis Wichman.
Questions ?