Reverse Engineering Sequence Diagrams for ... - IEEE Xplore

4 downloads 0 Views 310KB Size Report
Reverse Engineering Sequence Diagrams for. Enterprise JavaBeans with Business Method. Interceptors. Alexander Serebrenik∗, Serguei Roubtsov∗, Ella ...
2009 16th Working Conference on Reverse Engineering

Reverse Engineering Sequence Diagrams for Enterprise JavaBeans with Business Method Interceptors Alexander Serebrenik∗ , Serguei Roubtsov∗ , Ella Roubtsova† and Mark van den Brand∗ ∗ Eindhoven University of Technology P.O. Box 513, 5600 MB Eindhoven, The Netherlands {a.serebrenik, s.roubtsov, m.g.j.v.d.brand}@tue.nl † Open University of the Netherlands, Postbus 2960, 6401DL Heerlen, The Netherlands [email protected]

Abstract—Enterprise JavaBeans (EJB) is a component technology commonly used for enterprise application development. Recent EJB 3.0 specification involves interceptors, a mechanism providing means to dynamically introduce additional behaviour into the execution of a bean. As multiple interceptors can be applied to the same bean, and the order of interceptor invocation can be affected by a variety of specification rules, complexity of interceptors invocation can easily become a burden for the developers or maintainers. In order to help the developers we propose an algorithm for reverse engineering UML sequence diagrams from EJB 3.0 programs.

I. I NTRODUCTION Interceptor [7] is a software mechanism that provides means to dynamically introduce behaviour implemented as separate code into the execution of an application. Recently proposed Java frameworks [13], [17], [9] exploit interceptors to extend Enterprise JavaBeansTM (EJB) with aspect-orientedprogramming (AOP) features. Usually, one distinguishes between life cycle event callbacks, interceptors invoked when objects are, e.g., created or destroyed, and business method interceptors invoked with a business method invocation. We focus exclusively on business method interceptors. The EJB 3.0 specification [13] provides the developer with multiple means of specifying business method interceptors. The developer can decide to specify the interceptors in different ways (using deployment descriptor XML files and/or Java annotations), on different levels (bean class and method), and locations (in a separate class, as part of the bean class itself, in a superclass or in an injected bean). This broad choice on possible implementation points comes at a price, however. As specified in the invocation rules of EJB 3.0 [13], should multiple interceptors be present, the way, level and location of interceptors influence the order of their invocation. Hence, to understand the order of interceptor invocation, the developer has to scrutinize her source code and check which of the invocation rules apply. We observed, however, a number of discrepancies between the specification [13], owned by Sun Microsystems, and GlassFish [14], a popular free application 1095-1350/09 $26.00 $25.00 © 2009 IEEE DOI 10.1109/WCRE.2009.27

server also provided by Sun Microsystems. Due to the inherent complexity of interceptors as well as due to discrepancies between the specification and the implementation, keeping the invocation order in mind can easily become a burden for the developers or maintainers of enterprise applications. Increasing popularity of EJB 3.0 can, therefore, easily become a maintenance time bomb. To address this problem we advocate the use of UML sequence diagrams. Being a part of the industrial de facto standard and supported by multiplicity of development tools, UML sequence diagrams have also been shown to be beneficial for program comprehension [15]. Since interceptor invocation is essentially sequential and data independent, it is specifically well suited for being portrayed by UML sequence diagrams. The contribution of this paper consists, hence, in an algorithm for reverse engineering UML sequence diagrams for enterprise applications involving business method interceptors. The algorithm is based on the information consolidated from different parts of the EJB specification [13] and further clarified by a series of experiments with the GlassFish [14]. The remainder of this paper is organized as follows. Section II discusses EJB 3.0 interceptors while Section III presents the algorithm for reverse engineering sequence diagrams from the source code with interceptors. Section IV reviews the related work, sketches possible directions for future work and concludes the paper. II. I NTERCEPTORS IN EJB 3.0 AND G LASS F ISH Interceptors are reported to make the AOP programs more reusable [8]. Successful reuse, however, demands understanding the different possibilities of implementing interceptors defined in the EJB 3.0 specification, while they are so versatile that the comprehension of their mixed usage can become a challenge. To address the inherent complexity of business method interceptor invocation the EJB 3.0 specification [13] defines nine rules governing the invocation order (Fig. 1). Example 1: Consider the code listing in Fig. 2. According to the rules of Fig. 1, when productInfo() is invoked, three

269

If multiple interceptor methods are defined for a bean, the following rules governing their invocation order apply: • Default interceptors may be defined to apply to all the beans. Default interceptors, if any, are invoked first. Default interceptors can only be specified in the deployment descriptor. Default interceptors are invoked in the order of their specification in the deployment descriptor. • If there are any interceptor classes defined on the bean class, the interceptor methods defined by those interceptor classes are invoked before any interceptor methods defined on the bean class itself. • The AroundInvoke methods defined on those interceptor classes are invoked in the same order as the specification of the interceptor classes in the Interceptors annotation. • If an interceptor class itself has superclasses, the interceptor methods defined by the interceptor class’s superclasses are invoked before the interceptor method defined by the interceptor class, most general superclass first. • After the interceptor methods defined on interceptor classes have been invoked, then, in order: – If any method-level interceptors are defined for the business method that is to be invoked, the AroundInvoke methods defined on those interceptor classes are invoked in the same order as the specification of those interceptor classes in the Interceptors annotation applied to that business method. – If a bean class has superclasses, any AroundInvoke methods defined on those superclasses are invoked, most general superclass first. – The AroundInvoke method, if any, on the bean class itself is invoked. • If an AroundInvoke method is overridden by another method (regardless of whether that method is itself an AroundInvoke method), it will not be invoked. Fig. 1.

Invocation order of business method interceptors (Chapter 12 [13]).

package ejb; import ... @Stateless @Interceptors(Logger.class) public class ProductFacade extends EJBObject implements ProductFacadeRemote { @PersistenceContext

@Interceptors(Profiler.class) public String productInfo(int id) { Product product = find(new Integer(id)); if (product != null) { return ” Description: ” + product.getDescription(); } else return null; }

private EntityManager em; ...

@AroundInvoke @Override protected Object logMethods (InvocationContext ctx) throws Exception {...}

public Product find(Object id) { return em.find(Product.class, id); } } Fig. 2.

Sample code

methods should be invoked: first the AroundInvoke method of Logger, then the AroundInvoke method of Profiler, and finally, the logMethods(). ¤ The list of method invocations in Example 1 may, however, be incomplete or incorrect. Incompleteness results from the fact that additional interceptors can be defined in descriptor XML files or in additional Java files, e.g., in a superclass of Logger.Incorrectness can be caused if the invocation order has been intentionally changed by the developer, e.g., using a special tag or @ExcludeDefaultInterceptors annotation. Furthermore, while [13] requires proceed() of the InvocationContext to be called in the body of any interceptor implementation, reachability of the call to proceed() cannot be guaranteed. If proceed() is not called during the execution of the interceptor, the execution chain is stopped and a ‘no-op’ is returned to the caller. Moreover, the invocation rules above leave room for vagueness or counter-intuitive behaviour specification. To resolve these issues we have performed a series of experiments with the GlassFish application server [14]. GlassFish application

server is a free application server, provided by Sun Microsystems. Since the EJB 3.0 specification is also owned by Sun, we expected the implementation to adhere to the specification. The following discrepancies, however, have been detected. First, the specification [13] states that can specify total ordering of interceptors on a bean at class level and/or method level. The implementation, however, allows only one such an element: either on the class or on the method level of the bean. Second, the specification states that the invocation order given by the element can be overridden by means of one of the exclude- elements. However, in the GlassFish implementation, the element has the absolute priority and the exclude- elements cannot override it. Third, the specification defines that a element should be used to specify an interceptor method. GlassFish, however, requires the element to be enclosed in the element. In all these situations, the algorithms presented in the next section follow the implementation rather than the specification.

270

main(business method m of a bean class C) 1) IF ( defined on C) OR ( defined on m) FOR class IN ... DO traverseInheritance ELSE a) IF ( OR @ExcludeDefaultInterceptors defined on m) OR ( OR @ExcludeDefaultInterceptors defined on C) GOTO 1b ELSE FOR class IN * ... DO traverseInheritance b) IF or @ExcludeClassInterceptors defined on m, GOTO 1c ELSE i) FOR class IN (@Interceptors(...) on C) DO traverseInheritance ii) FOR class IN C ... DO traverseInheritance c) FOR class IN (@Interceptors(...) on m) DO traverseInheritance d) FOR class IN C ... m DO traverseInheritance. 2) For C perform traverseInheritance. 3) Enqueue (InvocationContext,C,m) to Q. 4) Analyse m using a conventional sequence diagram reverse engineering algorithm: FOR each method invocation C’.m’ i) Enqueue (C,C’,m’) to Q. ii) IF m’ is a business method of a bean injected into C, Notify the user that invocation of m’ might involve interceptors and recommend creating a new sequence diagram. 5) Visualization phase. Using Q, by means of any known visualization approach render the sequence diagram of the business method invocation. Fig. 3.

main: Determining the invocation order.

271

traverseInheritance(class D) 1) L = ∅, S = ∅, c = D. 2) DO a) IF there exists an AroundInvoke method i) Let n be the AroundInvoke method ii) IF n not in L push (c, n) on S. b) Add all methods of c to the methods list L. c) c = superclass(c). WHILE (user-defined(c)) 3) WHILE(not-empty(S)) a) (c, n) = Pop(S); b) Enqueue (InvocationContext, c, n) to Q; c) Analyse n: i) IF there is no call of the proceed() method of the InvocationContext class in n, A) Report an error message. B) GOTO main step 5. ii) IF a call of the proceed() method of the InvocationContext class occurs inside a decision statement or a loop, report a warning. iii) Add (c,InvocationContext,proceed()) to Q. Fig. 4.

traverseInheritance: Interceptors from the superclasses.

* interceptor.Login ProductFacade interceptor.Auditor true productInfo Fig. 5.

Sample deployment descriptor

III. R EVERSE E NGINEERING S EQUENCE D IAGRAMS WITH I NTERCEPTORS Our reverse engineering algorithm consists of two parts: main and traverseInheritance (Figures 3 and 4, respectively). Since the interceptors are invoked sequentially, we opt for a queue Q of all the method invocations as the main data structure used. Each queue element records names of the caller class, of the callee class, and the method called. Order of elements in the queue corresponds to the order of invocation. The query Q is initially empty. Furthermore, traverseInheritance(class D) makes use of a list L and a stack S. The list L contains all methods of all classes on the inheritance path from D to the most general user-defined class from which D inherits. The stack S consists of pairs (c,n), where n is an

AroundInvoke method of a class c on the inheritance path. The EJB 3.0 specification does not state the class responsible for interceptor invocation. It does require, however, an EJB container to create an instance of a class InvocationContext. The instance records the information about the business method invoked and provides a proceed() method which invokes the next method in the chain. Hence, we consider an instance of the InvocationContext class as a caller of each interceptor. If an additional business method m’ is injected in C (Step 4()ii of Fig. 3) main notifies the user that the invocation of m’ may involve invocations of interceptors and suggests her to create a separate sequence diagram for m’. We have chosen to put the decision whether to create an additional sequence diagram in the user’s hands, since not all business methods may be equally interesting for her. Example 2: We illustrate the algorithm by applying it to Example 1. Let the deployment descriptor file be as shown in Fig. 5. We assume the following interceptors to be present: a default interceptor Login.access(), class-level interceptors Logger.logger(), EJBObject.logMethods() and ProductFacade.logMethods(), and method-level interceptors Profiler.measureDuration() and Auditor.doAudit(). The user requests a sequence diagram for the productInfo business method invocation, i.e., she invokes main with m being productInfo and C being ProductFacade. The algorithm proceeds as follows (InvocationContext has been abbreviated to IC). The growth of Q is shown in Fig. 6. main 1 Since is not defined on ProductFacade, we continue to the ELSE branch. 1a The deployment descriptor does not contain , @ExcludeDefaultInterceptors is absent from the Java code. Proceed with the ELSE branch. traverseInheritance(Login) 2 Login has one superclass (Object), so upon termination of the DO. . . WHILE loop, S contains (Login, access()) and L lists all methods of Login. 3b (IC, Login, access()) is added to Q. 3(c)i, We assume that a call to proceed() exists in the 3(c)ii body of access() and that the call is not enclosed in control statements. 3(c)iii Q becomes as indicated in row 1a of Fig. 6. main 1b is present in the deployment descriptor, so we continue to Step 1c. 1c The only class mentioned in the @Interceptors annotation on productInfo is Profiler, and traverseInheritance is called. For the sake of brevity we do not elaborate on this call. Assuming Profiler does not have user-defined superclasses, traverseInheritance extends Q as indicated in Fig. 6.

Step 1a 1c 1d 2 3 4

Q (IC, Login, access()) (Login, IC, proceed()) (IC, Profiler, measureDuration()) (Profiler, IC, proceed()) (IC, Auditor, doAudit()) (Auditor, IC, proceed()) (IC, ProductFacade, logMethods()) (ProductFacade, IC, proceed()) (IC, ProductFacade, productInfo()) (ProductFacade, EntityManager, find()) (ProductFacade, Product, getDescription())

Fig. 6. Growth of the invocation queue in the running example. InvocationContext has been abbreviated to IC.

1d

Auditor is detected in the deployment descriptor, traverseInheritance updates Q. 2 traverseInheritance is called on the bean itself. traverseInheritance(ProductFacade) 2 Since ProductFacade inherits from EJBObject, the DO. . . WHILE loop is executed twice. At the first iteration logMethods() (of ProductFacade) is added to L, and (ProductFacade, logMethods()) to S. At the second iteration since logMethods() already belongs to L, S is not modified. 3b (IC, ProductFacade, logMethods()) is added to Q. 3(c)iii (ProductFacade, IC, proceed()) is added to Q. main 3 Q is extended with a call to productInfo(). 4 This step is carried out by a conventional sequence diagram reverse engineering algorithm, updating Q as indicated in Fig. 6. 5 The sequence diagram is visualized (Fig. 7).

¤

ctx:Invocation

:Login

:Profiler

:Auditor

:ProductFacade

Context

em:

:Product

EntityManager

productInfo(id) access(ctx) proceed() measureDuration(ctx) proceed() doAudit(ctx) proceed() logMethods(ctx) proceed() productInfo(id)

find() getDescription()

Fig. 7.

Sequence diagram for the running example

We conclude this section with a brief discussion of the algorithm’s correctness. We show that the algorithm terminates and that if it terminates, then the output conforms to the 272

invocation rules and discrepancies discussed in Section II (partial correctness). Termination Algorithm traverseInheritance(class D) terminates due to finiteness of the inheritance path from Object to D. Each one of the loops in main terminates due to finiteness of the Java code and of the deployment descriptor. Finally, the GOTO statement in traverseInheritance (Step 3(c)iB of Fig. 4) cannot lead to non-termination as it transfers control to the visualization step of main, and this step does not invoke traverseInheritance. Partial correctness For the sake of brevity we discuss only two rules of those discussed in Section II. Chapter 12 states that the interceptor methods defined by the interceptor class’s superclasses should be invoked before the interceptor method defined by the interceptor class, most general superclass first. The DO. . . WHILE loop proceeds from subclasses to superclasses. In this loop method invocations are pushed on the stack S. The subsequent WHILE loop pops the invocations from S and adds them to Q, reversing the order of elements. Hence, the inheritance path is traversed in the decreasing order. Chapter 12 also requires overridden AroundInvoke methods not to be invoked whether the overriding method is an AroundInvoke method or not. Due to condition of Step 2(a)ii of traverseInheritance the method n will be enqueued only if a method with the same signature did not appear in L, i.e., if a method with the same signature does not appear in a subclass. IV. R ELATED WORK AND CONCLUSIONS In this paper we have considered reverse engineering sequence diagrams involving business method interceptors. Business method interceptors extend EJB with aspect-oriented-type features and are supported by many state-of-the-art Java frameworks. In presence of multiple interceptors, their invocation order is governed by the EJB 3.0 specification [13]. Due to inherent complexity of interceptors as well as due to discrepancies found between the specification and the implementation provided by the specification owner, keeping the invocation order in mind can easily become a burden for the developers or maintainers of enterprise applications. To address this problem we have proposed an algorithm for reverse engineering UML sequence diagrams involving business method interceptors. Reverse engineering of UML sequence diagrams is a wellstudied research problem: both static and dynamic approaches have been proposed. Static approaches, such as [10], [11], [16], do not attempt to execute the system under investigation, and infer sequence diagrams from the source code. Dynamic approaches derive sequence diagrams from observing the system’s run-time behaviour [1], [4]. As we aim at integrating our work in Eclipse, our approach should be applicable to not necessarily executable systems during the development phase. Hence, we have opted for a static approach. Furthermore, we aim at dependencies injected in system code, that were not considered by the existing static approaches [6], [10], [11]. As explained above, interceptors are in a way similar to AOP. In the AOP community sequence diagrams are used in

273

the forward engineering for choice of join points (business methods in our case) [12]. Cross-cutting concerns have been modelled using UML sequence diagrams in [3]. Reverse engineering sequence diagrams of systems with aspects or cross-cutting concerns gets, however, less attention. We consider a number of possibilities as the future work: extending the applicability of the approach, implementing the algorithms in Eclipse and assessing usefulness of the implementation by means of a comprehension study. As mentioned in the Introduction EJB 3.0 supports two kinds of interceptors: business method interceptors, considered in this paper, and life cycle event callbacks. Hence, the first direction for the future work would consist in developing an algorithm for reverse engineering life cycle event callbacks, similar to main (Fig. 3). Furthermore, we intend to implement the algorithms as an Eclipse plugin. To foster practical applicability of the resulting tool the sequence diagram ‘size explosion’ problem [5] should be addressed, e.g., by (selective) constructor hiding [2]. Finally, benefits of the plugin implemented should be assessed by means of a comprehension study. R EFERENCES [1] L. C. Briand, Y. Labiche, and J. Leduc, “Toward the reverse engineering of UML sequence diagrams for distributed Java software,” IEEE Trans. Software Eng., vol. 32, no. 9, pp. 642–663, 2006. [2] B. Cornelissen, A. van Deursen, L. Moonen, and A. Zaidman, “Visualizing testsuites to aid in software understanding,” in CSMR, R. L. Krikhaar, C. Verhoef, and G. A. Di Lucca, Eds. IEEE, 2007, pp. 213–222. [3] M. Deubler, M. Meisinger, S. Rittmann, and I. Kr¨uger, “Modeling crosscutting services with UML sequence diagrams,” in MoDELS, ser. LNCS, L. C. Briand and C. Williams, Eds., vol. 3713. Springer, 2005, pp. 522–536. [4] Y.-G. Gu´eh´eneuc and T. Ziadi, “Automated reverse-engineering of UML v2.0 dynamic models,” in Proceedings of the 6th ECOOP workshop on Object-Oriented Reengineering, S. Demeyer, S. Ducasse, K. Mens, and R. Wuyts, Eds. Springer, July 2005. [5] A. Hamou-Lhadj and T. C. Lethbridge, “A survey of trace exploration tools and techniques,” in CASCON, H. Lutfiyya, J. Singer, and D. A. Stewart, Eds. IBM, 2004, pp. 42–55. [6] R. Kollmann and M. Gogolla, “Capturing dynamic program behaviour with UML collaboration diagrams,” in CSMR, 2001, pp. 58–67. [7] P. Narasimhan, L. E. Moser, and P. M. Melliar-Smith, “Using interceptors to enhance CORBA,” IEEE Comp., vol. 32, no. 7, pp. 62–68, 1999. [8] D. Panda, R. Rahman, and D. Lane, EJB 3 In Action, 2007. [9] Red Hat. Seam - Contextual Components. A Framework for Java EE 5, 2007. [10] A. Rountev and B. H. Connell, “Object naming analysis for reverseengineered sequence diagrams,” in ICSE, G.-C. Roman, W. G. Griswold, and B. Nuseibeh, Eds. ACM, 2005, pp. 254–263. [11] A. Rountev, O. Volgin, and M. Reddoch, “Static control-flow analysis for reverse engineering of UML sequence diagrams,” in PASTE, M. D. Ernst and T. P. Jensen, Eds. ACM, 2005, pp. 96–102. [12] D. Stein, S. Hanenberg, and R. Unland, “Join point designation diagrams: a graphical representation of join point selections,” International Journal of Software Engineering and Knowledge Engineering, vol. 16, no. 3, pp. 317–346, 2006. [13] Sun Microsystems. JSR-000220 Enterprise JavaBeans 3.0 (Final Release), 2006. [14] Sun Java System Application Server 9.1 Reference Manual, 2007. [15] S. R. Tilley and S. Huang, “A qualitative assessment of the efficacy of UML diagrams as a form of graphical documentation in aiding program understanding,” in SIGDOC, S. B. Jones and D. G. Novick, Eds. ACM, 2003, pp. 184–191. [16] P. Tonella and A. Potrich, “Reverse engineering of the interaction diagrams from C++ code,” in ICSM. IEEE, 2003, pp. 159–168. [17] R. Vanbrabant, Google Guice: Agile Lightweight Dependency Injection Framework. APress, 2008.