bridging java and aspectj [pppj08]
Post on 18-Dec-2014
743 Views
Preview:
DESCRIPTION
TRANSCRIPT
Bridging Java and AspectJ
through Explicit Join Points
Kevin Hoffman and Patrick Eugster
PPPJ 2007
AOP
AOP
Cross-cutting Concerns
(Thanks to AspectJDev Tools (AJDT) Visualization Eclipse Perspective)
Cross-cutting Concerns
(Thanks to AspectJDev Tools (AJDT) Visualization Eclipse Perspective)
Aspect-Oriented Programming
Make cross-cutting concerns:
Separated from the “base code”
No coupling between base code / cross-cutting concerns
Aim for lexical and semantic separation
Modular Domain experts write the “hard stuff” once
AOP Stratagems
Obliviousness Increased modularity of base code and aspect code
Parallel and domain-specific development
Better post-mortem extendibility
Quantification (pattern matching)
Reduction in code size and duplicity
Higher level interaction between primary and cross-
cutting concerns
Toy Tracing Example
class Store {
pointcut logEvents():call(* * Store.*(..));
//advicearound(): logEvents() {
println(“”+thisJoinPoint);Object ret = proceed();println(“ret: “+ret);return ret;
}after() throwing(Exception e):
logEvents() {println(“err: ”+e);throw e;
}
JSP Pages aspect Logging {
void buy(…){
try {…
} catch (…) { }}
void cancel(…){
…throw …;
}
void retItem(…){
…}
}}
…s.buy(_order);…
…s.cancel(o);…
…s.retItem(o);…
Toy Tracing Example
class Store {
pointcut logEvents():call(* * Store.*(..));
//advicearound(): logEvents() {
println(“”+thisJoinPoint);Object ret = proceed();println(“ret: “+ret);return ret;
}after() throwing(Exception e):
logEvents() {println(“err: ”+e);throw e;
}
JSP Pages aspect Logging {
…s.buy(_order);…
…s.cancel(o);…
…s.retItem(o);…
void buy(…){
try {…
} catch (…) { }}
void cancel(…){
…throw …;
}
void retItem(…){
…}
}}
println (…)
println (…)
println (…)
Toy Tracing Example
class Store {
pointcut logEvents():call(* * Store.*(..));
//advicearound(): logEvents() {
println(“”+thisJoinPoint);Object ret = proceed();println(“ret: “+ret);return ret;
}after() throwing(Exception e):
logEvents() {println(“err: ”+e);throw e;
}
JSP Pages aspect Logging {
…s.buy(_order);…
…s.cancel(o);…
…s.retItem(o);…
void buy(…){
try {…
} catch (…) { }}
void cancel(…){
…throw …;
}
void retItem(…){
…}
}}
println (…)}catch(…){
println(…);…}
try {
println (…)}catch(…){
println(…);…}
try {
println (…)}catch(…){
println(…);…}
try {
AspectJ Join Points
class Store {
pointcut logEvents():call(* * Store.*(..));
//advicearound(): logEvents() {
println(“”+thisJoinPoint);Object ret = proceed();println(“ret: “+ret);return ret;
}after() throwing(Exception e):
logEvents() {println(“err: ”+e);throw e;
}
JSP Pages aspect Logging {
…s.buy(_order);…
…s.cancel(o);…
…s.retItem(o);…
void buy(…){
try {…
} catch (…) { }}
void cancel(…){
…throw …;
}
void retItem(…){
…}
}}
AspectJ Pointcuts
class Store {
pointcut logEvents():call(* * Store+.*(..));
//advicearound(): logEvents() {
println(“”+thisJoinPoint);Object ret = proceed();println(“ret: “+ret);return ret;
}after() throwing(Exception e):
logEvents() {println(“err: ”+e);throw e;
}
JSP Pages aspect Logging {
…s.buy(_order);…
…s.cancel(o);…
…s.retItem(o);…
void buy(…){
try {…
} catch (…) { }}
void cancel(…){
…throw …;
}
void retItem(…){
…}
}}
AspectJ Advice
class Store {
pointcut logEvents():call(* * Store+.*(..));
//advicearound(): logEvents() {
println(“”+thisJoinPoint);Object ret = proceed();println(“ret: “+ret);return ret;
}after() throwing(Exception e):
logEvents() {println(“err: ”+e);throw e;
}
JSP Pages aspect Logging {
…s.buy(_order);…
…s.cancel(o);…
…s.retItem(o);…
void buy(…){
try {…
} catch (…) { }}
void cancel(…){
…throw …;
}
void retItem(…){
…}
}}
AspectJ Advice
class Store {
pointcut logEvents():call(* * Store+.*(..));
//advicearound(): logEvents() {
println(“”+thisJoinPoint);Object ret = proceed();println(“ret: “+ret);return ret;
}after() throwing(Exception e):
logEvents() {println(“err: ”+e);throw e;
}
JSP Pages aspect Logging {
…s.buy(_order);…
…s.cancel(o);…
…s.retItem(o);…
}}
void buy(…){
try {…
} catch (…) { }}
void cancel(…){
…throw …;
}
void retItem(…){
…}
AspectJ in Action1
Logging (canonical example)
Pooling / caching
Policy / contract enforcement
Business logic
Security
Transactions
Exception Handling
1) AspectJ in Action: Practical aspect-oriented programming, R. Laddad, Manning, 2003
Fragile Pointcuts
Base Code Aspect Code
public aspectWafViewTemplateHandlerextendsExceptionGenericAspect
{ pointcut initScrGetResHdlr():
withincode(private voidTemplateServlet. initScreens(
ServletContext, String))
&& call(URL ServletContext.getResource(String));
…}
private void initScreens(
ServletContext ctxt,
String language)
{
…
screenDefURL =
ctxt.getResource(…);
…
}
State—Point Separation Issue
Base Code aspect AbortedTranAnalyzer {
}
try {…
} catch (OldExc e) {t.abortTrans(…);throw new
GenExc ("failed");}
//========POSSIBLE========pointcut gotOldExc(OldExc ex):
handler(OldExc) && args(ex);pointcut abortedTran(Tran tr):
call(* *.abortTrans(..))&& target(tr);
pointcut gotGenExc(GenExc ex):initialization(GenExc.new(..))&& target(ex);
//======NOT POSSIBLE=======pointcut get3State(OldExc old,
Tran tr, GenExc gen):gotOldExc(old)&& abortedTran(tr)&& gotGenExc(ex);
State—Point Separation Issue
Base Code aspect AbortedTranAnalyzer {
}
try {…
} catch (OldExc e) {t.abortTrans(…);throw new
GenExc ("failed");}
//========POSSIBLE========pointcut gotOldExc(OldExc ex):
handler(OldExc) && args(ex);pointcut abortedTran(Tran tr):
call(* *.abortTrans(..))&& target(tr);
pointcut gotGenExc(GenExc ex):initialization(GenExc.new(..))&& target(ex);
//======NOT POSSIBLE=======pointcut get3State(OldExc old,
Tran tr, GenExc gen):gotOldExc(old)&& abortedTran(tr)&& gotGenExc(ex);
State—Point Separation Issue
Base Code aspect AbortedTranAnalyzer {
}
try {…
} catch (OldExc e) {t.abortTrans(…);throw new
GenExc ("failed");}
//========POSSIBLE========pointcut gotOldExc(OldExc ex):
handler(OldExc) && args(ex);pointcut abortedTran(Tran tr):
call(* *.abortTrans(..))&& target(tr);
pointcut gotGenExc(GenExc ex):initialization(GenExc.new(..))&& target(ex);
//======NOT POSSIBLE=======pointcut get3State(OldExc old,
Tran tr, GenExc gen):gotOldExc(old)&& abortedTran(tr)&& gotGenExc(ex);
State—Point Separation Issue
Base Code aspect AbortedTranAnalyzer {
}
try {…
} catch (OldExc e) {t.abortTrans(…);throw new
GenExc ("failed");}
//========POSSIBLE========pointcut gotOldExc(OldExc ex):
handler(OldExc) && args(ex);pointcut abortedTran(Tran tr):
call(* *.abortTrans(..))&& target(tr);
pointcut gotGenExc(GenExc ex):initialization(GenExc.new(..))&& target(ex);
//======NOT POSSIBLE=======pointcut get3State(OldExc old,
Tran tr, GenExc gen):gotOldExc(old)&& abortedTran(tr)&& gotGenExc(ex);
State—Point Separation Issue
Base Code aspect AbortedTranAnalyzer {
}
try {…
} catch (OldExc e) {t.abortTrans(…);throw new
GenExc ("failed");}
//========POSSIBLE========pointcut gotOldExc(OldExc ex):
handler(OldExc) && args(ex);pointcut abortedTran(Tran tr):
call(* *.abortTrans(..))&& target(tr);
pointcut gotGenExc(GenExc ex):initialization(GenExc.new(..))&& target(ex);
//======NOT POSSIBLE=======pointcut get3State(OldExc old,
Tran tr, GenExc gen):gotOldExc(old)&& abortedTran(tr)&& gotGenExc(ex);
AspectJ in Action1
Logging (canonical example)
Pooling / caching
Policy / contract enforcement
Business logic
Security
Transactions
Exception Handling
1) AspectJ in Action: Practical aspect-oriented programming, R. Laddad, Manning, 2003
Challenges of AspectJ
Hindered by:
• Tight aspectbase code coupling
• Burden of fragile pointcuts
• State—point separation problem
• Lack of advice parameterization
• Inability to share abstract pointcuts
Motivation for our Work
How to stop writing
complex, brittle pointcuts,
just to avoid touching the base code,
and start writing
truly reusable aspect libraries
Is all this
obliviousness
really worth it?
AspectJ Approach
What If Join Points Were Explicit?
Cooperative AOP
Explicit Join Points (EJPs)
Abstract a cross-cutting concern to its most essential form
Invoke the information hiding principle
Model the abstraction explicitly using named join points instead of implicit join points
Reference EJPs in code explicitly
Or use aspects to inject EJP references obliviously
Enhance EJPs to mitigate the aspect modularity challenges of AspectJ
Explicit Join Point Declarations
Optional
Modifiers
Keyword to
Declare EJP
Constraints Acting
Upon Base Code
Explicit Name to Associate
with Abstract Semantics
Explicit Value
Parameterization
abstract aspect TranConcern {scoped joinpoint void enterTrans(int isolation)
throws TranException;}
Referencing EJPs in Base Code
Some policy aspect could
implement/override this EJP
Reference to
EJP in base code
Reference to scoped EJP;
entire block of code is advised
abstract aspect TranConcern {scoped joinpoint void enterTrans(int isolation)
throws TranException;joinpoint int defIso() = 1;
}
void someMethod() throws TranException {TranConcern.enterTrans(TranConcern.defIso()) {
//block of code}
}
Advising EJPs in Aspects
aspect TranConcernViaSomeLibrary {void around(int iso) throws TranException:
call(ejpScope(TranConcern.enterTrans))&& args(iso) {
TransContext t = …;t.beginTrans();try {
proceed(); /* calls original block of code */t.commitTrans();
} catch(Throwable e) {t.abortTrans();throw TranException(e);
}}
Advising EJPs in Aspects
aspect BillingComponentsTranPolicy {int around(): call(ejp(TranConcern.defIso))
&& within (com.me.billing.*){ return 4; } //use a higher isolation level in billing pkg
}
aspect ForceIsolationLevel {int around(): call(ejp(TranConcern.defIso))
&& cflow(call(* CreditCard+.*(..))){ return 5; } //anytime the call stack includes a method
} //from the CreditCard class use iso level 5
EJP Pointcut Arguments
Provide mechanisms for pointcuts to be
defined piecewise in base code:
Allow each piece of such a pointcut to be lexically
close to the fragile join points
Fragile code and pointcuts evolve together
Represent the disjunction of all of the pieces as a
pointcut associated with an EJP declaration
Declaring EJP Pointcut Arguments
interface CompRecord {void compensate();void log(…);
}abstract aspect TranConcern {
scoped joinpoint void enterTrans(int isolation)pointcutargs ignoreableCompensations()throws TranException;
joinpoint void addCompensation(CompRecord r);}
This pointcut models the join points that reference the
addCompensation EJP but should actually be ignored
Defining Pointcutargs Piecewise
void testTrans() throws TranException {TranConcern.enterTrans(TranConcern.defIso())
pointcutargs ignorableCompensations():(call(ejp(*.addCompensation)) &&cflow(call(thisblock)))
{//any references to the addCompensation EJP//in the cflow of this block are included in the full//definition of the pointcut ignorableCompensations
}}
Building Aspect Libraries with EJPs
Define semantic interfaces of cross-cutting concerns using interfaces and EJPs
Package these in a JAR
Define aspects that advise the EJPs to implement the cross cutting concerns
Package each implementation in a different JAR
Write base code or aspects to reference EJPs
Choose aspect implementation JAR at load-time
As the EJPs evolve, use aspects to obliviouslyadapt calls from old EJPs to new EJPs
Comparison of Approaches
AspectJ:
AspectJ with EJPs (Cooperative AOP):
AspectsBase Code EJP Interfaces
AspectsBase Code
Library Interfaces Pluggable Libraries
Scoped EJPs, pointcutargs and thisblock, advice
parameterization by type/value, and policy enforcement
Addressing EJP Explicitness
Use EJPs only when appropriate
Design EJPs so that their presence is minimal
Use aspects to reference EJPs as appropriate
Aspect-oriented code editors
Fluid AOP [Hon / Kiczales]
AspectsBase Code EJP Interfaces
EJPs Empirical Case Study [ICSE08]
Related Work
XPIs [Sullivan et al]
Define design rules to shape base code so that
implicit join points have a predictable structure
Write pointcuts against stable design rule patterns
Open Modules [Aldrich]
Restrict advisable join points to be only those that
are explicitly exported by a module
Modular reasoning [Kiczales and Mezini]
Inference of cross-cutting interfaces
AspectJ + EJPs Deliver
The separation of cross-cutting concerns:
Syntactically
Semantically (Base code EJPs aspects)
Benefits from obliviousness
Increased modularity of base code ̂ and aspect code
Parallel and domain-specific development
Post-mortem extendibility
Benefits from quantification
Reduction in code size and duplicity
Higher level interaction between primary and cross-cutting concerns (matching against semantic interfaces)
(presence of EJPs)
AspectJ in Action1
Logging (canonical example)
Pooling / caching
Policy / contract enforcement
Business logic
Security
Transactions
Exception Handling
1) AspectJ in Action: Practical aspect-oriented programming, R. Laddad, Manning, 2003
Goal of Reusable Aspect Libraries
Hindered by:
• Tight aspectbase code coupling
• Burden of fragile pointcuts
• State—point separation problem
• Lack of advice parameterization
• Inability to share abstract pointcuts
AspectJ in Action1
Logging (canonical example)
Pooling / caching
Policy / contract enforcement
Business logic
Security
Transactions
Exception Handling
1) AspectJ in Action: Practical aspect-oriented programming, R. Laddad, Manning, 2003
Goal of Reusable Aspect Libraries
Facilitated by:
• AspectEJPbase code decoupling
• Stable pointcuts / pointcutargs
• Scoped EJPs
• Type/value advice parameterization
• Policy enforcement constructs
kjhoffma@cs.purdue.edu
peugster@cs.purdue.edu
Example Fragile Pointcuts
public aspect WafViewTemplateHandlerextends
ExceptionGenericAspect{
/*** ScreenDefinitionDAO***/
pointcut loadDocument() :
execution(public static Element
ScreenDefinitionDAO.loadDocument(URL));
/*** TemplateServlet***/
pointcut initScreensGetResourceHandler() :
call(URL ServletContext.getResource(String)) &&
withincode(private void
TemplateServlet.initScreens(ServletContext, String));
pointcut internalGetUserTransactionHandler() :
execution(* TemplateServlet.internalGetUserTransaction());
pointcut internalGetRequestDispatcherHandler() :
execution(private void
TemplateServlet.internalGetRequestDispatcher(..));
/*** com.sun.j2ee.blueprints.waf.view.template.tags.InsertTag ***/
public pointcut aroundExceptionDoNothingHandler() :
execution(private void
com.sun.j2ee.blueprints.waf.view.template.tags.InsertTag.intern
alDoStartTag1());
pointcut internalDoStartTag2Handler() :
execution(private void
com.sun.j2ee.blueprints.waf.view.template.tags.InsertTag.intern
alDoStartTag2());
pointcut doEndTagHandler() :
execution(public int
com.sun.j2ee.blueprints.waf.view.template.tags.InsertTag.doEn
dTag());
Example Fragile Pointcuts
private void initScreens(ServletContext context, String language) {
URL screenDefinitionURL= null;
screenDefinitionURL= context.getResource("/WEB-INF/screendefinitions_" + language + ".xml");
if (screenDefinitionURL != null) {
Screens screenDefinitions= ScreenDefinitionDAO.loadScreenDefinitions(screenDefinitionURL);
if (screenDefinitions != null) {
allScreens.put(language, screenDefinitions);
} else {
System.err.println("Template Servlet Error Loading Screen Definitions: Confirm that file at URL
/WEB-INF/screendefinitions_" + language + ".xml contains the screen definitions");
}
} else {
System.err.println("Template ServletError Loading Screen Definitions: URL /WEB-
INF/screendefinitions_" + language + ".xml not found");
}
}
Example State—Point Separation
/**
* @author [redacted]
*/
public aspect AsyncsenderEjbHandler{
//QueueConnectionqConnect= null;
Map qConnect= new HashMap();
/*** AsyncSenderEJB***/
pointcut sendAMessage() :
execution(public void AsyncSenderEJB.sendAMessage(String));
pointcut createQueueConnectionHandler() :
call(* QueueConnectionFactory.createQueueConnection()) &&
withincode(public void AsyncSenderEJB.sendAMessage(String));
declare soft : JMSException: sendAMessage();
after() returning(QueueConnectionqc) : createQueueConnectionHandler() {
//Save inner method variable to local(multi-thread)
qConnect.put(Thread.currentThread().getName(), qc);
//qConnect= qc;
}
void around() throws EJBException: sendAMessage() {
try {
proceed();
} catch(Exception e) {
e.printStackTrace();
throw new EJBException("askMDBToSendAMessage: Error!",e);
} finally {
try {
QueueConnectionqConnectAux= (QueueConnection)qConnect.get(Thread.currentThread().getName());
if( qConnectAux!= null ) {
qConnectAux.close();
}
} catch(Exception e) {}
}
}
}
top related