bridging java and aspectj [pppj08]

Post on 18-Dec-2014

743 Views

Category:

Technology

1 Downloads

Preview:

Click to see full reader

DESCRIPTION

Through AspectJ, aspect-oriented programming (AOP) is becoming of increasing interest and availability to Java programmers as it matures as a methodology for improved software modularity via the separation of cross-cutting concerns. AOP proponents often advocate a development strategy where Java programmers write the main application, ignoring cross-cutting concerns, and then AspectJ programmers, domain experts in their specific concerns, weave in the logic for these more specialized cross-cutting concerns. However, several authors have recently debated the merits of this strategy by empirically showing certain drawbacks. The proposed solutions paint a different development strategy where base code and aspect programmers are aware of each other (to varying degrees) and interactions between cross-cutting concerns are planned for early on. Herein we explore new possibilities in the language design space that open up when the base code is aware of crosscutting aspects. Using our insights from this exploration we concretize these new possibilities by extending AspectJ with concise yet powerful constructs, while maintaining full backwards compatibility. These new constructs allow base code and aspects to cooperate in ways that were previously not possible: arbitrary blocks of code can be advised, advice can be explicitly parameterized, base code can guide aspects in where to apply advice, and aspects can statically enforce new constraints upon the base code that they advise. These new techniques allow aspect modularity and program safety to increase. We illustrate the value of our extensions through an example based on transactions.

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