The head buyer for a Fortune 500 chemical company is on site in South America with his supplier, about to order millions of dollars worth of solvent at a reduced price, but before signing the deal he uses a software application embedded into his PDA to check his global inventory. He sees that as a result of an acquisition that took place hours ago on the other side of the world, his company now has an excess of the solvent. He cancels the deal, saving his company millions.
Embedded software is absolutely critical to the success of organizations that cannot tolerate failure. To achieve the highest levels of software quality demanded by such organizations, software developers are increasingly relying upon the Unified Modeling Language™. As a visual programming language, the UML can be used to design and specify Java software for embedded systems, and through UML model-driven design and source code generation from models, increased developer productivity can be realized and software quality improved.
Embedded development projects have traditionally been less successful than other development projects, with over 50% of embedded projects completed months behind schedule, 44% of designs coming within 20% of expectation,1 and a staggering 25% of embedded projects being abandoned completely.2 Despite such dismal statistics, embedded developers face increasing time-to-market pressures and higher quality expectations, with customers insisting on more features with each new release of product. As software becomes prominent on handheld wireless devices, the cost of failure becomes prohibitive, contributing to the mixture of time and quality pressure that has increased the chaos of software development.
With high customer expectations and the cost of failure potentially catastrophic, it's clear that things need to be done differently. Developers are writing good code for the most part, but the complexity of the application, the market enforced deadlines, and the need for quality are exerting too much pressure. One of the root causes of project failure is a breakdown in communication: "What are the requirements?" "Can you describe the system architecture?" "The customer wants X but we have delivered Y." In order to succeed, developers must have a clear understanding of what they are building. Other points of failure in real-time embedded systems include incorrect or misunderstood interfaces and behavior of threads/tasks/processes.
UML has been used with Java in non-embedded development and has been successful. Although the Java language for development in embedded systems is still a new proposition developers are beginning to consider UML as part of their development strategy.
In most engineering disciplines, modeling is entrenched within the development process as an integral piece of everyday activity. Architects, for example, could not build even simple dwellings if blueprints have not been prepared prior to construction in order to achieve success and quality. Models are a simplification of the real world and help us understand what we are building.
While modeling in software engineering has been discussed, studied and used for many years, the practice is still not an industry standard in software development. In many cases, developers have been able to achieve a measure of success by doing things by hand. Moreover, tool support for these modeling languages has not met expectations.
Models and visual models, in particular, are a way for teams to communicate and to better understand what they are trying to build. This is by no means a new concept, but the standardization of the language and advanced tool support has made it much more practical. UML simplifies the complex process of software design, making a "blueprint" for construction. The specification of UML is owned by the Object Management Group (http://www.omg.org.) and was adopted in November, 1997.
Model Driven Development using UML
UML is a visual language that uses a visual syntax to represent a blueprint of software. These blueprints, much like architectural drawings of buildings, use a standard set of icons that have much more semantic meaning than a typical programming language statement, to represent accepted concepts in software engineering.
UML defines a set of diagrams that are used to show relationships between objects in a system. Here is a short summary of these diagrams3:
Class Diagram: The class diagram shows the relationships between a set of classes. This is the most common diagram in UML and is a structural view of how classes are related.
Collaboration Diagram: The collaboration shows the structural organization of objects that communicate with each other.
Component Diagram: The component diagram shows the relationship between components. A component is a physical manifestation of software, and may be a library, executable, DLL, etc. Components are built and combined to form applications.
Deployment Diagram: The deployment diagram shows the relationship between physical entities like a CPU, printer, or workstation. It can also show where components are deployed.
Use Case Diagram: The use case diagram captures functional requirements. It shows the relationships between actors and use cases. Actors are external entities to the system such as users and other systems. A use case is an end-to-end sequence of actions (including variants) that result in an observable and useful result.
Sequence Diagrams: The sequence diagram is an interaction diagram that shows the communication between objects in a time-ordered fashion.
State Diagram: The state diagram contains a finite state machine that describes the behavior of a class. State machines are an excellent way to describe event-driven behavior.
Activity Diagram: The activity diagram shows the flow of control through activities in a system.
Java is quickly gaining a foothold in the embedded development world. At one time the language was thought to be too big and too slow for use in embedded systems. Sun Microsystems took this as the driving force behind what has become the Java 2 Micro Edition™ (J2ME™). Java for embedded systems is not limited to J2ME™, but it seems to be the front-runner as the Java platform for a variety of embedded and handheld devices. Java has certain strengths that may appeal to the embedded developer, such as excellent Object-Oriented (OO) programming support, strong typing, exception handling, built-in threading, large existing frameworks, and most importantly, a safe and stable run-time environment. The run-time performance of Java is improving through the use of Just In Time (JIT) compilers and hardware Virtual Machines (VMs). Memory footprint, although larger in comparison to small C-based applications, is improved through the introduction of smaller and efficient VMs and significantly smaller class frameworks.
Java offers some excellent features for the embedded developer. Those developers who are tired of debugging to find pointer bugs and applications that hang with no indication of errors will welcome Java's strong typing, OO support and run-time environment. These features do not, however, alleviate all of the burdens of complex software development for the embedded developer.
As more complex devices emerge, and the capabilities of the target systems increases, the demand for complex behavior and sophisticated features also increases. J2ME is not simply a cell-phone platform -- it is also a platform for game consoles, set-top boxes, Internet appliances, etc. In fact, these applications likely have behavior, concurrency, reliability and availability requirements that desktop applications do not offer. J2ME applications are embedded applications that must react quickly and efficiently to input from devices and users. In many cases, complex concurrent behavior is required, e.g., an application that contains communicating threads, device drivers, user interface and a network connection. A useful abstraction for designing concurrent systems is the active object -- an object that has its own thread of control. Typical Java objects are passive: they only react to method calls. There is no activity by the object when no method is called. An active object (see Figure 1) has its own thread of control and process messages that arrive through a message queue rather than from method calls. Message queues allow for asynchronous communication; therefore, the active object can perform activities while messages arrive. Messages are processed when current activities are complete. The active object concept can be directly modeled in UML and provides a convenient and powerful building block for development in embedded systems.
|
| Figure 1: The active object pattern. |
An active object has an encapsulation boundary that protects the inner behavior and state and an external interface defined by ports. Active objects communicate using messages rather than operation (method) calls.
UML provides a powerful building block for system design through the combination of the following: capsules, which are a specialized class with its own thread of control that communicates with other capsules using message queues, represents active objects in UML, and comprises a portion of the UML toolbox that addresses a key need of the embedded and real-time developer; ports, which are interface objects of capsules that allow for message-based communication between capsules; and protocols, which define the list of signals that are accepted by and sent on a port. The combination of capsule, port and protocol is analogous to hardware design where engineers build systems from components (e.g., logic chips, ASICs, micro-controllers) that have established interfaces (pin outs) and connect them together on a schematic diagram. The behavior of a capsule, i.e., the way it reacts to external stimulus, is defined with Hierarchical Finite State Machines (HFSMs). State machines are also common in hardware design and prove useful for building reactive and event-driven software. The state machines in capsules react to events that arrive as signals on the public ports -- the public interface of the capsule to the external environment. Therefore systems built with capsules are networks of cooperating and communicating state machines, similar to the architecture of complex hardware logic. Using smaller building blocks with well-understood behavior and interfaces is a proven way to achieve success with large-scale systems.
Code Generation from UML Models
A practical benefit of using UML models for system architecture and design is the ability to automatically generate source code. UML is a programming language (higher level than C++ or Java) and UML models are formal enough to generate a complete application. The combination of structure defined by collaboration diagrams (see Figure 2), relationships defined by class diagrams (see Figure 3), communication by ports and protocols and behavior with state machines provides a rich and detailed description. Code generation from such models is mature and has been available for over a decade.
|
| Figure 2: A UML role collaboration diagram. This diagram defines how capsules are composed and connected. |
|
| Figure 3: A UML class diagram. The boxes represent classes and the lines between boxes represent relationships. In this example, aMidlet has a dependency on InjectEvent, Container is composed of MyApp and Limiter. |
| (click here to enlarge) |
Why is code generation important? Code generation extends the usefulness and power of visual modeling by not only giving a developer visual building blocks but a way to generate small and fast code from these building blocks. Code generation from UML models eliminates repetitive and error-prone manual coding that can cripple any project. Capsules, ports and protocols provide a convenient communication mechanism that would normally be hand-coded. Code generation enhances the productivity gained from visual modeling.
UML Modeling for Mobile and Embedded Java
So far we have discussed the benefits of UML and Java independently. How does UML apply to J2ME? The configuration and profile class framework can be made into a UML library, i.e., the developer can access the class framework as a set of visual tools (classes, diagrams, etc.) and use them as needed. For example, a developer writing a Mobile Information Device Profile (MIDP) application can use the available classes from the Connected Limited Device Configuration (CLDC) and MIDP class framework. A typical tool allows the developer to make use of the framework by just dragging and dropping any of these classes into a diagram, adding another class and a generalization (inheritance) relationship (see Figure 4). The ability to use the class framework and the application as a visual model greatly enhances productivity.
|
| Figure 4: A UML Class Diagram showing how a MIDP MIDlet is created from the CLDC/MIDP framework. Note that the aMidlet class realizes (implements) the CommandListener interface. |
Mobile and embedded Java applications are similar to other embedded systems. They typically use threads (or tasks) to accomplish the required response to events arriving from users, devices and other systems through intermittent network connectivity. The problem domain is more complex and time sensitive. The use of capsules to model concurrent active objects and the use of state machines to describe their behavior provide a developer with the tools to represent these concurrent active objects. Compact and efficient Java code is generated from a capsule's state machine. Any detailed coding, such as in class operations and state transitions, is part of the model and is included in the generated Java code (see Figure 5). Classes and capsules are built together in a component that specifies how the code is generated, compiled, and packaged. Tool support for such activities exists today and is essential to make model driven development practical.
|
| Figure 5: A UML state diagram. |
State diagrams define the behavior of a capsule to external events that arrive from ports. Messages trigger the transitions of the state machine; action code can be added to transitions which is executed when the transition is fired.
UML and Java are not silver bullets4. They do not provide the magic solution to all embedded development problems. However, it is possible to make significant steps to improve the productivity of a developer by using UML model-driven development and robust and powerful OO language like Java. Alleviating the chaos of complex software development is the primary motivation for using UML to describe and build software.
Java is a good language for embedded systems but a programming language alone cannot solve the problems and pains of the embedded developer. The use of UML for Java applications is a synergistic combination. Embedded and wireless applications differ from desktop and server applications by the need to handle concurrent asynchronous events within strict time constraints. Active objects are a proven pattern for concurrent systems and these are modeled in UML with capsules. The availability of Java class frameworks as UML models allows for quick and convenient re-use. Finally, code generation increases UML's value to the developer by reducing errors and improving productivity. Consider UML and model driven development for your next embedded project!
1 Electronics Market Forecasters, April 2001
2 Embedded Developer Systems Survey, Summer 2001
3 G. Booch, J. Rumbaugh, I. Jacobson, The Unified Modeling Language User Guide, Addison-Wesley, 1999.
4 F.P. Brooks Jr. No silver bullet: Essence and accidents of software engineering. IEEE Computer, pages 10-19, April 1987.
Bill Graham is a Technical Marketing Engineer at IBM Rational Software. He has over 13 years of experience developing real-time and embedded systems for commercial and military projects. He is currently part of the Rational Embedded Solutions team. He has delivered seminars and presentations on model driven development for embedded systems. He has a B. Eng. and a M. Eng. from Carleton University.
Comments (Undergoing maintenance)





