Automatic Java Code Generation Based on ... - Semantic Scholar

4 downloads 214 Views 59KB Size Report
Automatic Java Code Generation Based on. CORBA IDL plus Semantic Comments. Markus Aleksy, Axel Korthaus. University of Mannheim, Germany.
Automatic Java Code Generation Based on CORBA IDL plus Semantic Comments Markus Aleksy, Axel Korthaus University of Mannheim, Germany {aleksy|korthaus}@wifo3.uni-mannheim.de Abstract 2. The development of CORBA-based applications is often criticized because of its high complexity. In this work we point out which parts in a CORBA-based application represent the recurring infrastructural”plumbing” code, and we describe an approach to supporting the automatic generation of these code fragments for a CORBAbased application in a standard-compliant, languageand tool-independent way. The proposal is based on a smooth enhancement of CORBA’s Interface Definition Language by enriching standard IDL comments with semantic content .

1.

Introduction

In the area of distributed object-oriented applications, the Common Object Request Broker Architecture (CORBA) standard [1] enjoys increasing popularity. On the one hand, this can be ascribed to its independence of computer architecture, operating system, and programming language to be used, and on the other hand it can be attributed to the fact that it provides the possibility to use different Object Request Broker (ORB) products together and to collaborate with different (sub) systems. The main reason for CORBA’s degree of esteem lies in the fact that it specifies an interoperable system architecture which regularizes the exchange of data between implementations based on different vendors’ products. Yet, CORBA is often criticized because of its enormous complexity. Even the Object Management Group (OMG), the originator of CORBA, frankly admits [2]: “CORBA’s flexibility gives the developer a myriad of choices, and requires a vast number of details to be specified. The complexity is simply too high to be able to do so efficiently and quickly.” For this reason, it is worth while researching aspects that could facilitate the development of CORBA-based applications in order to work out potential solution alternatives to the current situation, especially relieving the programmer from tedious standard implementation tasks.

The process of developing CORBAbased applications

We begin by analyzing the process of developing a CORBA-based application. Usually, the first step in this process is to define the application interface which is specified using CORBA’s Interface Definition Language (IDL). IDL is merely a declarative language, i.e., with the help of IDL the data types and interfaces to be used are described by specifying their attributes, operations, and exceptions, but not the actual implementation algorithms. The IDL represents the core foundation of CORBA’s programming language independence: The translation into a specific programming language does not take place before the IDL-based interfaces are compiled by a language-specific IDL compiler. Besides the language mappings described in the OMG standard, i.e. IDL to Ada, C, C++, COBOL, Java, Lisp, Python, and Smalltalk, there are a number of non-standardized mappings to other programming languages such as Eiffel, Objective-C, and Perl, which are only implemented by several ORB products but do not belong to the CORBA specification. After having the stub and skeleton files generated by an IDL compiler, these code frameworks then have to be manually supplemented with the actual application logic by a programmer.

3.

Starting points for automation

Every CORBA-based application contains several lines of recurring code implementing typical infrastructural parts of the application which are almost the same in every application. Mainly, these are code snippets concerning the following activities: • • • • •

initializing the middleware, using CORBAServices, resolving the initial reference, initializing attributes, and including application logic.

First, a CORBA-based application has to create an instance of the Object Request Broker (ORB) and to initialize it. This step has to be performed, no matter whether the client part or the server part of the application is under development. A server application furthermore has to instantiate at least one Portable Object Adaptor (POA) which passes the client requests on to the respective servants. These tasks are more or less standardized and represent first candidates for automatic code generation. Besides the core architecture, the CORBA standard also specifies several services. These services extend the basic functionality of CORBA by providing commonly needed features such as persistence, transactions, or security. By standardizing the interfaces to such services in CORBA, the application portability was considerably improved. In order to obtain the reference to a specific CORBA service, a client has to invoke ORB operation resolve_initial_references, handing over an argument of type string with the required service’s name. Most commonly, the Naming Service [3] is looked up at this point, for it might be the most fundamental CORBA service because of its ability to localize any other distributed services. It was one of the first services to be specified by the OMG and, up to now, has been implemented by almost every ORB vendor. The automatic generation of code for the resolution of references to CORBAServices thus seems to be another aspect suitable for facilitating the development of CORBAbased applications. If object-oriented programming languages are to be used for implementation, there are further possibilities for optimization by automatic generation: • •

creation of constructors and creation of application logic for get and set methods that access attributes.

Usually, the implementation of a CORBA object – which has to be defined with IDL using the keyword interface – in an object-oriented programming language requires the implementation of a constructor. One exception to this rule are stateless CORBA objects such as mere dispatch objects which pass incoming requests on to the actually responsible CORBA objects without processing those requests by themselves. Because IDL does not provide any ways to initialize the attributes of a CORBA object, we also have to consider possible solutions to this problem, so that an automatic generation of the constructors becomes feasible. We chose to reuse the identifiers used for the IDL attributes as identifiers for the attributes of the CORBA object implementation. Thus, it is also simple to generate

access methods to the attributes, because their names are already known. The aspects described above represent potential starting points to the partial automation of the coding of CORBA-based clients and servers. In the following sections, we will explain in detail, how enhancing IDL with semantic comments could address these aspects and be the foundation for automatic code generation.

4.

Enhancing CORBA’s IDL with semantic comments for automatic code generation

The approach propagated in this paper was developed keeping in mind the important goals of standard compliance and application portability. For this reason, we decided to extend the IDL and to hide the new semantics within standard IDL comments. Applying this kind of semantic comments approach provides a lot of advantages, e.g.: •

• •

existing IDL compilers can still process the enhanced IDL interfaces without any problems, because the extensions are hidden in comments and will simply be ignored; by embedding the new semantics within standard IDL, independence of programming languages can be preserved, and modeling tools which use graphical software engineering models as a basis for the generation of IDL files could be upgraded to support the enhanced IDL version. If several different vendors integrated the new IDL version, users would be able to choose their product on the market freely.

In the following sections, we will portray the core elements of our solution.

4.1.

Automatic initialization of attributes and creation of access operations

The following example shows the definition of an enhanced IDL interface which only includes basic data types: interface A { attribute boolean b; // @init { true } attribute string s; // @init { “Hallo“ } }; While conventional IDL-to-Java compilers only create the Java classes implementing the skeleton files by

appending the postfix POA to the identifiers of the CORBA objects’ IDL interfaces, an enhanced IDL compiler implementing our approach would additionally have to produce code frameworks for the servant classes by appending the postfix Impl to the interface names. The @init statement in the IDL specification above defines initial values for the IDL attributes of the servant. The example IDL interface would therefore lead to the generation of the following Java code: public class AImpl extends APOA { private boolean b; private String s;

attribute array a; // @init { 1, 2, 3, 5, 8 }; attribute lseq s; // @init { 1, -2, 4, -9 }; }; would result in the following Java code: public class BImpl extends BPOA { private int[] a; private int[] s; public BImpl() { a = { 1, 2, 3, 5, 8 }; s = { 1, -2, 4 , -9 }; }

public AImpl() { b = true; s = "Hallo"; }

public BImpl(int[] a, int[] s) { this.a = a; this.s = s; }

public AImpl(boolean b, String s) { this.b = b; this.s = s; } public boolean b() { return b; } public void b(boolean b) { this.b = b; } public String s() { return s; } public void s(String s) { this.s = s; } } As can be seen, two constructors are automatically generated for each interface. The first one requires no arguments, and the second one requires argument values for all attributes. Each attribute defined in IDL automatically becomes an attribute of the servant class with the same name, provided that its data type is not complex. The data types to be used can be derived from the programming language mapping. Furthermore, one can detect the automatically generated accessor methods in the listing above. Their signatures are also determined by the IDL mapping to the target programming language, which is Java in our case. Since the names of the servant attributes are known, the logic of the get and set operations can be generated using simple return statements or assignments, respectively. IDL arrays and sequences can be initialized just as easy. Thus, the following IDL interface interface B { typedef unsigned long array[5]; typedef sequence lseq;

public int[] a() { return a; } public void a(int[] a) { this.a = a; } public int[] s() { return s; ); public void s(int[] s) { this.s = s; } } Again, the IDL-to-Java mapping determines the data types of arguments and attributes as well as the method signatures. For example, both IDL arrays and IDL sequences are mapped to Java arrays, as can be seen in the listing. If enumeration types or complex types such as enum or struct are used, their initialization will have to be done as follows: interface C { enum Kind { ONE, TWO, THREE }; struct DataStructure { long l; Kind k; }; attribute Kind k; // @init { Kind.TWO }; attribute DataStructure s; // @init { 100, Kind.ONE }; }; Then, the resulting Java code would look like this: public class CImpl extends CPOA { private Kind k;

public A anA() { return anA; } public void anA(A a) { this.anA = a; }

private DataStructure s; public CImpl() { k = Kind.TWO; s = new DataStructure( 100, Kind.ONE); } public CImpl(Kind k, DataStructure s) { this.k = k; this.s = s; } public Kind k() { return k; } public void k(Kind k) { this.k = k; } public String s() { return s; ) public void s(String s) { this.s = s; } } Should interface definitions be used as attributes in other interfaces, their initialization could be done in the same way. The following example illustrates this: interface D { attribute A anA; // @init { false, “World“ } }; Since interface A contains two attributes (cf. the first example), they both have to be initialized with the help of a corresponding @init statement. The code generator would have to produce the following code then: class DImpl extends DPOA { private AImpl anAImpl; private A anA; private ORB orb; public DImpl() { } public DImpl(ORB orb) { this.orb = orb; anAImpl = new AImpl(false, "World"); anA = anImpl._this(orb); } public DImpl(ORB orb, AImpl aimpl) { this.orb = orb; this.anAImpl = aimpl; this.anA = anAImpl._this(orb); }

} Obviously, class DImpl uses a constructor of class AImpl. Prerequisite to the automatic generation of this constructor is the initialization of the attributes defined in interface A which is triggered by @init statements (cf. the first example). Although attribute orb is not defined in the interface, it is needed for the registration and later incarnation of the servant (see invocation of _this) and, for that reason, is added automatically. If inheritance structures, such as interface E : A { attribute unsigned long ul; // @init { 12 } ; } ; are used, the existing initialization statement from the superinterface (here: A) is reused. The reason for this is that IDL does not support “real” inheritance, but simply reuses the complete definition of the superinterface for the subinterface. Consequently, when implementing interface E in the example above, both “inherited” attributes and newly added attributes have to be defined in order to be able to generate the corresponding Java class. The same is true for the generation of access methods, so that an automatic code generation would lead to the following Java class: class EImpl extends EPOA { private boolean b; private String s; private int ul;

public EImpl() { b = true; s = "Hallo"; ul = 12; } public EImpl(boolean b, String s, int ul) { this.b = b; this.s = s; this.ul = ul; } public boolean b() { return b; } public void b(boolean b) {

this.b = b; } public String s() { return s; } public void s(String s) { this.s = s; } public int ul() { return ul; } public void ul(int ul) { this.ul = ul; } }

4.2.

Generation of frameworks for CORBAbased client and server applications

Commonly, an IDL-based application interface consists of several interface definitions. However, IDL does not provide any hints with respect to the question, whether an individual interface has to be implemented within a specific server application or whether it is used by a certain client application, respectively. Therefore, we need to be able to enrich IDL interfaces with additional information to solve this problem. Furthermore, IDL does not allow to specify whether a specific interface, i.e., the corresponding server or client application, uses one of the CORBAServices defined in the standard. Here’s our approach to these problems. We introduce @create and @endcreate statements which embrace information controlling the process of generating the code frameworks. The @create statement is followed by the name(s) of the client and/or server application(s) to be generated. With the help of the @uses statement code frameworks for the determination and resolution of frequently needed services can be generated automatically. The service name has to be one of the names defined in the CORBA standard, such as RootPOA, NameService or InterfaceRepository. The @deploys statement, followed by the names of one or more interfaces, indicates that these interfaces have to be instantiated as servants within the generated code framework. If two clients named c1 and c2 are to be generated which make use of the Naming Service, the following specification will have to be written: // @create: c1,c2 // @uses: NameService // @endcreate Let’s assume that two server applications are needed. The first one is to be named s1, has to determine references to the root POA and the Naming Service and must instantiate interfaces A and B. The second one is to be named s2, has to determine references to the root POA and the Trading Service and must instantiate interfaces A and C. To achieve this, the following specification has to be written:

// // // //

@create s1 @uses RootPOA, NameService @deploys A,B @endcreate

// // // //

@create s2 @uses RootPOA, TradingService @deploys A,C @endcreate

With the help of an @import statement the application logic of a method can be added automatically. The statement must only be placed next to a definition of an operation. The following example shows the use of an @import statement: interface F { void do_it(); // @import "doit.java" }; In this way, method do_it of class FImpl is filled with code stored in a file named "doit.java". Thus, already existing algorithms can be imported into the generated files directly.

5.

Choice options for the implementation of the automatic program generation

As already mentioned, our solution shows the advantage of being programming language independent since it is based on enhancing CORBA’s language-neutral IDL. Therefore, it can be smoothly integrated into typical software engineering tools for graphical modeling, such as UML CASE tools, which would produce the enhanced IDL interfaces from the graphical models automatically. Since the extensions are placed within comment lines, the generated code can even be compiled by conventional IDL compilers. Beyond that, an enhanced IDL compiler would additionally produce the extended code as described in this paper, so that the developer of a CORBA-based application would have to perform considerably less manual work than before. Such an enhanced IDL compiler could be implemented in several ways. For example, it could be built as one single component responsible for parsing the extensions and generating the corresponding Java code. Or, as we prefer in our approach, it could be a templates-based solution working as follows: here, code fragments are stored as template files in Extensible Markup Language (XML) format. These XML files are read in and evaluated during code generation. Thus, several different ORB product-specific templates can be written and reused. This kind of approach was already used successfully in

[4]. A templates-based architecture seems to be a clever

solution because the products offered on the market today provide very different qualities of CORBA support (cf. [5]). Besides, future developments of the IDL do not inevitably lead to the necessity of changing the code generator. Mostly, it is sufficient to adapt the templates to the innovations. Figure 1 shows an illustration of the code generation process.

6.

Restrictions

Although the approach presented here results in a distinct simplification of the process of developing CORBA-based applications, the generated code nevertheless requires manual completion in most cases. For example, many problems are caused by the scope of the IDL. Since only “public” attributes can be defined, the programmer has to add “private” and “protected” attributes required by the applications by hand. This problem also affects the constructors, since some constructors need to initialize private and protected attributes. Another problem has its origin in the great variety of policies supported by the Portable Object Adaptor (POA). Since a CORBA-based application might instantiate a big number of POAs – with varying policies – an initialization based on information specified by the designer of the enhanced IDL interfaces would be uncomfortable and prone to errors because it would be very complex. One more problem should be mentioned at this point. While the initialization of attributes of simple CORBA data types is feasible as described above, it is not so easy for attributes of type any. Since the CORBA type any is able to store any kind of data type, the specification of

Modeling Tool generates

uses IDL-Compiler

calls generates Client

Skeletons

Enhanced IDL-Compiler

Server

uses

Template Template Templates

Figure 1: Code generation process

Critical review

By enhancing the IDL with semantic comments, both standard compliance and programming language independence are preserved and mappings to several concrete programming languages can be defined. The applied technique of embedding new directives within comment lines is not new, but it is very suitable for the achievement of an important goal: the extensions proposed here do not have any influence on already existing applications and compilers. In our paper, we demonstrated the mapping of enhanced IDL to Java as an example, but mappings to other programming languages should be similarly easy to achieve. Being based on the automatic generation of infrastructural parts of the code, the approach presented in this paper results in a considerable reduction of the development effort for CORBA-based applications. Thus, the developer can fully concentrate on the implementation of the essential business logic of the application under development. As a result, development cycles can be shortened, error possibilities reduced, development costs decreased, and application quality can be improved.

References [1] OMG, “CORBA/IIOP 2.5 Specification”, OMG Technical Document Number 01-09-01, 2001, http://www.omg.org/ technology/documents/formal/corba_iiop.htm. [2] OMG, “CORBA Components – Volume I”, Joint Revised Submission, OMG Document Number orbos/99-07-01, August 1999, http://www.omg.org/cgi-bin/doc?orbos/99-07-01.pdf.

[4] M. Aleksy, and R. Gitzel, “ViDiO - Visual Distribution of Objects”, in: Proc. International Symposium of Visual Methods for Parallel and Distributed Programming (IV2001-VmPDP), London, England, 25.-27. July 2001, IEEE Computer Society, pp. 331-335.

generates Stubs

7.

[3] OMG, “Naming Service Specification”, OMG Technical Document Number 01-02-65, 2001, http://www.omg.org/cgi-bin/ doc?formal/01-02-65.pdf.

Extended IDL-Interface

calls

the initialization values is not sufficient for code generation. Rather, the exact data type of the initialization values would have to be known or specified.

uses

[5] M. Aleksy, and M. Schader, „Standardkonformität von IDL-Compilern und deren Einfluß auf die Interoperabilität”, OBJEKTspektrum 1, 2001.

Suggest Documents