Introduction to AOP, AspectJ, and Explicit Join Points

Post on 21-Jun-2015

2.784 views 3 download

Tags:

description

An introduction to and history of aspect-oriented programming. A short overview of AspectJ, certain challenges such as the state-point separation problem, and how explicit join points (EJPs) help mitigate these problems.

Transcript of Introduction to AOP, AspectJ, and Explicit Join Points

Why you should get excited

about AOP and AspectJ

(or not)

Kevin Hoffman

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

History of AOP [1]

Defined by Kiczales et al. @ ECOOP‘97

Functional vs data flow decomposition example

History of AOP [2]

Aspects are properties not ―cleanly

encapsulated‖ (locality / composability)

History of AOP [3]

Aspect Weavers: ―process the component

and aspect languages, composing them

properly to product the … total system …‖

Join Points: ―Those elements of the

component language semantics that the

aspect programs coordinate with‖

History of AOP [4]

Filman/Freiman @ OOPSLA‘00:

`AOP is Quantification and Obliviousness‘

―Distinguishing characteristic‖ … of AOP … is ability to

make ―quantified programmatic assertions over programs

written by programmers oblivious to such assertions‖

‗ ―Just program like you always do, and we’ll be able to

add the aspects later.‖ (And change your mind

downstream about your policies, and we‘ll painlessly

transform your code for that, too.)‘

History of AOP [5]

Sullivan–Levels of Obliviousness (FSE‘05):

Language-level (i.e. language support for AOP)

Feature obliviousness—base code unaware of

features in aspects, but do know of preconditions

Designer obliviousness—

Base code programmers blissfully unaware…

Pure obliviousness—

Complete, symmetric separation

History of AOP [6]

Languages (countless)

AspectJ – ~2000 / ECOOP‘01

25+ for Java (CaesarJ, Classpects, LogicAJ, EJPs)

13+ for .NET (PostSharp, Aspect#, …)

6+ for C/C++ (AspectC++, XWeaver, …)

37+ for others (Cobol (!), Delphi, JavaScript, Lua,

make, ML, Perl, PHP, Python, Ruby, XML, UML)

AspectJ Introduction

AspectJ (~2000; Kiczales @ ECOOP‘01)

Join point model:

Structural points in ‗base code‘

Quantification model (pointcuts):

Lexical patterns and type constraints

Dynamic predicates and control flow

Aspects inject advice before, after, around…

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(…){

…}

Pointcuts [1]

Methods and Constructors

call(Signature)

execution(Signature)

Fields

get(Signature)

set(Signature)

Exception Handlers

handler(TypePattern)

Pointcuts [2]

Advice

adviceexecution()

Initialization

staticinitialization(TypePattern)

initialization(Signature)

preinitialization(Signature)

Lexical

within(TypePattern)

withincode(Signature)

Pointcuts [3]

Instanceof checks / context exposure

this(Type or Id)

target(Type or Id)

args(Type or Id)

Control Flow

cflow(Pointcut)

cflowbelow(Pointcut)

Pointcuts [4]

Conditional

if(Expression)

Combination

! Pointcut

Pointcut0 && Pointcut1

Pointcut0 || Pointcut1

( Pointcut )

Pointcut Examples

pointcut setXY(FigureElement fe, int x, int y):

call(void FigureElement.setXY(int, int))

&& target(fe)

&& args(x,y)

after(FigureElement fe, int u, int v) returning:

setXY(fe, u, v)

{

System.out.println(fe+" moved to ("+u+","+v+")");

}

Pointcut Examples

pointcut setXY(FigureElement fe, int x, int y):

call(void FigureElement.setXY(int, int))

&& target(fe)

&& args(x,y)

after(FigureElement fe, int u, int v) returning:

setXY(fe, u, v)

{

System.out.println(fe+" moved to ("+u+","+v+")");

}

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(…){

…}

}}

Advice (unit of logic injection)

Specify where to inject aspect logic:

before

after (returning, throwing)

around – use of proceed

Aspect Reflection:

thisJoinPoint encapsulates currently advised join

point, including ability to proceed

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(…){

…}

}}

Aspects

Encapsulation of a cross-cutting concern

Collection of pointcuts, state, and advice

Variety of instantiation models:

Singleton, per this/target, per cflow

aspectOf() to retrieve aspect instance in base code

Example Aspect

aspect FieldModificationLogger {

Fieldlog l = new FieldLog(…);

pointcut allSets(Object o, Object newVal):

set(* *.*)

&& this(o)

&& args(newVal);

before(Object o, Object nv): allSets(o,nv) {

l.record(o,nv);

}

}

Modern AspectJ

Intertype declarations

Statically modify types (add/override methods, etc.)

Integration with generics

Only for pointcuts, generics erased for advice

Annotation support

Aspect specification via annotations

Matching based on annotations

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

Empirical Metrics Formulated…

Coupling, Cohesion, Separation of Concerns

On the reuse and maintenance of Aspect-Oriented

software: [Sant‘Anna et. al. 2000]

AspectBase Code Coupling

Measuring the effects of software aspectization

[Ceccato/Tonella 2004]

http://aopmetrics.tigris.org/

Empirical Studies Emerging…

Separation of Concerns in Multi-agent Systems: An

Empirical Study [2004]

Modularizing design patterns with aspects: a quantitative

study [AOSD’05]

Composing design patterns: a scalability study of aspect-

oriented programming [AOSD’06]

Exceptions and aspects: the devil is in the details [FSE’06]

On the impact of aspectual decompositions on design

stability: An empirical study [ECOOP’07]

Towards Reusable Components with Aspects [ICSE’08]

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

Solutions?

Explicit Join Points [Hoffman/Eugster]

Bridging Java and AspectJ [PPPJ‘07]

Towards Reusable Components with Aspects: An

Empirical Study on Modularity and Obliviousness

[ICSE‘08]

Cooperative Aspect-Oriented Programming [SCP]

XPIs [Sullivan et.al.] / Classpects [Rajan]

Open Modules [Aldrich]

Motivation for Explicit Join Points

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

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

EJPs Empirical Case Study [ICSE08]

AspectJ + EJPs Delivers

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.internal

DoStartTag1());

pointcut internalDoStartTag2Handler() :

execution(private void

com.sun.j2ee.blueprints.waf.view.template.tags.InsertTag.internal

DoStartTag2());

pointcut doEndTagHandler() :

execution(public int

com.sun.j2ee.blueprints.waf.view.template.tags.InsertTag.doEndT

ag());

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 Servlet Error 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) {}

}

}

}