Formal Model Driven Approach to Developing Enterprise Systems Risto Pitkänen Tampere University of Technology Institute of Software Systems P.O. Box 553, FIN-33101 Tampere, FINLAND [email protected] Abstract Developers of distributed enterprise systems face the challenges of ever-increasing complexity and heterogeneous, constantly evolving platforms. One approach to coping with these is model driven development, in which refinement, model execution and code generation pave the way from an abstract model to a specific implementation. In this paper, a model driven approach built on a formal refinement-based specification method is introduced. The approach comprises a specification language for computation-independent and platform-independent modeling as well as model execution and code generation tools. Its advantages include simple yet precise semantics, welldefined refinement, and clear model relationships. The approach is reflected against OMG’s Model Driven Architecture (MDA), and its use is demonstrated by developing a non-trivial example application. 1. Introduction Development of distributed enterprise systems has been facing a crisis due to ever-increasing application-level complexity combined with heterogeneous and constantly evolving platforms. Many professionals agree that it is advisable to avoid the use of implementation-level concepts in early model entities such as UML diagrams. When modeling a system that is to be implemented using Enterprise JavaBeans [16], it may seem only natural to resort to concepts such as Remote, Local and Home interfaces, or to divide components to session and entity beans. Focusing on platform-specific details too early, however, seriously complicates modeling and makes it hard to implement the system on some alternative platform. For example, when developing a specification model of an information system for a public library, one should initially concentrate on concepts such as books, customers, loans and reservations, and what can be done with them, and not on whether a loan is an entity bean or not and which kinds of factory methods its Home interface provides. The OMG Model Driven Architecture (MDA) [14] is an effort to formalize and even automate the above advice. MDA is essentially an approach to using models in specification, design and implementation of heterogeneous systems. Literature mentions model executability, refinement and automatic code generation as techniques that pave the way from an an abstract MDA Computation Independent Model to an actual implementation [15, 3, 4]. So far, MDA has mostly been studied from the viewpoint of using OMG Universal Modeling Language (UML) [12], although the MDA Guide [14] is careful not to restrict MDA to modeling in UML. In some respects, UML is not an ideal language for MDA. For example, it is large and complicated, precise operational semantics are not yet widespread, high-level models tend not to be executable, and model refinement is not precisely defined. We propose an approach to developing distributed enterprise applications that resembles MDA in many respects, and could even be argued to be an instance of MDA. Instead of UML, we rely on an action-oriented specification language, which allows formal refinement of models and verification of model properties. Our models are executable even at the very highest levels of abstraction. Safety properties are preserved by construction in model refinement, and critical properties can be formally verified by using theorem proving or model checking. Models can also be validated and tested by executing them in an animation tool. There is also an experimental code generator and plans for other advanced tools. To reflect our approach against the mainstream of model driven development, we introduce OMG MDA in Section 2. Section 3 gives an overview of our approach and how it relates to the MDA framework. Computation Independent modeling in our approach is discussed in Section 4. Platform Independent Modeling is described in Section 5. Platform specific issues are treated in Section 6, and Section 7 concludes the paper with a summary and some discussion. 2. OMG Model Driven Architecture OMG MDA has been described as an approach to using models in software development [14], or using modeling languages as programming languages [7]. It is based on the well-known idea of separating the specification of a system from the details of its implementation, particularly details that arise from the platform the system operates on. In MDA, models are not just specifications of implementations, but in fact the most important products of a software project. Models do not become obsolete as soon as an implementation is obtained, but they are used through the entire lifecycle of a system, from initial analysis and design to operation and maintenance. With adequate tool support, an implementation might even be generated automatically from a model. MDA specifies three viewpoints to a system: a Computation Independent, a Platform Independent, and a Platform Specific viewpoint. Models are to be written according to each viewpoint. Figure 1 depicts the relationships of different models. Computation Independent Model (CIM) Platform Independent Model (PIM) Platform information + Platform Specific Model (PIM) Figure 1. Model relationships in OMG MDA. A Computation Independent Model (CIM) employs concepts and vocabulary of the problem domain, specifying high-level requirements and/or operation of the system without delving into details of structure or processing. A CIM specifies the system within its operating context, e.g. the business environment in which an enterprise information system is used. A Platform Independent Model (PIM) specifies the structure and operation of a system in a way that is independent of platform-specific details to a specified degree. A PIM can for example be targeted towards a platform-independent virtual machine, or to a class of platforms offering similar kinds of basic services, such as distributed component platforms [6]. MDA does not define the difference or relationship between a PIM and a CIM very precisely; PIMs are just more implementation-oriented and detailed, and they are assumed to relate to CIMs in a meaningful way. A Platform Specific Model (PSM) is obtained by combining the details arising from a specific platform with a PIM as depicted in Figure 1. The result is (a model of) an implementation of the system for that particular platform. In an ideal world, the mapping from a PIM to a PSM is done automatically by an MDA mapping tool, based on a model of the target platform and perhaps some guidance from the developer. The PSM might be expressed using program code, or it could be input to a code generator, which produces an actual implementation of the system, or part of it. As pointed out in [3], precise semantics are a prerequisite for code generation. If the semantics of a model are unclear, code generation can of course be attempted, but the result is likely to be something that was not intended. UML models do not have precise semantics, but a solution exists in the form of Action Semantics [13], UML extension. Action Semantics as such do not define a concrete syntax in which details about processing can be included in a model, but such a syntax is specified in e.g. [17]. Precise operational semantics also make models executable, which enables model testing, early validation and model prototyping. Mappings may also be utilized for refinement of models. Several PIM-to-PIM transformations may be done before the step to a PSM. Refinement is not precisely defined in UML; it is just considered a process that produces a more detailed model in some respect. Refinement may e.g. involve implementing a compound operation as a sequence of simpler messages. Using UML as a modeling language with MDA is not without its problems. Use of Action Semantics is not widespread yet, and its lack of standard concrete syntax is somewhat disturbing. UML has a respectable set of powerful notations, but does not in itself provide guidelines on how to use the notations effectively. The sheer amount of different notations and concepts and metalevels may cause a steep learning curve for those who want to master UML at a level necessary for utilizing advanced MDA capabilities. In addition, many UML notations have their roots in object-oriented programming, which means that developers may to use them to express implementation-level concepts even in computation-independent models, leading to unnecessary complexity [10]. 3. Overview of Our Approach Our approach is similar to OMG MDA, but we do not employ UML for modeling. This choice is motivated by our endeavor towards well-defined refinement and formal semantics, simplicity, orthogonality and executability. Thus far we have focused on one domain: enterprise systems. Our PIMs are therefore targeted towards enterprise computing platforms such as CORBA and Enterprise JavaBeans. Our approach is summarized in Figure 2. refinement CIM (DisCo) Model Execution Tool refinement PIM (one or more components) (TransCo) code generation PSM (generated) (currently EJB) External Components sion interfaces which may be used to customize their functionality or add calls to external components. A central part of the approach is a model execution tool, the DisCo Animator [1], to which we also plan to add support for TransCo and model/implementation interaction. This would enable synchronized execution of a model and its implementation, driving an implementation from a model, using a model as a substitute for test stubs with a partial implementation, observing and obtaining feedback from a running system, and other advanced activities. This work builds on existing research on the DisCo method, language and tools. TransCo and its EJB implementation scheme are new contributions of this paper. 4. Computation Independent Modeling Figure 2. Our model driven approach. Our CIMs are written in the DisCo (Distributed Cooperation) language, which will be introduced in Section 4. A model is produced incrementally using stepwise refinements, leading to hierarchical abstractions and aspectoriented views to the system and its environment. Despite its familiar-looking syntax to programmers, DisCo has formal semantics and support for automated verification of model properties. Informal reasoning based on its operational semantics may also be used. Furthermore, refinements preserve safety properties, which simplifies both formal and informal reasoning. Once a sufficiently detailed CIM has been obtained, a PIM is produced using TransCo (Transactional Components), an extension of DisCo. This model may consist of several components, which together form a (partial1 ) refinement of the DisCo CIM. TransCo could be compared to marking a model [14], or described as a very high-level platform-independent transactional programming language for enterprise systems. An experimental code generator produces Enterprise JavaBeans implementations from TransCo PIMs. Support for other enterprise platforms such as CORBA can be added in the future. Depending on one’s point of view, we either skip the PSM phase or use Java as our PSM language. Nevertheless, the PIM includes all the information needed for implementation, and the EJB code generator includes the EJB platform model, which corresponds to automatic model transformation [14] in OMG MDA. To facilitate integration with components not modeled using our approach, the generated implementation is extensible. In addition to ordinary EJB Remote interfaces through which external components may call services, the generated components expose exten1 Partial in the sense that environment part of the DisCo model is not included in the TransCo model. DisCo [8, 5] is a formal specification language designed for reactive and distributed systems. Based on action systems [2] and Temporal Logic of Actions [11], it allows stepwise refinement by safety-preserving superposition. DisCo is suitable for modeling of enterprise systems partly because it is action based. Actions may be considered abstractions of transactions, which are usually needed in enterprise applications. A recent survey article reviewing many of the ideas behind DisCo is [9]. Our choice of using DisCo instead of UML leads to a few methodological consequences. Our CIMs or PIMs do not consist of separate static, dynamic or other views. There are no numerous different notations, but just one relatively simple specification language. DisCo models are written using relatively fine-grained well-defined refinements and they are structured in an aspect-oriented manner, enabling utilizing different levels of abstraction and separation of concerns. Even CIMs are always executable and tool support exists for model execution. Formal verification of critical properties is also supported. We shall introduce the basic concepts of DisCo using a running example describing a specification of a library. The same example is mapped to TransCo components in Section 5 and automatically generated EJB implementations of those components are obtained using a code generation tool, described in Section 6. 4.1. Layers DisCo specifications consist of layers, which can be seen as aspect-oriented units of modularity, allowing separation of concerns in specification. Our aspects are not to be confused with aspects of aspect-oriented programming (AOP), which are implementation-level entities. DisCo specification aspects may or may not be implemented using AOP. Furthermore, layers enable stepwise refinement, or incremental specification development. Our model of a library is developed using several layers. The first layer specifies the collection management aspect of the system: layer collection_management is The layer will introduce the concepts of titles and copies, and allow adding and removing both from the library collection. 4.2. Classes Data types are modeled using classes much like in ordinary object-oriented languages. The following specification fragment introduces classes Title and Copy: dynamic class Title is isbn: String; author: String; title: String; end; dynamic class Copy is of_which: reference Title; id: integer; end; The above piece of specification is self-explanatory apart from a few details. DisCo classes do not have methods. Objects, instances of classes, are just collections of data. Methods are replaced by multi-object actions. In our library, class Title represents a certain title such as “The Art of Computer Programming, vol. I” by Donald Knuth, while Copy represents a particular physical instance of a title indicated by a reference (of_which) to the corresponding Title. Keyword dynamic in a class definition indicates that objects of the class may be dynamically created and deleted. 4.3. Actions Actions are atomic units of execution consisting of action name, parameters, a guard, and a body. Parameters can be objects, in which case they are called participants, or plain values such as integers or character strings. A guard is a boolean-valued expression. An action is said to be enabled if its guard evaluates to true for some parameter combination. There is no explicit control flow; instead, execution proceeds by nondeterministic selection of one enabled action at a time and executing its body for some parameter combination its guard evaluates to true for. Concurrency is thus modeled in an interleaving fashion. Allowed executions can be restricted by fairness and real-time requirements, which are, however, not used in our example. Action add_title models adding a new title to the collection: action add_title(t: new Title; isbn, author, ti: String) is when not (∃ t2: Title :: t2.isbn = isbn) do t.isbn := isbn || t.author := author || t.title := ti; end; Action add_title has four parameters, one of which (t: new Title) is a participant, the rest being values of type String. Its guard requires that there exists no other title with the same ISBN as the title to be added. Its body is a parallel assignment which initializes the fields of the new title with the parameter values. Keyword new before the type specification of participant t means that this participant is a new dynamically created object. We want to emphasize that actions are never explicitly called. Execution just proceeds by nondeterministic selection of any enabled action and any legal parameter combination. In an implementation this would of course not be the case, but the purpose of a specification is to model precisely all allowed executions. Removing control flow and concepts such as “caller” and “callee” greatly simplifies specifications. Action remove_title removes a title from the collection: action remove_title(t: Title) is when not (∃ c : Copy :: c.of_which = t) do delete t; end; Note that the guard requires that no copies of the title exist, i.e. any copies need to be removed first. The rest of layer collection_management is specified as follows: action add_copy(t: Title; c: new Copy; id: integer) is when not (∃ c2: Copy :: c2.id = id) do c.of_which := t || c.id := id; end; action remove_copy(c: Copy) is when true do delete c; end; end collection_management; Copies of any Titles in the collection can be added as long as they are given globally unique ids. Existing copies can be removed from the collection at any time. 4.4. Refinement Layer structure of the library CIM is depicted in Figure 3. Each arrow depicts a refinement relation, and where two arrow tails meet, there is an implicit composition layer which combines two specification branches. We will explain the contents of all layers after first showing how refinement works in detail. Layer customer_management specifies a very simple aspect of the library that is orthogonal with the aspect specified by collection_management: layer customer_management is dynamic class Customer is collection_ management customer_ management dynamic class Loan is customer: reference Customer; target: reference Copy; end; loans reservations layer loans is import collection_management, customer_management; due_dates complete_ library refines Figure 3. Layer structure of the library CIM. id: integer; name: String; end; action add_customer(c: new Customer; id: integer; name: String) is when not (∃ c2: Customer :: c2.id = id) do c.id := id || c.name := name; end; action remove_customer(c: Customer) is when true do delete c; end; end customer_management; There are no new language concepts in the layer, so we proceed straight to layer loans, which refines the composition of the two layers given above. This is expressed by an import statement in the beginning of the new layer: layer loans is import collection_management, customer_management; In this case the result of composition is simple: all classes and actions of both layers become part of the composition. DisCo has special rules for what is allowed in refinement and what is not. Obeying the rules guarantee that all safety properties (of the form “something bad never happens”, e.g. “there are never two titles with the same ISBN in the collection”) are preserved by construction. Rules required in our example are summarized in the following: • New classes and actions may be introduced. However, new actions may not assign to existing variables, but only variables introduced in the current layer. • Existing classes can be extended by adding new variables. • Existing actions may be refined by adding parameters, strengthening guards by adding new conjuncts, and adding assignments to newly introduced variables to action bodies. Layer loans adds class Loan and two actions to handle instances of it: action do_loan(cu: Customer; co: Copy; l: new Loan) is when not (∃ l2 : Loan :: l2.target = co) do l.customer := cu || l.target := co; end; action return_loan(c: Copy; l: Loan) is when l.target = c do delete l; end; end; We observe that loans apply to copies, and titles are not mentioned here. Notice that classes from both imported layers are referred to, but their variables are not assigned to in the actions. The above superposition step was very simple, because existing classes or actions were not touched. Let us look at a fragment of layer due_dates to see an example of a little more sophisticated refinement: extend Customer by fees: integer; end; extend Loan by due_date: time; end; refined do_loan(cu: Customer; co: Copy; l: new Loan) of do_loan(cu, co, l) is when ... cu.fees < BAN_LIMIT do ... l.due_date := now + LOAN_TIME; end; Here Customer is augmented with a variable indicating the amount of overdue fees on the customer’s account, and each Loan is extended by a field due_date indicating when the loan has to be returned by the latest. Action do_loan is refined by strengthening its guard (a customer may only loan something if her overdue fees do not exceed constant BAN_LIMIT defined elsewhere in this layer) and adding an assignment which records now + LOAN_TIME in the due_date field of the new loan. DisCo has facilities for specifying real-time properties, an implicit parameter now of type time in each action being one of them. 4.5. Rest of the Specification The rest of the specification layers are briefly described in the following:2 Layer due_dates includes, in addition to the fragment shown above, definitions of a few constants, a refined 2 The complete specification is available at http://disco.cs.tut. fi/examples/library/. version of action return_loan which checks if the loan time has expired, and if so, adds an overdue fee to the customer’s account, and a new action pay_fees which decrements the fee balance of its participating customer by an amount specified by an integer parameter. Layer reservations introduces class Reservation, which contains references to a reserving customer and a reserved title. A new action reserve is enabled whenever all copies of the title to be reserved are currently in loan. Action do_loan is refined by two separate actions: an ordinary do_loan, whose guard is strengthened to require that there are more copies of the title available than pending reservations, and fetch_reserved, which has a new participant of class Reservation, and whose guard requires that the Reservation has been made by the participating customer and its target is a Copy of the reserved Title. Layer complete_library is an empty refinement of the composition of layers reservations and due_dates. The composition rules of DisCo cause classes and actions that have common ancestors in the specification hierarchy to be combined, which results in a library whose do_loan action, for example, contains the refinements given in both ancestor layers. The complete library specification is being executed in the DisCo Animator in Figure 4. Note that also any earlier layer can be animated. Animator shows the current states of specification objects and allows the user to select enabled actions for execution. The screen has been grabbed at the moment of execution of action return_loan. Execution history is depicted graphically as a kind of a generalized sequence diagram. 5. Platform Independent Modeling Code generation directly from a DisCo model has been attempted before, but it does not seem feasible in the general case. The gap between DisCo and program code is too wide: code generation cannot produce realistic and efficient implementations. The developer has to supply at least some additional information. The fact that direct code generation from DisCo is not feasible also leads to a natural definition of a CIM in our approach: any model written in plain DisCo is considered a CIM. One possibility for expressing the required extra information is to extend DisCo with language constructs capable of expressing sufficient detail for code generation. This is the approach we have chosen. Figure 4. DisCo Animator. The new language constructs shall not be used inside ordinary DisCo layers, but only in a refinement of the complete CIM. Thus, we add an extra level of refinement below the most detailed DisCo specification, as depicted in Figure 2. Furthermore, certain DisCo constructs (such as actions) are too abstract to be directly implemented and are not allowed at the PIM level. For convenience, we call the language subset only available at the CIM level DisCo, and the PIM subset TransCo. According to our definition, any model written in TransCo is considered a PIM. The most important implementability-related requirements for TransCo are summarized in the following: Partitioning. TransCo has to enable partitioning of a DisCo specification into system and environment parts, and further partitioning of the system part into one or more components with well-defined interfaces. Components are needed in order for the system to be efficiently distributable. Parameter binding. Let us consider action return_loan of the library example. In DisCo, any combination of Copy and Loan satisfying the guard condition may be nondeterministically picked, while in an implementation, the user would provide one of the participants and the other would be computed thereof. TransCo has to provide facilities for binding parameters by computing them based on other parameters. Control flow. The execution model of DisCo has been designed from the viewpoint of specification. Substituting nondeterminism for control flow is not feasible in an implementation. In TransCo, more explicit control flow is required. The following subsections introduce TransCo language constructs and discuss how the above requirements are fulfilled. 5.1. Components The step from a DisCo CIM to a realistic and efficient distributed implementation requires two kinds of partitioning. First, the model has to be partitioned into system and environment parts. This is done in TransCo in a straightforward manner: whatever is not specified in the PIM is considered part of the environment. The CIM still documents possible assumptions about environment behavior. The system part is further partitioned into components with well-defined interfaces. This is a process entirely up to the developer. Often the layer structure of the model leads to a useful partitioning, but sometimes some other way of dividing the system into components is more appropriate. In our library example, a suitable partitioning arises more or less directly from the layer structure. The library will consist of components collection_management and customer_management, mutually orthogonal aspects easily modularized as components, and loan_management, which combines features from layers loans, reservations and due_dates. Let us begin with component collection_management. In TransCo, we first indicate the name of the component and the name of the DisCo layer that induces the complete CIM: attribute author : String; attribute title : String; unique key (author, title); end; Keys provide means of obtaining references to objects. They are analogous to database keys, but function in an object-oriented fashion. Keys in TransCo are conceptually simple, declaring and using them is straightforward, and there are no separate storage interfaces such as EJB or CCM “Homes.” We indicate that attribute isbn is the primary key of class Title above. A class operation (i.e. an operation that can be invoked without access to a specific instance of a class) _find(String) is now automatically generated into class Title. For example Title._find(’’123456789’’) returns a reference to a Title object with ISBN number 123456789, or null if no such title exists. An additional unique key consisting of fields author and title is defined, leading to automatic generation of a class operation _find_by_author_title(String, String). Note that keys consisting of just one field can be defined by including the key specifier in parentheses after the attribute type, while compound keys can be defined separately after the attributes they consist of. Class Copy is implemented in a similar manner. In this case we define a non-unique key as well: class implementation Copy is attribute of_which : reference Title (key); attribute id : integer (primary key); end; A class method _find_by_of_which(Title) is generated, but as the key is not unique, its return type is set Copy (TransCo for set of copies) instead of Copy. component collection_management of complete_library is In TransCo, we can define variables inside component scope. We will implement the selection of unique id’s for Copy objects as required in the CIM with a running index: var next_free_id : integer := 1; 5.2. Classes, Attributes and Keys There are two kinds of classes in TransCo: a class can either be an implementation of a CIM class (indicated by the keyword implementation) or a new class not part of the CIM. The name of a class implementation must correspond to some class in the CIM, and it must implement the variables of the corresponding CIM class as attributes or operations. Roughly the same rules of superposition apply to the DisCo-to-TransCo step as to DisCo-to-DisCo steps, and safety properties are thus preserved. Classes may also define keys as in the following: class implementation Title is attribute isbn : String (primary key); 5.3. Interfaces and Transactions Components may expose one or more named interfaces. An interface consists of transactions. Transactions are atomic compound operations that may be called by a client. The client is another transaction or the environment. Analogously to classes, there are two kinds of transactions, namely the kind that are implementations of CIM actions, and the kind that are new at the PIM level. Component collection_management exposes one interface, default, which is a special interface name meaning that the name of the component itself refers to this interface in a context in which an interface name is required: interface default is Transactions look a lot like actions. A transaction has a parameter list and a combination of a guard and a body: transaction add_title(isbn: String; author: String; title: String) t: new Title; of complete_library.add_title(t, isbn, author, title) is when Title._find(isbn) = null; t.isbn := isbn; t.author := author; t.title := title; end A transaction may also have local definitions and an action call (complete_library.add_title(t, isbn, author, title)) as above. If an action call is present, the transaction is considered to be an implementation of the “called” CIM action. An action call is required in order to bind formal parameters of an action to parameters and local definitions of a transaction. This binding is needed in order to define the refinement relationship between a PIM and a CIM. An action call does not, however, add to the functionality of a transaction. Unlike an action, a transaction is actually called, and the caller supplies only those parameters that are the required inputs. Compare this to a DisCo action that indicates all its participating objects and required values as its parameters, regardless of whether they are “inputs”, “outputs” or something else. In the case of add_title, isbn, author and title are input values, while t: new Title is the object to be created. Therefore, only the former three are listed as transaction parameters, and t is defined as a local reference to a new Title object, while the action call complete_library.add_title(t, isbn, author, title) binds action formals to the parameters and the local. The body of transaction add_title contains a guard statement (when. . . ) and three assignments. The body is executed using transactional semantics: if any of its statements fails, the whole transaction is aborted. The TransCo expression Title._find(isbn) = null is logically equivalent to the action guard not ∃t2: Title :: t2.isbn = isbn in DisCo. There may be several guard statements, and their conjunction should imply the original action guard. Unlike action bodies in DisCo, transaction bodies are sequential to simplify implementation. Locals can be used as auxiliary variables if the assignments of the original action implemented by a transaction have cyclic dependencies. Transaction remove_title is a straightforward implementation of its corresponding action: transaction remove_title(t: Title) of complete_library.remove_title(t) is when Copy._find_by_of_which(t) = {}; delete t; end; Again, Copy._find_by_of_which(t) = {} is equivalent to the original action guard, not (∃c: Copy :: c.of_which = t). Transaction add_copy only requires a Title object to be passed as a parameter, while the copy to be created and its id are implemented as locals: transaction add_copy(t: Title) c: new Copy; id : integer := next_free_id; of complete_library.add_copy(t, c, id) is when Copy._find(id) = null; next_free_id := next_free_id + 1; c.of_which := t; c.id := id; end; Notice how the originally nondeterministically chosen value id is now replaced by a running index. If we wanted, we could omit the guard statement altogether, obtaining a proof obligation that the expression of the guard is an invariant. Finally, transaction remove_copy is again a straightforward implementation of the action with the same name: transaction remove_copy(c: Copy) of complete_library.remove_copy(c) is delete c; end; This concludes the interface and the component: end default; end collection_management; 5.4. More on Transactions The actions to be implemented by transactions are the ones of the final, complete CIM. For example, transaction return_loan implements the final version of its corresponding action, i.e., it also contains code derived from layer due_dates: transaction return_loan(c: Copy) l: Loan := Loan._find_by_target(c); cu: Customer := l.customer; of complete_library.return_loan(c, l, cu) is when l /= null; -- note! if now > l.due_date then cu.fees := cu.fees + OVERDUE_FEE; end if; delete l; end; end; An interesting detail to notice here is that local l: Loan is initialized as Loan._find_by_target(c). Specifying a copy to be returned determines the loan object as well, as only one loan per copy can exist at the same time. Furthermore, a reference to the needed customer object is obtained from the loan object just fetched. Thus, parameters of the original action are bound to the Copy object passed as a parameter to the transaction and the Loan and Customer objects computed thereof. Hence the guard of the original action l.target = c ∧ l.customer = cu may be simplified to l /= null, which together with the initialization implies the original guard. Of course, to be formal, this should be proved. 5.5. Components, Environments and Calling Transactions Java package TransCo component class interface stateless session bean (XDoclet format) transaction 6. Platform Specifics A PIM written in TransCo could be executed directly, but the language has been designed with modeling in mind. It has an overly restricted set of concepts to be an all-purpose programming language, there are no libraries to speak of, and no run-time environment or distribution middleware that support it exist. Therefore a better choice is to use code generators, which produce implementations (PSMs) which utilize existing languages and middleware platforms. Our first target platform is Enterprise JavaBeans (EJB). We have an experimental code generator, which produces extensible EJB implementations of TransCo components. The basic EJB code generation strategy depicted in Figure 5 is quite simple. Each TransCo component becomes a package containing entity beans and session beans. XDoclet is used in conjunction with the Ant build tool to simplify code generation. XDoclet is a tool that enables declarative EJB programming using a single Java source file per bean, and removing the need for manually providing separate deployment descriptors or local, remote and home interfaces. TransCo classes become entity beans whose persistence is managed by the EJB container. Interfaces become stateless session beans with methods corresponding to transactions of the interface. Container-managed or bean-managed transactionality (the latter is currently not supported by our code generator) is used to execute each session bean method as a distributed transaction. method code Ant build files Database creation files (JSP form interface files) configuration user_conf of library is coll_m: collection_management; cust_m: customer_management; loan_m: loan_management; User(coll_m, cust_m, loan_m.basic_loans, loan_m.reservations); end; (Note that interface default is bound if only component is specified.) The code generator now generates a simple WWW user interface which can be used to call transactions in each interface bound to User. We could as well manually implement a user interface and connect it to the extension interface exposed by the generated library implementation. generator Transactions may be called by other transactions or environment external to a TransCo model. In the library example, no transaction calls other transactions. All transactions are called by the environment. A component configuration file is used to express component connections. In this case, we connect the interfaces of all components to a special User component: entity bean (XDoclet format) Ant + XDoclet + javac Compiled Java component Figure 5. EJB code generator. 6.1. Extensibility The generated EJB implementation needs to be extensible in order to facilitate adding external components such as user interfaces (which might be easier to model using for example UML instead of TransCo) and adding implementation-specific functionality to existing components. We do not want to modify generated code, because re-generation would destroy modifications and they would have to be manually incorporated again. Therefore, each generated entity and session bean exposes an extension interface allowing functionality to be added at certain extension points including: prior and posterior to executing a transaction, and prior and posterior to accessing an attribute or calling an operation. Extensibility is further enabled by the fact that external components can call the services of the generated components in the ordinary way. 6.2. Generating Library An EJB implementation of the full library example has been generated using our experimental code generator. The code generator has also produced a simple Java ServerPages based web interface which enables testing the generated implementation. Furthermore, scripts to create and drop the required database tables have also been generated. As a J2EE execution environment we currently use the Resin application server. The generated library allows managing the collection and customers, loaning, reserving, and using other basic library functions. All data is persistently stored in a relational database, without the developer having had to write a single line of SQL, EJB-QL or other query language. Consistency of the data is ensured by transactional execution semantics. 7. Summary and Discussion filing data. We have described a formal model-driven approach to the development of enterprise systems and reflected it against OMG MDA. The approach builds on earlier research on the DisCo method, language and tools, our new contributions being the model-driven framework, the TransCo language for writing PIMs based on CIMs given in DisCo, an EJB implementation scheme for TransCo components, and an experimental code generator. Our approach differs from the mainstream of modeldriven research, because we do not employ UML for modeling. The rationale behind this is our will to keep things simple, executable and precisely defined all the way through, from the most abstract CIM to implementation. Our definitions of CIM, PIM and PSM are clear, and relationships between models are well-defined. One way to evaluate the usefulness of our approach is to examine its effect on the amount of lines produced by a developer. The library example is 193 lines in TransCo (counting blank lines). Stripped of details related to extensibility interfaces, the generated EJB/XDoclet Java sources contain a total of 1176 lines of code. This does not yet include generated build files and SQL scripts. The generated code does not radically differ from manually produced code in this case. Running XDoclet generates some more code, resulting in a total of 2278 lines of Java. This figure roughly corresponds to the amount of code that would be needed if plain EJB without the declarative facilities of XDoclet was used. Although the above figures of course represent only a rough comparison based on one example, they probably suggest something about the expressiveness of our PIM language and the usefulness of our code generation tool. Gaining in the level of abstraction leads to tradeoffs in lowlevel expressiveness. Everything that can be expressed in Java/EJB cannot be formulated in TransCo. However, our generated implementations expose extensibility interfaces to enable adding of manually produced functionality and components that have been modeled using, for example, UML. Efficiency of the generated implementation has not been measured, but there is nothing that would suggest higher inefficiency than in a typical manually written EJB application using transactions and container-managed persistence. Our future plans include instrumenting the generated EJB code with a DisCo Animator interface, which would allow us to observe, test and drive an implementation using the corresponding CIM and PIM. This would enable e.g. tracing real executions as model animations, using model execution scenarios directly as test cases, executing individual components with the CIM filling in as their environment and other system components, and gathering real-time pro- References [1] T. Aaltonen, M. Katara, and R. Pitkänen. DisCo toolset – the new generation. Journal of Universal Computer Science, 7(1):3–18, 2001. http://www.jucs.org. [2] R. J. R. Back and R. Kurki-Suonio. Distributed cooperation with action systems. ACM Transactions on Programming Languages and Systems, 10(4):513–554, Oct. 1988. [3] E. Breton and J. Bézivin. Towards an understanding of model executability. In Proceedings of the international conference on Formal Ontology in Information Systems, pages 70–80. ACM Press, 2001. [4] J. Bézivin and S. Gérard. A preliminary identification of MDA components. In OOPSLA 2002 Workshop on Generative Techniques in the context of Model Driven Architecture, November 2002. http://www.softmetaware.com/ oopsla2002/mda-workshop.html. [5] DisCo WWW site. http://disco.cs.tut.fi. [6] W. Emmerich. Distributed component technologies and their software engineering implications. In Proceedings of the 24th International Conference on Software Engineering, pages 537–546. ACM Press, 2002. [7] D. S. Frankel. Model Driven Architecture: Applying MDA to Enterprise Computing. Wiley Publishing, 2003. [8] H.-M. Järvinen and R. Kurki-Suonio. DisCo specification language: marriage of actions and objects. In Proceedings of the 11th International Conference on Distributed Computing Systems, pages 142–151. IEEE Computer Society Press, 1991. [9] R. Kurki-Suonio. Action systems in incremental and aspectoriented modeling. Distributed Computing, 16:201–217, 2003. [10] R. Kurki-Suonio and T. Mikkonen. Liberating objectoriented modeling from programming-level abstractions. In J. Bosch and S. Mitchell, editors, Object-Oriented Technology, ECOOP’97 Workshop Reader, number 1357 in Lecture Notes in Computer Science, pages 195–199. Springer– Verlag, 1998. [11] L. Lamport. The temporal logic of actions. ACM Transactions on Programming Languages and Systems, 16(3):872– 923, 1994. [12] Object Management Group. Universal modeling language specifications. http://www.omg.org/uml/. [13] Object Management Group. Action semantics for the UML. OMG document 2001-08-04, August 2001. [14] Object Management Group. MDA guide version 1.0.1. OMG Document Number omg/2003-06-01, June 2003. http://www.omg.org/mda/specs.htm. [15] J. Siegel and the OMG Staff Strategy Group. Developing in OMG’s model driven architecture. OMG White Paper, http://www.omg.org/mda/presentations.htm, November 2001. [16] Sun Microsystems. Enterprise JavaBeans specification, version 2.0, August 2001. [17] I. Wilkie, A. King, M. Clarke, C. Weaver, and C. Rastrick. UML ASL Reference Guide. Kennedy Carter, asl language level 2.5 edition, 2001. http://www.kc.com/download/.
© Copyright 2026 Paperzz