• No results found

Development of dynamically reconfigurable ground station software

N/A
N/A
Protected

Academic year: 2021

Share "Development of dynamically reconfigurable ground station software"

Copied!
127
0
0

Bezig met laden.... (Bekijk nu de volledige tekst)

Hele tekst

(1)Development of Dynamically Reconfigurable Ground Station Software by. Hendrik Gideon Marais. Thesis presented at the University of Stellenbosch in partial fulfilment of the requirements for the degree of. Master of Science in Engineering (Electronic Engineering with Computer Science). Department Electrical & Electronical Engineering University of Stellenbosch Private Bag X1, 7602 Matieland, South Africa. Study leader: Mr H.R. Gerber. December 2007.

(2) Copyright © 2007 University of Stellenbosch All rights reserved..

(3) Declaration I, the undersigned, hereby declare that the work contained in this thesis is my own original work and that I have not previously in its entirety or in part submitted it at any university for a degree.. Signature: . . . . . . . . . . . . . . . . . . . . . . . . . . . H.G. Marais. Date: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. ii.

(4) Abstract Development of Dynamically Reconfigurable Ground Station Software H.G. Marais Department Electrical & Electronical Engineering University of Stellenbosch Private Bag X1, 7602 Matieland, South Africa. Thesis: MScEng (E&E) December 2007 Applications are normally developed with a specific purpose in mind and when new features are needed the source code has to be modified, recompiled and redistributed. It will be more beneficial if new features can be dynamically added during runtime without the need to disrupt execution, especially in the case of ground station software. This thesis is about the implementation of a dynamic development environment within which a modular system can be created from existing components that can be extended with additional components at any time. The interaction between these components can then be specified which can result in a completely automated system. It is concluded that the graphical tools of such an environment can make it easy for people who do not necessarily have programming knowledge to build a system from existing components that can be extended and reconfigured whenever necessary. iii.

(5) Uittreksel Development of Dynamically Reconfigurable Ground Station Software H.G. Marais Departement Elektries en Elektroniese Ingenieurswese Universiteit van Stellenbosch Privaatsak X1, 7602 Matieland, Suid Afrika. Tesis: MScIng (E&E) Desember 2007 Sagteware word normaalweg ontwikkel met ’n spesifieke doel in gedagte en wanneer nuwe funksionaliteit benodig word moet die bronkode aangepas, herkompileer en versprei word. Dit sal meer voordelig wees as nuwe funksies dinamies gedurende looptyd bygevoeg kan word sonder om die uitvoer van die program te onderbreek, veral in die geval van grondstasiesagteware. Hierdie tesis handel oor die implementering van ’n dinamiese ontwikkelingsomgewing waarmee ’n modulêre stelsel geskep kan word wat uit reedsbestaande komponente bestaan en wat dan met nuwe komponente op enige tyd uitgebrei kan word. Die wisselwerking tussen hierdie komponente kan dan gespesifiseer word om sodoende ’n volledig geoutomatiseerde stelsel te skep. Die gevolgtrekking is dat die grafiese koppelvlak van so ’n ontwikkelingsomgewing dit maklik kan maak vir mense, wat nie noodwendig programmeringskennis het nie, om ’n stelsel op te bou uit bestaande komponente wat dan uitgebrei en aangepas kan word wanneer nodig. iv.

(6) Contents. Declaration. ii. Abstract. iii. Uittreksel. iv. Contents. v. List of Figures. x. List of Tables. xiii. 1 Introduction. 1. 1.1. Problem description . . . . . . . . . . . . . . . . . . . . . . . .. 1. 1.2. Proposed solution . . . . . . . . . . . . . . . . . . . . . . . . . .. 2. 1.3. Overview of document . . . . . . . . . . . . . . . . . . . . . . .. 2. 2 Foundational Work. 4. 2.1. Previous work . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 4. 2.2. Dynamic service based architecture . . . . . . . . . . . . . . . .. 5. 2.3. Existing mechanisms for extensions . . . . . . . . . . . . . . . .. 7. v.

(7) vi. CONTENTS. 2.4. 2.3.1. Component Object Model . . . . . . . . . . . . . . . . .. 8. 2.3.2. Qt Plugin System . . . . . . . . . . . . . . . . . . . . .. 9. 2.3.3. JavaBeans . . . . . . . . . . . . . . . . . . . . . . . . . .. 9. 2.3.4. Java Plugin Framework . . . . . . . . . . . . . . . . . .. 10. Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 11. 3 Development of a Dynamic Structure. 13. 3.1. Software requirements . . . . . . . . . . . . . . . . . . . . . . .. 13. 3.2. Mechanism for dynamic access . . . . . . . . . . . . . . . . . .. 14. 3.2.1. Pure reflection . . . . . . . . . . . . . . . . . . . . . . .. 16. 3.2.2. Scripting languages . . . . . . . . . . . . . . . . . . . . .. 19. 3.2.3. Dynamic compilation . . . . . . . . . . . . . . . . . . . .. 21. Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 21. 3.3. 4 Component Structure and Design. 23. 4.1. Overview of widget structure . . . . . . . . . . . . . . . . . . .. 24. 4.2. Widget class hierarchy . . . . . . . . . . . . . . . . . . . . . . .. 25. 4.3. Runtime widget structure . . . . . . . . . . . . . . . . . . . . .. 27. 4.3.1. Abstract methods . . . . . . . . . . . . . . . . . . . . .. 28. 4.3.2. Abstract tasks . . . . . . . . . . . . . . . . . . . . . . .. 29. 4.3.3. Implemented methods . . . . . . . . . . . . . . . . . . .. 30. Custom widget interface and implementation . . . . . . . . . .. 31. 4.4.1. Example of timer widget interface and implementation .. 32. 4.4.2. Automatic code generation . . . . . . . . . . . . . . . .. 35. Widget configuration . . . . . . . . . . . . . . . . . . . . . . . .. 36. 4.4. 4.5.

(8) vii. CONTENTS. 4.6. Custom widget class hierarchy . . . . . . . . . . . . . . . . . . .. 39. 4.7. Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 42. 5 System Services 5.1. 5.2. 5.3. 43. Remote access manager . . . . . . . . . . . . . . . . . . . . . .. 44. 5.1.1. Implementation with widgets . . . . . . . . . . . . . . .. 44. 5.1.2. Integration with framework . . . . . . . . . . . . . . . .. 45. 5.1.3. Remote server configuration . . . . . . . . . . . . . . . .. 47. 5.1.4. Automatic code generation . . . . . . . . . . . . . . . .. 50. User manager . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 50. 5.2.1. Automatic code generation . . . . . . . . . . . . . . . .. 51. Script manager . . . . . . . . . . . . . . . . . . . . . . . . . . .. 52. 5.3.1. Script hierarchy . . . . . . . . . . . . . . . . . . . . . . .. 53. 5.3.2. Script editor . . . . . . . . . . . . . . . . . . . . . . . .. 53. 6 System Example and Deployment 6.1. 55. System example . . . . . . . . . . . . . . . . . . . . . . . . . . .. 55. 6.1.1. Example description . . . . . . . . . . . . . . . . . . . .. 56. 6.1.2. Adding widgets to the workspace . . . . . . . . . . . . .. 57. 6.1.3. Creating a task for downloading TLE . . . . . . . . . .. 58. 6.1.4. Configuring the widgets . . . . . . . . . . . . . . . . . .. 60. 6.1.5. Automatic updating of TLE . . . . . . . . . . . . . . . .. 62. 6.2. Dynamic upgrading of widgets. . . . . . . . . . . . . . . . . . .. 63. 6.3. Making widgets remotely accessible . . . . . . . . . . . . . . . .. 65. 6.4. Deployment . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 69.

(9) viii. CONTENTS. 6.5. Summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 7 Conclusions and Recommendations. 70 71. 7.1. Evaluation of work done . . . . . . . . . . . . . . . . . . . . . .. 71. 7.2. Recommendations for enhancements . . . . . . . . . . . . . . .. 73. 7.2.1. RPC callbacks . . . . . . . . . . . . . . . . . . . . . . .. 73. 7.2.2. Selective RPC calls . . . . . . . . . . . . . . . . . . . . .. 74. 7.2.3. Asynchronous RPC calls . . . . . . . . . . . . . . . . . .. 74. 7.2.4. Web based access . . . . . . . . . . . . . . . . . . . . . .. 74. 7.2.5. Widget state persistence . . . . . . . . . . . . . . . . . .. 75. 7.3. Conclusion. . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 75. A Method invocation via reflection. 77. B Experiments and Results. 81. B.1 Reflective vs. direct method access time . . . . . . . . . . . . .. 81. B.2 Execution time of interpreted vs. compiled code . . . . . . . . .. 82. C Example of Custom Widget Creation. 84. C.1 Timer widget interface . . . . . . . . . . . . . . . . . . . . . . .. 85. C.2 Timer widget implementation . . . . . . . . . . . . . . . . . . .. 86. C.3 Timer widget configuration . . . . . . . . . . . . . . . . . . . .. 88. C.4 Timer widget configuration panel . . . . . . . . . . . . . . . . .. 89. D Model-View-Controller Design Pattern. 91. D.1 MVC implementation in Java . . . . . . . . . . . . . . . . . . .. 92. D.2 Application to system service managers . . . . . . . . . . . . .. 95.

(10) CONTENTS. D.3 Observable state definitions . . . . . . . . . . . . . . . . . . . . E System Services APIs. ix 98 100. E.1 User manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 E.2 RPC manager . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 E.3 Script manager . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 Bibliography. 111.

(11) List of Figures 2.1. Block diagram of system components. . . . . . . . . . . . . . . . .. 5. 3.1. Illustration of component interaction by means of tasks. . . . . . .. 15. 3.2. Illustration of task execution flow. . . . . . . . . . . . . . . . . . .. 17. 3.3. Example of development environment’s task editor. . . . . . . . . .. 17. 3.4. Example of code automatically generated from a task. . . . . . . .. 19. 3.5. Example of development environment’s code based task editor. . .. 20. 4.1. Overview of the parts a widget consists of. . . . . . . . . . . . . . .. 24. 4.2. Widget class directory tree. . . . . . . . . . . . . . . . . . . . . . .. 26. 4.3. Widget class diagram. . . . . . . . . . . . . . . . . . . . . . . . . .. 26. 4.4. Runtime widget class diagram. . . . . . . . . . . . . . . . . . . . .. 28. 4.5. Example of overriding methods from an interface and an abstract class. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .. 32. 4.6. Timer widget class diagram. . . . . . . . . . . . . . . . . . . . . . .. 33. 4.7. Illustration of calling dynamically compiled scripts from statically compiled methods. . . . . . . . . . . . . . . . . . . . . . . . . . . .. 35. 4.8. Widget configuration class diagram. . . . . . . . . . . . . . . . . .. 36. 4.9. Example of custom widget directory tree. . . . . . . . . . . . . . .. 40. x.

(12) LIST OF FIGURES. xi. 4.10 (a) Example of the Propagators family tree. (b) Class diagram of propagator widgets inheriting the parent’s interface and their own.. 41. 5.1. Remote call via client and server widget interfaces. . . . . . . . . .. 45. 5.2. Example of remote access via widgets as interfaces. . . . . . . . . .. 46. 5.3. Screen shot of a widget’s RPC properties. . . . . . . . . . . . . . .. 47. 5.4. (a) RPC manager’s control panel (b) Remote server settings panel.. 49. 5.5. Pseudo code of code generated to remotely access a task. . . . . . .. 50. 5.6. User manager’s graphical editor. . . . . . . . . . . . . . . . . . . .. 51. 5.7. Pseudo code of code generated for method access control. . . . . .. 52. 5.8. Example of a script family tree. . . . . . . . . . . . . . . . . . . . .. 53. 5.9. Example of development environment’s script editor. . . . . . . . .. 54. 6.1. Screen shot of widget family tree and workspace. . . . . . . . . . .. 57. 6.2. Screen shot of editing downloadTLE task. . . . . . . . . . . . . . .. 58. 6.3. Specifying constant parameter in task editor. . . . . . . . . . . . .. 59. 6.4. Diary widget’s configuration panel. . . . . . . . . . . . . . . . . . .. 60. 6.5. Tracker widget configuration panel. . . . . . . . . . . . . . . . . . .. 61. 6.6. Choosing to edit the downloadComplete task. . . . . . . . . . . . .. 62. 6.7. Calling addElementsFromFile method from SGP4 widget. . . . . .. 62. 6.8. Specifying location of file to load elements from. . . . . . . . . . .. 63. 6.9. Screen shot of graphical runtime environment. . . . . . . . . . . . .. 63. 6.10 Refresh the widget tree to search for new SGP8 widget and choose to replace the old SGP4 widget. . . . . . . . . . . . . . . . . . . . .. 64. 6.11 Dialog used for replacing one widget with another. . . . . . . . . .. 65. 6.12 Remote access configuration for client and server systems. . . . . .. 66.

(13) LIST OF FIGURES. xii. (a). Server system remote access manager panel . . . . . . . . . .. 66. (b). Client system remote access manager panel . . . . . . . . . .. 66. 6.13 Remote access configuration for client and server widgets. . . . . .. 68. (a). Server widget properties panel . . . . . . . . . . . . . . . . .. 68. (b). Client widget properties panel . . . . . . . . . . . . . . . . .. 68. 6.14 Deployment tool dialog window. . . . . . . . . . . . . . . . . . . .. 70. B.1 Direct vs. reflective method access time. . . . . . . . . . . . . . . .. 82. C.1 Timer widget class diagram. . . . . . . . . . . . . . . . . . . . . . .. 85. C.2 Timer widget configuration panel. . . . . . . . . . . . . . . . . . .. 90. D.1 Simple illustration of relationship between MVC components. . . .. 92.

(14) List of Tables B.1 Average execution time(ms) for various number of strings. . . . . .. 83. D.1 User observable states defined in the class gs.manager.user.UserObservable. 99 D.2 Script observable states defined in the class gs.manager.script.ScriptObservable. 99 D.3 RPC observable states defined in the class gs.manager.rpc.RpcObservable. 99. xiii.

(15) List of Abbreviations COM Component Object Model IDL. Interface Definition Language. JPF. Java Plugin Framework. JVM Java Virtual Machine MIDL Microsoft Interface Definition Language MSJVM Microsoft Java Virtual Machine RPC Remote Procedure Call. xiv.

(16) Chapter 1. Introduction 1.1. Problem description. One of the first steps in developing an application is to determine the software requirements. Unfortunately these requirements tend to change during the project life cycle, even after the product has been released. Whenever a new technology needs to be made provision for or an extension is required, the source code has to be modified, recompiled and redistributed. For developers integrating new features into an existing application this can be a daunting task, because it might not have been developed with such a feature in mind. Once the new software is available it either has to update or replace the current version, which may require the system to be temporarily suspended. In a real time application one may require an update, but does not have the luxury of bringing the system to a halt. This may be due to a need to provide critical services to clients or processing information in real time. Ground station software is an example of a system of which the requirements may change over time. It may not necessarily change for a specific mission, but for the next mission the hardware, communication protocols and orbit prediction algorithms, for instance, may change. If the application used for the previous mission did not make provision for these, the software will have to be updated. It can be quite a bottleneck when programmers first have to learn another ones source code and then attempt to extend it with a feature 1.

(17) CHAPTER 1. INTRODUCTION. 2. that may not integrate easily, due to design choices that are applicable only to the previous system. In such a case it may be easier to rewrite the software, but limited time may not make that possible.. 1.2. Proposed solution. This document will look at the approach that was taken to solve the problems mentioned above, by developing a system of which the functionality can be extended dynamically. Users will be able to introduce new features to an existing system during runtime. These features will integrate without the need to recompile and reinstall. Withing this framework a system can be constructed, by making use of already existing components, each performing a function of its own. The system designer can choose which components to use in the desired system and specify how they should interact with one another. Developers are also given the ability to create their own custom components in order to implement specific features, which can then be added to the rest of the system, without interrupting its execution. The benefit of building a system from small parts is that one can use components that have already been developed without having to implement the desired component oneself. For developers it is beneficial, because components can be made and tested independent of the rest of the system, without having to be concerned about what the rest of the system may look like. For users it is beneficial, because existing components can be updated and new ones added without them having to recompile and reinstall the software. These components can then be integrated into the system without having to see a single line of code.. 1.3. Overview of document. The proposed solution indicates that it is necessary to create a development environment within which a system can be built from existing components. Since development of such a system continues during runtime it must allow components to be added dynamically. Users must be able to indicate how.

(18) CHAPTER 1. INTRODUCTION. 3. these components should interact with one another. The interaction between components must also be adjustable during runtime. Chapter 2 shows the foundational work upon which this is built, along with existing techniques used for dynamic extensions. In chapter 3 the various approaches taken to create a dynamically editable structure are discussed. This is followed by an explanation in chapter 4 of the design of the dynamic components that will contain this structure. The services built into the development environment are discussed in chapter 5, after which an example of a system built with this environment is shown in chapter 6. Chapter 7 is the final chapter and discusses the conclusions drawn from the work and makes recommendations for future development..

(19) Chapter 2. Foundational Work 2.1. Previous work. Most of the concepts in this thesis are based on the the work done by R. Barry in his thesis entitled “Design of a Distributed Satellite Ground System” [1]. From his study of existing ground systems he identified certain trends used in their design and implementation that lead to more efficient solutions. The most important aspects he concluded with were as follows: • Design the system in such a way so it can be re-used and make use of existing components where possible, in order to save cost and time. • Make provision for the various subsystems to be distributed across a network. • Human interaction with the ground system should be unnecessary. A level of automation is suggested so as to prevent humans from having to manually perform routine tasks. • Separation of the user interface from the business logic is suggested in order to prevent graphical interfaces from being affected when the system is changed. These principals formed the basis of the ground support system that was consequently designed. Based on the work done by B. van der Merwe in his thesis 4.

(20) CHAPTER 2. FOUNDATIONAL WORK. 5. [12], it is stated that a ground support system can be seen as consisting of a group of services designed to provide the functionality needed to manage the satellite mission. The ground support system developed by Barry thus had a service based architecture. Since the ground support system was designed with future expansion and missions in mind, certain services that are necessary for satellite projects where identified of which some where implemented. Due to the focus on the design of a distributed system a network service was created. Other services could then be registered at the network service in order to be made remotely accessible.. 2.2. Dynamic service based architecture. In this thesis, instead of identifying services particular to a ground station beforehand, provision is rather made to add services during runtime whenever they become necessary. For this to be done it is necessary to be able to add new software components to the system during runtime. In the section that follows some of the existing technologies that make such dynamic extensions possible are evaluated, but first an overview of the new system’s layout will be given.. Figure 2.1: Block diagram of system components.. The block diagram of the system in figure 2.1 shows the various parts it consists of, which can be categorized into the underlaying framework, development.

(21) CHAPTER 2. FOUNDATIONAL WORK. 6. environment and runtime environment. Each layer provides services and functionality to the layer above it. Below follows a description of each of the components: Project Manager The project manager is responsible for all housekeeping tasks related to the project. This includes loading new components and saving and loading new and existing projects. This component is particularly important in the development environment when a project is created. Remote Procedure Call Manager The Remote Procedure Call (RPC) manager is used to manage connections made to remote servers and also to run a local server when the local system is made remotely accessible. It is also responsible for establishing connections with and logging into remote systems and serves as an interface to remote components. User and Security Manager The user manager is used to keep track of the credentials of users and the access rights granted to them. It is used by the runtime manager to authenticate users who attempt to log into the local system. It is also used by the RPC manager for those who attempt to log in remotely. It also determines whether an already logged in user is authorized to access certain functions. Graphical Development Environment The graphical development environment is built on top of the framework to provide a convenient interface with which projects can be created. It also provides graphical interfaces with which all the other managers can be configured and monitored. Dynamic Components This part does not describe a specific function, but rather indicates that components can be added to the system at runtime. The development environment makes use of the project manager to dynamically load components. It can be seen that this part extends from the development layer to the runtime layer. This is to show that the components chosen during development are used during runtime and also that during runtime the development environment can still be used to add new components. Runtime Manager The runtime manager is responsible for creating instances of the components chosen and loading their settings as specified in the.

(22) CHAPTER 2. FOUNDATIONAL WORK. 7. development environment. It also serves as an interface between the graphical runtime environment and the development environment, since changes made in the development environment must be reflected in the runtime environment. Script Manager The script manager is used to load and compile scripts that are called by components and other scripts. It can be seen that it extends from the development layer to the runtime layer. Scripts can be executed prior to runtime, but it will only be able to access the chosen components during runtime, due to the fact that instances of components are only created at runtime. Graphical Runtime Environment The graphical runtime environment is a window that contains the individual graphical interfaces of each component loaded by the runtime manager. This is where components can be interacted with by the users during runtime.. 2.3. Existing mechanisms for extensions. As mentioned, one of the design goals is to make use of existing components as much as possible in order to save cost and time. In [4] Peishu Li makes a distinction between code reuse and software reuse. With code reuse the same source code is used in different projects and is recompiled along with the rest of the code every time it is used. It is thus necessary that all projects that use that code to be written in the same language and whenever another language is used, it will have to be manually translated. Software reuse, on the other hand, requires that the code is compiled only once and then added to applications at a later stage as a binary component. It is clear that in order to satisfy the need for dynamic extensions, software reuse is required, since recompiling the project for each addition will violate the requirement of being dynamic. Such extensions are sometimes referred to as plugins, add-ons, add-ins, etc. and are quite common in applications today. Web browsers such as Mozilla Firefox1 use plug-ins to support extensions for 1. http://www.mozilla.org/.

(23) CHAPTER 2. FOUNDATIONAL WORK. 8. technologies like Flash and Java Applets2 whereas audio players and graphics software use add-ons to make provision for various file formats. In the rest of this section some of the existing technologies that make software reuse possible that were considered will be looked at.. 2.3.1. Component Object Model. Component Object Model (COM) is a component architecture developed by Microsoft. It is used to develop reusable object-oriented software components in a language independent manner. It does this with a language-neutral interface definition language (IDL) that is used to describe the interface of a COM component [7]. The Microsoft IDL (MIDL) compiler can then be used to compile an IDL file into language specific files for languages such as C++, Visual Basic or Delphi. A COM component is compiled once into a binary format and can then be accessed via the interfaces generated from the IDL file from any language that is COM compliant. There is always only one copy of a COM component in memory and it is used by all applications that require it. A COM component is referred to as a server, whereas the applications that access the services it provides, are referred to as clients. It is very important that the contract between the client and server do not change. The contract is the interface that describes the structure of the server and defines the methods(services) it provides. Unfortunately, COM suffers from a few weaknesses that prevents it from being an ideal solution. COM is used extensively in the Windows environment and makes provision for many Windows-based programming languages, but lacks support for other platforms. Another limitation is the problems involved in using it in the Java programming language. Only the Microsoft Java Virtual Machine (MSJVM) makes provision for COM, but it is not available on nonWindows platforms. Also, the MSJVM will be discontinued from 31 December, 2007 [5] after which enhancements will not be made anymore. 2. http://www.java.com.

(24) CHAPTER 2. FOUNDATIONAL WORK. 2.3.2. 9. Qt Plugin System. Qt is a product developed by Trolltech3 that provides C++ libraries and tools that can be used for cross-platform development. It is currently available for Windows, Mac OS X and various distributions of Linux. One of the features of Qt is its support for plugins. Qt provides two APIs for creating, what is referred to as, high-level plugins and low-level plugins. High-level plugins are used for writing extensions for Qt itself such as database drivers, image formats, etc. Low-level plugins are used to extent Qt applications. Unlike high-level plugins, that need to conform to a predefined interface, low-level plugins can provide arbitrary functionality as defined by the developer. When a plugin-based application is being developed with Qt it is necessary to define the interfaces of all the plugins it supports prior to compilation. When a plugin is developed for such an application it is required to implement an interface already known to the application. Qt’s plugin loader may be able to load a plugin, but its functions can only be accessed if it implements one of the interfaces that the application is familiar with. Even though Qt contains features that are similar to what is required in this project it is still not ideal. It may have the advantage of being cross-platform, but applications developed with it still requires to be compiled for each platform, which is not as convenient as Java’s “compile once, run anywhere” philosophy. Similar to COM, its requirement for a plugin’s interface to be known before compilation is also a restriction. It is desirable to be able to add components to the system of which no information is known prior to compilation.. 2.3.3. JavaBeans. JavaBeans are classes written in Java that conform to a specific design pattern in order to be used as components in graphical development tools. Sun Microsystems4 defines a JavaBean as “a reusable software component that can 3 4. http://trolltech.com/products/qt http://www.sun.com/.

(25) CHAPTER 2. FOUNDATIONAL WORK. 10. be visually manipulated within a builder tool” [9, p. 266]. The Java Tutorial [10] lists the following characteristics of a bean: • Builder tools use a process called introspection to determine a bean’s features, such as its properties, methods and events. Introspection is based on Java’s Reflection API and is also extensively used in this project. More is said about reflection in appendix A. • Properties describe the appearance and behavior of beans. Builder tools use introspection to discover a bean’s properties and allow them to be specified during design time. • Each property has an associated accessor and mutator method used to retrieve and set the value of each property respectively. These methods must conform to the specified naming convention required for JavaBeans in order for introspection to be used. • Beans communicate with each other via events. Beans that receive events can be registered at beans that fire events. Builder tools can detect what events a bean can send and receive and provide graphical means of connecting beans with each other. • Beans use Java serialization for persitence. Its properties are saved as a stream of bytes that can later be loaded again to restore its state. JavaBeans can also be seen as ordinary Java objects that simply conforms to a specific design pattern, but it becomes truly useful when used in a GUI builder. There are many such tools available. NetBeans5 is a very good crossplatform, open-source development environment that makes special provision for JavaBeans. The Java Tutorial6 contains a good guide to using it for bean development.. 2.3.4. Java Plugin Framework. The Java Plugin Framework (JPF)7 is defined as a runtime engine that dynamically discovers and loads plugins. Its purpose is to improve modularity and 5. http://www.netbeans.org http://java.sun.com/docs/books/tutorial/javabeans/nb/index.html 7 http://jpf.sourceforge.net. 6.

(26) CHAPTER 2. FOUNDATIONAL WORK. 11. extensibility of Java systems by providing a framework which automatically loads plugins that are available and compatible with the application. In the context of the JPF, a plugin is described as a structured component that describes itself to the framework using a manifest. The manifest is simply an XML file that contains information about the plugin, such as its name, version, the Java class files that contains its code and the resources it is packaged with, such as icons and other necessary files. JPF introduces the concept of extensions and extension points. Extension points are made available to other developers to extend an application by writing a plugin that conforms to the structure defined by the extension point. A plugin that can be extended defines in its manifest file an extension point and gives it a unique identifier. An extension point also specifies parameters it requires. A plugin that can be used as an extension for the extension point then defines in its manifest file an extension and specifies the identifier of the extension point it must be connected to. JPF shows great potential and is very attractive due to its ease of use. The framework takes care of all housekeeping tasks such as discovering plugins, loading them into memory and associating extensions with extension points. It has many more features, but does not completely meet our need. When an application is developed with JPF, it is necessary to define a plugin’s structure beforehand and each extension must also be developed with a specific extension point in mind. The primary drawback is that a plugin’s structure is limited to the extensions that are supported by the parent application.. 2.4. Summary. There are many more technologies available other than those discussed, but of those looked at some common drawbacks can be seen. One of the primary problems encountered is that of platform dependent code. Since we are interested in developing a distributed system we would like to make provision for as many platforms as possible. Even though code can in some cases be recompiled on various platforms, it is still not ideal. It would be better to compile code only once and then use it in many environments..

(27) CHAPTER 2. FOUNDATIONAL WORK. 12. Another problem is that of requiring information about a software component’s interface during development. A dynamically extendable system requires that, previously unknown, components can be added during runtime, after which information about its structure can be dynamically discovered. The most promising solution appears to be the Java programming language. Its support for various platforms solve the problem with platform dependent code. JPF shows that Java classes can be dynamically added during runtime with Java’s class loader. JavaBeans show that information can be extracted from loaded classes by means of introspection. In the next chapter more will be said about how these Java features were used to build a dynamic system..

(28) Chapter 3. Development of a Dynamic Structure 3.1. Software requirements. The results of the previous chapter indicate that the Java programming language provide the necessary features required for developing dynamically extendable applications. The primary features that make it an attractive solution are listed below: Platform independence Java source code is not compiled to native instructions but to an intermediate format called bytecode, which is then executed by the Java Virtual Machine (JVM). This gives Java a platform independent nature which allows its programs to be executed on any platform for which a virtual machine is available. Applications created with the framework, aswell as the framework itself, will therefore be able to execute on more than one platform without having to be recompiled. Dynamic class loader All compiled class files, which contain the bytecode mentioned above, can be loaded into the JVM during runtime by Java’s dynamic class loader. It is this feature which allows functionality to be added to a program during runtime and is also what the JPF, as discussed in section 2.3.4, uses to load plugins.. 13.

(29) CHAPTER 3. DEVELOPMENT OF A DYNAMIC STRUCTURE. 14. Reflection The Reflection API available in Java allows developers to extract information about a class’ structure, such as the names of available methods, their parameters and return types. This is necessary in order to determine what functionality a new class has to offer after it has been loaded into the virtual machine. Introspection, used by JavaBeans, also rely on reflection to inspect a class. Because Java is an object oriented language, developers can easily create self contained components that provide functions which can be used by other components. The ability to make use of existing code in a program is seen in almost all languages, but in most cases this can only be done prior to compilation, once compiled, new code cannot be included. This is the case with statically compiled programs. On the other hand, with the help of Java’s dynamic class loader, the framework can load components at any time during the development of a system or even while it is already running. Reflection can then be used to inspect the loaded class to determine what methods are publicly available for the user to call and in doing so provide the user with a list of services that the component provide. The combination of the class loader and reflection thus allows one to load the bytecode of new components during runtime that was not present during the initial compilation. It also allows one to determine what methods are accessible to the user and then make these new services available to be used. In the next section we will look at the various approaches that were taken in an attempt to create a dynamically editable structure from within which the methods of the components can be called.. 3.2. Mechanism for dynamic access. It has already been mentioned how new classes can be loaded into the virtual machine and how reflection can be used to determine which methods implemented in the classes can be accessed by the user. However the structure from within which these dynamic calls are made has not yet been discussed..

(30) CHAPTER 3. DEVELOPMENT OF A DYNAMIC STRUCTURE. 15. What was needed was a structure wherein a user can specify in a sequential order which methods should be called. As in usual method invocation the user must also be able to provide parameters for the calls, such as constant values or the returned value of a call to another method. This description sounds almost identical to that of methods in general, which is to execute a series of statements, but since the content of these structures must be dynamically editable it was decided to rather refer to them as tasks, so as to make a distinction between methods, that are statically compiled and those that are dynamically editable. Figure 3.1 shows an illustration of how tasks can be used to establish communication between components. It can be seen from the figure that methods are embedded within components. This is to indicate that the methods are statically compiled to provide a specific function. Tasks, on the other hand, lie on the border of a component. This is to show that a task is known by a component, but the content is available to the user to edit. Tasks can thus be edited during runtime to call methods and tasks from other components.. Figure 3.1: Illustration of component interaction by means of tasks.. What is important to note here is that since tasks are known to a component they can be called from the methods defined in the component, but it is up to the user to specify what must happen when the task executes. This con-.

(31) CHAPTER 3. DEVELOPMENT OF A DYNAMIC STRUCTURE. 16. cept is similar to that of events found in JavaBeans and introduces a level of automation which can allow a system to be completely event driver. The next three sections will look at the various attempts that were made to implement this dynamic task structure. Each approach was an improvement on the previous as a better understanding of the problem was being developed and the use of existing technologies explored. The first two approaches, even though not used anymore, are discussed in order to highlight their disadvantages and to show why a better solution was needed and how it lead to the final implementation.. 3.2.1. Pure reflection. Reflection can be used not only to determine what methods a class defines, but also to invoke those methods on an instance of that class. See appendix A for an example of how the class loader can be used to load a class and create an instance thereof and how reflection is then used to invoke its methods. In the first approach reflection was used to call the desired methods. The user was given the ability to create tasks within which a list of the desired methods could be constructed. In addition to calling methods, other tasks that were created could be called as well. This would cause its list of methods and tasks to be called in turn. Figure 3.2 illustrates the process of invoking the task called TaskA. It was initially decided to make the structure of a task as simple as possible by only allowing users to call methods and other tasks. This was so that users who do not have any programming knowledge will be able to construct tasks, by simply choosing which methods from which components to use. This could be done without having to be concerned about control structures such as conditional statements and loops. This decision lead to a very simple implementation for the task’s structure, which is a list of references to the methods and tasks that should be called in sequence..

(32) CHAPTER 3. DEVELOPMENT OF A DYNAMIC STRUCTURE. Figure 3.2: Illustration of task execution flow.. Figure 3.3: Example of development environment’s task editor.. 17.

(33) CHAPTER 3. DEVELOPMENT OF A DYNAMIC STRUCTURE. 18. The development environment’s task editor can be seen in figure 3.3, which gives an example of how tasks are constructed. In this example a task called tick of the component called Timer is being edited. On the right hand side the available components with their methods and tasks are shown to choose from. On the left those that have been chosen can be seen. The first level of nodes represent calls to methods whereas those deeper into the tree represent their parameters. Creating a list of methods to call via reflection is rather simple, but it was soon found that the drawbacks thereof made it an inefficient solution for this problem. The primary disadvantage is slow performance, which is supported by the following quote from the Java Tutorial [10] on reflection. Because reflection involves types that are dynamically resolved, certain Java virtual machine optimizations can not be performed. Consequently, reflective operations have slower performance than their non-reflective counterparts, and should be avoided in sections of code which are called frequently in performance-sensitive applications. In his article on reflection, Dennis Sosnoski compares the average time it takes to call a method directly to that of calling it via reflection. It was found that calling methods via reflection can on average take up to 100 times as long as direct method calls. For details about his experiment consult his article on an introduction to reflection [8]. The results of his experiment, which are applicable to this project, are summarized in appendix B. Another performance bottleneck was that a lot of the work done by the compiler had to be done manually during runtime. Java supports method overloading, which means that multiple methods can share the same name as long as their parameter types are different. The result was that the appropriate method first had to be found by specifying its name and parameter types before it could be called. This process would then repeat for each parameter that is either also a method or a task. Adding features to this structure became increasingly difficult, since each addition required implementing a function that is normally performed by the compiler, but a dynamic version thereof..

(34) CHAPTER 3. DEVELOPMENT OF A DYNAMIC STRUCTURE. 19. It will be shown in the next section how this problem was solved by making use of existing interpreters to implement more advanced programming structures and how it was used to prevent implementing some of it manually.. 3.2.2. Scripting languages. In the previous approach it was mentioned that a lot of the work of the compiler had to be done manually and that implementing new features, such as conditional statements and loops, became hard to do. In order to prevent the compiler from having to be rewritten, it was decided to rather make use of existing tools that are capable of executing code dynamically. This requirement lead to the use of an interpreter. The content of each task was then used to generate code that can be executed by the interpreter instead of requiring one to implement ones own, and probably less efficient, way of calling the methods listed in a task. The interpreter takes care of all the type checking of parameters. It also allows more advanced users to write code directly in the form of scripts, which makes tasks much more flexible. Figure 3.4 shows the code that would be generated from the task that was shown in figure 3.3.. Figure 3.4: Example of code automatically generated from a task.. There are many interpreters written for Java, but since Java is being used for both the framework and custom components it is desirable to use an interpreter that interprets Java code. This will prevent developers who create components from having to learn a new language when writing code for tasks and also enables them to easily understand the automatically generated code..

(35) CHAPTER 3. DEVELOPMENT OF A DYNAMIC STRUCTURE. 20. At the time of writing, two of the most popular interpreters that are implemented in Java and interprets Java code are Beanshell [6] and DynamicJava [3]. Each of these were tested for ease of use and efficiency. Both were found to be very easy to use. Now, with the capability of dynamically executing any Java code, a new feature was added to the system. Users were given the ability to write scripts that would be executed by the interpreter. This gave advanced users more control and made the system much more flexible. Figure 3.5 shows the same task as was shown in figure 3.3, but this time in the source code editor. In this editor users can write any Java code that can be written inside a method body.. Figure 3.5: Example of development environment’s code based task editor.. The new scripting capabilities made it very easy for users to write code the way they usually would in a normal programming environment, but with an undesirable performance loss. Unfortunately, this is the price one pays for the convenience of a scripting language. An experiment was done in order to compare the execution times of the interpreted and compiled code. It was found that interpreting code takes much longer than direct execution by the virtual machine. Even though DynamicJava is on average about twice as fast as Beanshell, in this experiment, it still takes on average 255 times longer than direct execution. The experiment is discussed in appendix B..

(36) CHAPTER 3. DEVELOPMENT OF A DYNAMIC STRUCTURE. 21. The experiment demonstrated how a simple algorithm that consists of only a few lines of code can take much longer to interpret than to execute. Interpreters are useful for adding dynamic features to a program, but in this application it is inefficient for development purposes. This lead to the approach of using a dynamic compiler to compile code during runtime. The bytecode can then be executed directly by the JVM.. 3.2.3. Dynamic compilation. Janino [11] is an embedded Java compiler that can compile either a single expression, a method body, a class body or a complete Java source file into bytecode during runtime, which can then be loaded and executed directly by the JVM. The same experiment that was done with the interpreters were done with Janino. The results are also shown in appendix B. It was found that Janino’s execution time is almost identical to that of direct execution. This makes sense, because Janino also compiles code to bytecode that is executed directly. Janino was then used to compile the task’s generated code. This dramatically increased performance during runtime. Using a dynamic compiler instead of reflection and interpretation thus solves the problems encountered in the previous approaches. By making use of an existing compiler one does not have to manually implement the required functions of a compiler. It also allow users to utilize the features of the Java programming language by writing scripts that can be compiled and executed during runtime. The problem of performance loss is also solved due to the fact that code compiled to bytecode is executed directly by the virtual machine.. 3.3. Summary. In the first solution a task consisted of a list of references to methods that are called via reflection. Due to the complexity of adding new programming structures it was decided to make use of interpreters instead, but it was found that both reflection and interpreters suffered severely from performance loss..

(37) CHAPTER 3. DEVELOPMENT OF A DYNAMIC STRUCTURE. 22. Reflective access is slow when calling a method whereas interpreters are slow at interpreting code. This lead to the use of a dynamic compiler. Tasks are now treated in the same way as methods by giving it a name and even parameters. The content of a task, as specified by the user, is then used to automatically generate code that is compiled to bytecode. With an efficient way of implementing the dynamic task structure, we can now continue to describe the approach that was taken to create components that can be accessed from these tasks. In the next chapter we will look at the structure and design of these components which allows them to easily integrate into a system where they can be used along with other such components..

(38) Chapter 4. Component Structure and Design It has been mentioned that the purpose of this project is to create a development environment within which one can make use of existing components to build a system that can be reconfigured and extended during runtime. An important requirement is that it must be easy for users to access and use the functions provided by the components and only be concerned about how they interact with one another and not how they are implemented. To make this possible, a model has been created to which all components must conform in order to easily integrate into the development framework. From hereon forward these dynamic components will be referred to as custom widgets, or just widgets. A custom widget is an object, created by a developer, that provide specific functionality, such as accessing a database, determining the time of the next pass of a satellite, scheduling the execution of a task etc. In the rest of this chapter it will be described in what way widgets must be developed in order to conform to this model and thus be able to integrate with the development framework.. 23.

(39) CHAPTER 4. COMPONENT STRUCTURE AND DESIGN. 4.1. 24. Overview of widget structure. All widgets consist of three parts: 1) A part created beforehand, which is available in the framework’s API. This part consists of existing classes that must be used by widget developers. 2) A part created by the widget developer, which contains the necessary code to perform the widget’s specific functions and to manage its configuration. 3) And finally a part that is added by the user during runtime that defines how the widgets should interact with one another. From figure 4.1 it can be seen that the second part, the one created by the widget developer, is itself divided into three pieces: An interface, an implementation object and a configuration object.. Figure 4.1: Overview of the parts a widget consists of.. Even though the widget as a whole consists of three layers we will primarily refer to the implementation object in the second layer as a widget, due to the fact that it is the part that contains the widget’s actual methods and thus defines its characteristics. It is also the second layer that is most the important, since it pertains to the development of widgets and will thus be focused on the most in this chapter. It was already mentioned that the implementation object, which we now refer to as the widget, contains the code of the functions provided by the widget. The purpose of a widget’s interface is to list all the methods and tasks that are made available for calls by the user. This interface is implemented by the widget, but only those methods that perform a predefined function are actually overridden in the widget, whereas the content of the tasks are left for the user to decide. Finally, the configuration object contains code that is used to store and edit a widget’s settings..

(40) CHAPTER 4. COMPONENT STRUCTURE AND DESIGN. 25. Each of these parts are discussed in turn in the following sections. In appendix C an example is given of how these parts are used to create a Timer widget. A more advanced version of this widget has actually been implemented, but only the most basic functions are shown in the example for illustrative purposes. During the next few sections the timer widget will also be used to show the purpose of each of the parts a widget consists of.. 4.2. Widget class hierarchy. The framework provides a set of interfaces and classes that must be used by developers whenever a custom widget is being made. It is important for the widget to implement an interface that is known to the framework in order for the framework to be able to perform certain operations on the widget, such as initializing it, accessing its configuration, etc. Even though any class can be dynamically loaded, a common interface is necessary in order for the framework to access the widget in a specific way. All the classes that the framework consists of are stored in a package called gs, which stands for Ground Station, but only those classes relevant to widgets will be discussed in this chapter. The widget’s class tree is shown in figure 4.2. The most fundamental class provided by the framework’s API is the WidgetBase class found in the gs.widget package. This class implements the IWidgetBase interface, which is found in the same package of which more will be said later. The WidgetBase class is only used to store information about a widget, such as its name, tasks, methods, interfaces, package name, etc. A distinction is also made between widgets used during development and those used during runtime, called development and runtime widgets respectively. Both of these classes inherit functionality from the WidgetBase class as shown in figure 4.3. Inheriting from WidgetBase means that both development and runtime widgets have access to the information contained in the base class. Development widgets are used by the IDE during development and serves as an interface between the IDE and the WidgetBase class. Each time the user chooses a widget to add to the system an instance of a development widget is created. This object is then used by the IDE to show the user what methods.

(41) CHAPTER 4. COMPONENT STRUCTURE AND DESIGN. 26. Figure 4.2: Widget class directory tree.. and tasks are available and also to store any widget specific settings defined by the user during development. Users are allowed to add and edit tasks and to access the widget’s configuration object to edit its settings. All this information is stored in the development widget and then used during runtime to create and setup the system as specified by the user. The development widget class can be found in the package gs.ide.widget, but is of no concern to either widget developer or user and is only shown here for the benefit of developers who desire to expand the system.. Figure 4.3: Widget class diagram..

(42) CHAPTER 4. COMPONENT STRUCTURE AND DESIGN. 27. The RunWidget class is of particular importance to widget developers. This class must be extended by all custom widgets created by developers and serves as an interface between the custom widget and the framework. The IRunWidget interface is implemented by the RunWidget class and defines tasks that must be overridden by the user. Both these files are found in the gs.station.widget package. It will be seen in section 4.4 how interfaces are used to define methods and tasks and how distinction is made between the two, but we will now first look at the methods and tasks defined in the RunWidget class and interface and discuss the functions they perform.. 4.3. Runtime widget structure. As mentioned, the RunWidget class must be extended by all custom widgets. It is by means of inheritance that the custom widget in layer 2 builds on the RunWidget class found in layer 1.(See figure 4.1 for an overview of the layers a widget consists of.) Figure 4.4 shows the class diagram of the runtime widget class and its interface along with all their public and abstract methods. The following should be noted in the diagram: • All methods written in italics are defined as abstract and does not contain a method body. • Abstract methods in the RunWidget class must be overridden in the custom widget class by the developer, whereas those in the IRunWidget interface are left for the user to override during runtime. The example in section 4.4 will clarify this requirement. • The RunWidget class is defined as abstract. This is due to the abstract methods it contains and means that it must be extended by another class, which in this case is the custom widget. The methods in the runtime widget’s class and interface can be divided into three categories: Abstract methods, tasks and implemented methods. A description of the methods in each of these categories will be given in the following subsections..

(43) CHAPTER 4. COMPONENT STRUCTURE AND DESIGN. 28. Figure 4.4: Runtime widget class diagram.. 4.3.1. Abstract methods. The abstract methods in the RunWidget class must be overridden by the widget developer. The developer must ensure that these methods provide the functions as described below in order for it to function as the framework expects it to. getUserPanel A widget can optionally have a graphical interface that can be used to either display information to the user or to allow interaction with the widget. If so, this method must return a reference to a Container object, which contains all the graphical components and will be shown in an internal frame in the deployed application’s window. If the widget does not have a graphical interface then this method returns null. getConfigurationPanel This method is similar to getUserPanel, but instead returns a graphical interface with which the widget can be configured during runtime. It also returns null if a configuration panel is not provided. In section 4.5 the configuration object of a widget and how its graphical panel can be returned by this method if desired, is looked at. loadConfiguration Developers are given the ability to store widget related settings in a configuration file if necessary. When a custom widget is made the loadConfiguration method must be overridden which must contain the necessary code to load the configuration from the file specified. It is up to the framework to specify the absolute file path, which depends on the current project’s directory and will automatically call this method immediately after an instance of the custom widget has been created..

(44) CHAPTER 4. COMPONENT STRUCTURE AND DESIGN. 29. startWidget After all widgets have been created, and their configurations loaded, the startWidget method of each widget is called by the framework. This method acts as a higher level constructor and contains code written by the developer that must be executed after all the widgets are created before control is given to the user. One of the tasks that must be called from here is the startup method defined in the IRunWidget interface. The startup method is implemented during runtime and contains user-defined code that must be executed upon startup. stopWidget Similar to the startWidget method, this method contains code written by the developer and is called by the framework when the application is terminated, before the widget is disposed of. It is also very important to note that similar to the startup task in the interface the shutdown task must be called from this method in order to execute the user’s code.. 4.3.2. Abstract tasks. All the tasks in the IRunWidget interface are left for the user to implement during runtime. It is not essential for these to be implemented, but does allow the framework to execute user-defined code by calling these methods. For instance, if the user wants something specific to happen when the widget starts then the startup task can be edited as desired, because the framework automatically calls the startWidget method when the system starts. The following list describes the tasks that can be overridden. startup It was mentioned before that this task must be called from the startWidget method. Whereas the startWidget method contains code the developer wants to have executed upon startup, the startup task contains code the user wants to execute upon startup. shutdown Similar to the startup task, this one also contains user-defined code, but is called by the stopWidget method before the widget is destroyed. logMessage Widget developers can call this method with a message as a parameter for logging purposes in order to log the widget’s state as it.

(45) CHAPTER 4. COMPONENT STRUCTURE AND DESIGN. 30. change. Since logMessage is a task, it is up to the user to decide what to do with this message, if anything. For instance, the message can be written to a file, displayed on the standard output, redirected to another widget for further processing or just ignored. logError This method is exactly the same as the logMessage method, but is used for error messages instead.. 4.3.3. Implemented methods. The rest of the methods that are not defined as abstract are implemented in the RunWidget class and provide functions to both developers and users. A description of each follows. getWidget This method simply returns a reference to the object itself. This is only for convenience when using the graphical task editor in the IDE and not the script editor. In the script editor programmers can refer to widgets via the widget’s name, but in the graphical editor one can do so by choosing to call this method. isConnectedToRpcServer It will be shown later that the framework has built-in support for remote procedure calling. This method will return true if the associated widget is being used to access a remote server, otherwise it returns false. logMessage This method is similar to the logMessage method defined in the IRunWidget interface, but is already implemented in the RunWidget class. It has an additional parameter called addInfo of type boolean. If it is set to true then the message will be appended with additional information such as the name of the current user and the date and time at which message was created. The new augmented message is then passed as a parameter to the logMessage task, which can then be processed by the user’s own code. logError This method serves the same purpose as the logMessage method described above, but is used for error messages instead..

(46) CHAPTER 4. COMPONENT STRUCTURE AND DESIGN. 31. setRpcServer It will be seen in chapter 5 how widgets on remote servers can be accessed via local widgets. Each server can be given a more userfriendly name, much like a URL, to make it easier for users to reference. The setRpcServer method receives as parameter such a name and allows users to specify which server to connect to via the associated widget. useAsRemoteInterface This method is closely related to the previous one. It will be seen later that any widget can be used either locally or as an interface to a similar widget on a remote server. This method receives a boolean parameter to indicate whether the associated widget should be used locally or only as an interface for a remote widget instead.. 4.4. Custom widget interface and implementation. Like many object oriented languages, Java provides the mechanism of an interface. In Java an interface can only contain constant values and abstract methods, which are method signatures without a body. It is not possible to create an instance of an interface, but must instead be implemented by a class of which an instance can then be made. If the class does not override all the abstract methods defined in the interface it implements, then the class itself must be declared as abstract so as to prevent it from being instantiated. An abstract class can then be extended by another class by means of inheritance and if this new class implements the remaining abstract methods an instance of it can be created. Figure 4.5 illustrates this concept. The interface InterfaceA defines two methods, methodA and methodB. InterfaceA is implemented by class ClassA, which overrides methodA, but must be defined as abstract due to methodB that must was not overridden. It is not possible to create an instance of a class that contains abstract methods and must itself be defined as abstract. ClassB then inherits from ClassA and overrides the outstanding abstract method methodB. Finally, because ClassB isn’t abstract and doesn’t contain any abstract methods an instance of it can be created. Inheritance plays a very important role in the creation of custom widgets. When creating a custom widget, an interface must be made by the developer to define all the methods and tasks that the widget must make available to the.

(47) CHAPTER 4. COMPONENT STRUCTURE AND DESIGN. 32. Figure 4.5: Example of overriding methods from an interface and an abstract class.. user. Note that programmatically there is no difference between a method and a task, but we do make a logical distinction between the two. The methods defined in a widget’s interface must be overridden by the widget developer in the widget itself and performs a specific developer determined function. The tasks are left for the user to implement during runtime. This explains the purpose of the IRunWidget interface shown in figure 4.4. The tasks defined in it are not implemented in either the RunWidget class nor by the developer in the widget they are left for the user to do so. This allows the user to dynamically choose what must happen when they are called. Next follows an example of how this concept is applied to the timer widget.. 4.4.1. Example of timer widget interface and implementation. Figure 4.6 shows the class diagram of the timer widget. It can be seen that the hierarchy consists of three levels, which corresponds to the three layers shown in figure 4.1: 1. The RunWidget class and its interface provided by the framework’s API..

(48) CHAPTER 4. COMPONENT STRUCTURE AND DESIGN. 33. 2. The custom widget class and its interface that is created by a widget developer, which inherits from the RunWidget class. 3. And finally the user class that contains all the user-defined code. This is the first class in the hierarchy that is not abstract, because it implements all the methods and tasks from the IRunWidget and custom widget interfaces. It is thus also the first class of which an instance can be made. Note that all the code necessary for this class is automatically generated and compiled during runtime without the user even being aware of it.. Figure 4.6: Timer widget class diagram.. The purpose of the timer widget is to periodically execute a specified command. What this command is, is unknown during development and is left for the user to decide during runtime. The problem is that the widget must be able to.

(49) CHAPTER 4. COMPONENT STRUCTURE AND DESIGN. 34. execute code that does not yet exist and that will only be specified later. This problem is solved by defining a method in the widget’s interface called tick and making the widget class abstract. By defining it in the widget’s interface it is known during development and can be referenced from inside the widget, even though it has not yet been implemented. The tick task is then left for the user to implement during runtime and when it is called by the widget the user-defined code will be executed. The other two methods, startTimer and stopTimer, are used to start and stop the timer respectively. These two methods are available to be called by the user, because they are listed in the interface, but are not made available to be edited since they are already implemented in the widget object by the developer. A few things are important to take note of in figure 4.6: • All the abstract methods defined in the RunWidget class are implemented by the widget developer in the widget class and must perform the functions as described in section 4.3.1. • All methods and tasks that the user must have access to are defined in the IRunWidget and custom widget’s interfaces, which are provided by the framework API and widget developer respectively. • The startTimer and stopTimer methods in the widget’s interface are implemented by the widget developer in the widget itself, because they perform a predefined function and are available to the user due to being defined in the widgets interface. • The tick task defined in the widget’s interface is not implemented by the developer, but by the user during runtime. • All the tasks in the IRunWidget interface are implemented by the user during runtime in order for the framework to be able to call user-defined code, whereas the tasks in the custom widget’s interface are implemented by the user in order for the custom widget to be able to call user-defined code. In this example the tick task is the only task defined..

(50) CHAPTER 4. COMPONENT STRUCTURE AND DESIGN. 4.4.2. 35. Automatic code generation. From figure 4.6 one can see the final level added by the user during runtime, but this is done by using the provided development environment and doesn’t require the user to manually write and compile any code. All the user does is specify how widgets interact with one another, while the code for the class in the last layer and its methods are automatically generated and compiled in the background. When the system is executed for the first time the code for the Timer class shown in figure 4.6 is automatically generated along with a method for each of its tasks. Unfortunately, once a class has been compiled its content cannot be changed, but this is where the dynamic compiler, Janino, comes in handy again. When a task’s code is generated it is placed inside a Janino script instead of directly inside the task’s associated method body. The Timer class and all its methods are then statically compiled, but the scripts that are referenced from within the statically compiled methods can be recompiled by Janino any time during runtime. Thus by adding another level of indirection we have added, what looks like, dynamically recompilable methods to classes. Figure 4.7 illustrates this concept as applied to tasks. It can be seen that each time a task is called it’s associated dynamic script is called in turn.. Figure 4.7: Illustration of calling dynamically compiled scripts from statically compiled methods..

(51) CHAPTER 4. COMPONENT STRUCTURE AND DESIGN. 4.5. 36. Widget configuration. It was shown that one of the three parts a widget consists of is a configuration object. Each developer will treat their configuration differently, but it is important for the framework to be able to access all configurations in the same way via a common interface. Similar to the way that all widgets extend the abstract RunWidget class all configuration objects must extend the abstract WidgetConfig class found in the gs.widget packet. See figure 4.2 for the widget class’ directory tree. The configuration object contains the widget’s settings and can optionally provide a graphical interface with which to view and edit them. It is important to mention here that the configuration object can be used for two purposes. First, it can be used prior to runtime in the IDE while the system is still being set up in order to provide the widget with an initial state. Second, it can also be used during runtime to monitor and change the widget’s settings. It is up to the widget developer to decide whether the configuration can be changed during either, neither or both of these stages, but the distinction must be kept in mind while a configuration object is being made.. Figure 4.8: Widget configuration class diagram.. The methods defined in the WidgetConfig class is shown in figure 4.8. The following should be taken note of: • The class is defined as abstract and must be extended by the widget developer’s own configuration object..

(52) CHAPTER 4. COMPONENT STRUCTURE AND DESIGN. 37. • There are three constant values defined which are used to identify the type of graphical interface the configuration has. Their purpose will be discussed when the createPanel method is described. • The getWidget and getFilename methods are marked as final, which prevents the widget developer from overriding them. • None of the methods are defined as abstract, which means that it is not necessary for any of them to be overridden by the developer. For instance, if the configuration doesn’t have to be saved then neither the save nor load methods will have to be overridden. Next follows a description of each of the methods found in the configuration class. It is important for the widget developer to make sure that the methods are implemented according to these definitions. getWidget This method returns a reference to the widget this configuration is associated with in the form of a WidgetBase class. It is very important to note that during development this method returns a reference to a DevWidget class, but during runtime it returns a reference to a RunWidget class. Since RunWidget is also the base class of all custom widgets the reference returned can be casted to the class of the custom widget and in doing so gain access to all the custom widget’s methods. See figure 4.3 for the widget class hierarchy. If the developer needs information about the widget’s methods and tasks then accessing the widget as a WidgetBase is sufficient, because it contains all the required information, but if the developer needs access to the custom widget’s methods during runtime, then the reference returned by this method must be casted to the appropriate custom widget class. The following example will clarify this. Listing 4.1: Example of casting during configuration 1 2 3 4 5 6 7. WidgetBase base = getWidget () ; System . out . println ( base . getWidgetName () ) ; if ( base instanceof CustomWidget ) { CustomWidget custom = ( CustomWidget ) base ; custom . callCustomMethod () ; }.

(53) CHAPTER 4. COMPONENT STRUCTURE AND DESIGN. 38. Listing 4.1 shows a code sample that can occur in the configuration class of a widget called CustomWidget. On line 1 the getWidget method of the configuration is called to get a reference to the associated widget and is stored in the local variable base, which is of type WidgetBase. On line 2 the getWidgetName method, which is defined in the WidgetBase class, is accessed through this reference in order to display the widget’s name. On line 5 the base reference is casted to a CustomWidget and a reference to it is stored in the local variable called custom and then on line 6 one of its methods is called. Note how on line 4 it is first checked to see if the widget is actually an instance of the CustomWidget class. This will only be so during runtime, which means that it’s only during runtime that the custom widget’s methods can be accessed. The reason the developer would like to access the custom widget during runtime is so that the widget’s methods can be called to reflect changes made to the configuration by the user via the configuration’s graphical interface. createPanel To make editing the settings of a widget easy for users a graphical interface is provided of which there are two types: a user panel and a developer panel. The createPanel method receives a parameter to indicate which of the two must be created, if any. The static integer TYPE_USER will indicate that a panel must be created that will be used after the widget has been created for runtime configuration. TYPE_DEVELOPER is used to indicate that a panel must be created which contains controls used to configure the widget during development, giving the user the ability to configure the widget before it is started. When TYPE_NONE is given then the configuration doesn’t have a configuration panel. The framework calls this method to specify what type of panel must be created, but it’s up to the developer to implement this method to make the appropriate graphical interface. getPanel All this method does is return a reference to the user interface that was created by the createPanel method. This method returns null if no interface exists. reset Whenever this method is called, the configuration will reset to default values. This method is not being used by the framework at the moment,.

Referenties

GERELATEERDE DOCUMENTEN

Second, statistical approaches such as structural equation or state-space modeling allow one to esti- mate conditional ergodicity by taking into account (un) observed sources

Findings – The trend paper identifies a fundamental shift from architectural processes to spatial agency as organizing principle for placemaking, discussing how digital tourism

Now the EU, and in particular the Eurozone, is facing a political, economic and monetary crisis, many people ask the question why some states were allowed to join the

In the evaluation study, the DIIMs suggested that following three drivers were most important: 1. Realizing a focus on the core competences. A decreased in the total cost of

characteristics (Baarda and De Goede 2001, p. As said before, one sub goal of this study was to find out if explanation about the purpose of the eye pictures would make a

The visibility affordance of IT makes work behavior, the type of people and the knowledge they have, status of work processes and external information of customers visiblea.

2.4 1: An overview of all the selected universities for all four case study countries 20 4.2 2: An overview of the percentage of EFL users categorized by language origin 31

The Pro/INTRALINK software version that the Engineering Services department used before PDMLink was built for providing the product data management and product data processes