- 1 -
Software Component Basics

A book on JavaBeans wouldn't be of much use if it didn't begin by explaining the conceptual foundations of software components, which form the basis of the JavaBeans technology. Through its specific approach at providing a software component technology, JavaBeans enables software developers to design and create reusable pieces of software that easily integrate with each other, with applications, and even with development tools. If this description of JavaBeans makes sense to you, then great. If not, don't feel discouraged, because I deliberately jumped ahead by describing JavaBeans in this manner. Even though it lies at the heart of JavaBeans, the concept of a software component is not something you are expected to know going into this book. In fact, the purpose of this chapter is to start off the book on a proper footing by exploring software components and why they are important to the future of software.

The best place to begin when uncovering the magic behind software components is to look at the reason why they were invented to begin with; in other words, what problems are software components trying to solve? The most simple and direct answer to this question is software reuse, which is the challenge of leveraging as much previous work as possible in each new development project. Even though a variety of different software component approaches have evolved, until recently none have come far enough in offering a means to create fully reusable software. In this chapter, you learn a great deal about this problem and the fundamental concept employed to solve it: the software component. You learn how software components improve software development in a variety of ways, which enables developers to spend more time leveraging existing code instead of hacking it or throwing it away in lieu of new code. Most important, this chapter lays the groundwork for JavaBeans, which is perhaps the most exciting and promising software component technology available.

In this chapter, you learn the following:

The Need for Software Components

Change is embraced in the innovative world of software development probably more than in any other professional endeavor. Software enters a final
commercial state for only a brief period of time, after which the next batch of enhancements and improvements is immediately planned and begun. For this reason, no other industry can more proudly boast of its products being "new and improved" than the software industry. However, all of this innovation comes at a price; that price is the stress of trying to work miracles in short periods of time. Software developers are always under extreme pressure to work faster and deliver better results. No doubt this pressure is present in plenty of other professions, but the software development community prides itself on its ability to meet seemingly unattainable deadlines.

In their quest to deliver feature-packed applications in a short period of time, software developers often are forced to cut corners in the midst of turning out applications. These cut corners typically result in code that is highly dependent on the specific application, with little usefulness beyond that particular project. Although this is acceptable in most cases, the end result is that the efforts put into a finished project offer little to aid in the development of future projects. In other words, it's back to the drawing board, or keyboard, for each new project. Wouldn't it be nice if you could somehow reuse similar features developed for one application in another application requiring the same functionality? Of course it would, but I'm getting ahead a little.

Regardless of how careful developers are about not cutting corners throughout a project's development, the mere size of a project often can lead to a great deal of problems. The most careful and thought-out design can lead to utter confusion when a project grows beyond a certain manageable size. In this situation, it becomes extremely difficult to make sense of a bloated application that has reached an unmanageable state of confusion and complexity. More than a few software development teams have thrown up their hands and started anew on projects after realizing that they were heading down a winding path of complexity with an obfuscated code base. Even if the code is well written, there simply are limits to the degree in which organization can help in making sense of things at the code level.

Lest you think I'm behind the times or just being overly negative and ignoring recent advances in software development technologies, let me say that object-oriented design methodologies and programming languages have come a long way toward improving this scenario. Even so, none of these languages has truly answered the need for a fully reusable software standard. As nice as C++ classes are, they still are inherently limited by the address space in which they execute, the specific protocol within which they communicate, and the platform for which they are compiled. In other words, programmers can reuse C++ classes only within the specific context of the applications they are developing, which is sometimes useful but nonetheless limiting. The same thing applies to Java classes, which are functionally similar to C++ classes, although they do add the benefit of being cross-platform in most situations.


New Term: A platform is a particular operating system and runtime environment, such as Windows 95 or Solaris.


New Term: Cross-platformrefers to software that can execute on different platforms without any special modification.

OK, so I've painted a fairly ugly picture of the software world and left you feeling hopeless and desperate, right? Maybe not, but hopefully I've gotten the point across that there are some big problems with the way software is developed, and something must be done to improve things. Object-oriented programming languages are a huge step in the right direction, because they enable programmers to deal with objects instead of worrying about procedures and data. This fits in much better with the human way of thinking, because we all live in a world full of objects.

The problem is that object-oriented programming languages enforce an object paradigm only within the bounds of a particular programming model such as C++ or Java. Although this certainly enables you to reuse code easier when you are working within the same programming language on a specific target platform, it doesn't offer much for the wider view of software where there are many different programming languages and platforms. The problem is that the object-oriented idea hasn't been fully realized beyond the code level, which is a shame.


Note: It's worth noting that the issue of supporting multiple platforms has become much more important with the popularity of the Web, which brings together users of all types of computing hardware and operating systems.

The software world has been inching toward the idea of wide-scale reusability for some time, but no single technology has emerged that provides answers to the many problems inherent in software reuse. The reason is that a real solution must not only enable developers to easily reuse code within a particular application, but also across different platforms and even in a distributed network environment such as the Internet. Ultimately, a realistic software technology for the future must easily integrate into the client/server model, which has become standard in most modern computing systems.

In addition to these requirements, a long-term solution to code reuse must provide an elegant solution to the existence of multiple versions of a piece of software. As stated earlier, software is in a constant state of change, which facilitates a need for handling multiple versions. Giving software a path to grow and expand is a crucial point because it enables developers to continue their endless crusade of improving on last month's bright idea.

Software Component Beginnings

The software development community has been exploring the idea of reusable software for a while. You might have heard reusable software referred to under its more popular name, software components. In case you've missed the hype, a component is a reusable piece of software that can be assembled easily to create applications with much greater development efficiency. Just in case you think this idea sounds groundbreaking, it is not. You only need to look back roughly a century to see this same idea applied to a very different type of application. I'm referring to the industrial revolution, in which the assembly-line approach to developing and assembling mechanical machinery was introduced. The idea as applied to software is to build small, reusable components once and then reuse them as much as possible, thereby streamlining the entire development process.


New Term: A software component is a piece of software isolated into a discrete, easily reusable structure.

Although component software certainly has its merits, fully reusable software has yet to really establish itself, for a variety of reasons. Not the least of which is the fact that the software industry is still very young compared to the industries carved out in the industrial revolution. It only stands to reason that it would take time to iron out the kinks in the whole software production process. If you're like me, you'll embrace the rapid changes taking place in the software world and relish the fact that you are a part of a revolution of sorts--an information revolution.

Perhaps the hardest thing component software has had to face is the wide range of disparate microprocessors and operating systems in use today. There have been a variety of reasonable attempts at component software, but they've always been limited to a specific operating system. Microsoft's VBX and OCX component architectures have had great success in the PC world, but they've done little to bridge the gap between other types of operating systems. Weighing in the amount of work required to get an inherently platform-dependent component technology running on a wide range of operating systems, it only makes sense that Microsoft has focused solely on the PC market.


Note: Actually, Microsoft's new ActiveX technology, which is a revamped version of its OCX technology, aims to provide an all-purpose component technology compatible across a wide range of platforms. However, considering the dependency of ActiveX on 32-bit Windows code, it has yet to be seen how Microsoft will solve the platform-dependency issue. You learn about the specific similarities and differences between JavaBeans and ActiveX in Chapter 15, "Advanced JavaBeans."

Before the explosion of the Internet, the platform-dependency issue wasn't all that big a deal. PC developers didn't necessarily care too much that their products wouldn't run on a Solaris system. Some PC developers hedged their bets and ported their applications to the Macintosh platform, but most with considerably lengthy and resource-intensive development efforts. The whole scenario changed with the operating system melting pot created by the Internet. The result was a renewed interest in developing software that everyone could use, regardless of which operating system they happened to be running. Java has been a major factor in making truly platform-independent software development a reality. However, until recently Java has not provided an answer to the issue of component software--you'll get to that in just a moment, and in fact throughout the rest of the book.

As if the platform dependency issue weren't enough, some existing component technologies also suffer because they must be developed using a particular programming language or within a particular development environment. Just as platform dependency cripples components at runtime, limiting component development to a particular programming language or development environment equally cripples components at the development end. Software developers want to be able to decide for themselves which language is the most appropriate for a particular task. Likewise, developers want to be able to select the development environment that best fits their needs, instead of being forced to use one based on the constraints of a component technology.

Therefore, any realistic long-term component technology must deal with both the issue of platform dependency and language dependency. This brings you to JavaBeans: JavaSoft's JavaBeans technology is a component technology that answers both of these problems directly. JavaBeans is implemented as an
architecture-independent and platform-independent application programming interface (API) for creating and using dynamic Java software components. JavaBeans picks up where other component technologies have left off, using the portable Java platform as the basis for providing a complete component software solution that is readily applicable to the online world. Before I get carried away, let me stop and mention that you have the rest of the book to worry about the details of JavaBeans; for now, continue with software components in general.

Visual Software Components

If the discussion of software components thus far has left you a little confused, hopefully this section will clear things up. So far you've learned software components in a relatively abstract sense, which can sometimes be difficult to grasp. An easier way to understand software components is to look at a specific subset of components: visual components. Visual components are software components that have a visual representation that requires physical space on the display surface of a parent application. Parent applications are sometimes more generally referred to as containers. You learn more about containers later, in the "Component Models" section of this chapter.


New Term: A visual component is a type of component that has a visual representation that requires physical space on the display surface of a parent application.

Possibly the most simple example of a visual component is a button, which is a graphical element completely distinguishable from the application within which it is contained. Many visual design tools, or application builder tools, provide support for graphically manipulating buttons, which is proof of the fact that buttons are separate entities that can be arranged and interacted with independently of any parent application. In this way, a button functions as a discrete self-contained unit, which just happens to be one of the key traits of a software component. Even though buttons are discrete units, the real power they provide is the capability to easily integrate into applications. Using an application builder tool, a button is as easy to add as clicking and dragging the mouse. Figure 1.1 shows a button being added to a dialog box in Visual J++, a popular Java development tool.

Figure 1.1. A button being added to a dialog box in Visual J++.

The button shown in Figure 1.1 is a visual software component, as is evident in the figure. Beyond its visual presence, the button component also can be interacted with programmatically. For example, you can specify a piece of code that is executed when the button is pressed. The pressing of the button is known as a user input event, and it is normal for visual components to propagate
input events to the parent application if the application is interested in knowing about the event. You learn much more about events and how they relate to JavaBeans in Chapter 6, "Handling Bean Events."

Many other types of visual components are supported in visual development environments such as Visual J++. These components include checkboxes, list boxes, and text edit boxes, to name a few. Keep in mind that the visual components used in Visual J++ are limited in that they actually are based on standard Java classes. One exception to this is the use of ActiveX controls, which provide some of the advanced capabilities required of true software components. Of course, JavaBeans components are an exception as well, but I don't want to jump ahead too much at this point.

Non-Visual Software Components

If visual components sound like the ideal use for software component technologies, understand that there are also situations in which non-visual components can be very useful. A very popular Visual Basic control is the Timer control, which is completely invisible at runtime. The Visual Basic Timer control can be set to trigger an event at periodic intervals, such as once every second. The Timer control is very useful in creating timing loops such as those that control animations. Because the Timer control is used entirely at the programming level, there is no meaningful reason to provide a graphical view of the component at runtime. The nice thing about the Timer control is that an application using the control doesn't have to be concerned at all about how the control is implemented internally; the application lets the control take care of its own business. That's the beauty of software components!

Another good example of a non-visual software component is a hypothetical spell checker component that processes text and finds misspelled words. Because this spell checker is a self-contained component, it can easily be integrated into any application that might benefit from spell checking functionality. For
example, the same spell checker component could be used in both a word
processor and an e-mail application. This saves the developers of each application the trouble of designing and implementing their own spell checker from scratch. Instead, they are free to purchase the spell checker component from a third-party component vendor. Or, if they so choose, they can develop their own spell checker component and reuse it however they want. The point is that the spell checker functionality is isolated into a self-contained unit, a component, that can be plugged into an application with minimal effort.

Software Building Blocks

The bottom line to this discussion is that components, both visual and non-visual, are the equivalent of software building blocks. Using components, you can build applications one discrete, functional piece at a time. To get a better grasp of why this is such a significant leap in the evolution of software design, consider some real-world building blocks. If you wanted to take up masonry as a side profession, you would first buy bricks, mortar, and a trowel. Using the trowel and a little know-how, you could start building walls without too much difficulty.

In the world of software, things just aren't that simple. First of all, you would be hard pressed to find software off the shelf that is as ready to assemble as bricks and mortar are for wall construction. More than likely, the software you find would be at a level of detail significantly lower than you had planned, and as a result you would have to spend a great deal more time developing the low-level parts of your application. The parallel in the masonry world would be if you had to create your own bricks, which is obviously well beyond the skills necessary to be a successful wall builder.

And it doesn't stop there! Back on the software side of things, most software you buy is limited to a particular platform, which means that you are often on your own if you choose to develop for a different platform. In your masonry profession, this leaves you with having to learn how to create a completely different type of brick each time you want to build a wall that looks a little different. Additionally, you would potentially have to buy a new trowel specifically designed for that type of brick.

OK, so my analogy went a little astray there, but I think you get the idea. Just as bricks and mortar form the building blocks of masonry, software components form the building blocks of software development.

Component Models

Now that you have a pretty good idea about what a software component is, it's time to look a little closer at what makes one work. At the heart of every software component technology is a component model, which defines the architecture of components and how they are manipulated and interacted with externally. The architecture defined by a component model is responsible primarily for determining how components are able to interact in a dynamic environment. Understanding component models and their related architecture is critical in seeing the big picture surrounding software components and how they work.

All software component models define two fundamental elements: components and containers. The component part of a component model lays the foundation for how different components are created and used. In other words, the component model provides the template from which practical components are created. The container part of the component model equation defines a method of combining components together into useful structures. Containers provide the context for components to be arranged and interacted with one another. For example, an application using a group of components acts as a container for the components.


New Term: A container is a context in which components can be grouped together and interacted with.

Containers also are sometimes referred to as forms, pages, frames, or shells, and can serve as the basis for applications. Just to confuse things a little more, containers also can be components themselves. Even though this might sound strange at first, this capability is important because it enables components to be nested within each other, resulting in complex visual interfaces. Figure 1.2 shows an example of a group box component in Visual J++ being used as a container to hold a group of buttons in a dialog box.

Figure 1.2. A group box component being used as a container in Visual J++.

Besides defining the structure of components and containers, a component model also is responsible for providing a variety of services. More specifically, a full-featured component model is responsible for supporting the following six major services:

Introspection

Introspection is the mechanism that exposes to the outside world the functionality of components. Through introspection, an application can query a component to find out its capabilities and then interact with the component accordingly. Introspection is one of the most critical aspects of a component model because it is responsible for dictating how a component appears to
applications and other components. If you recall, one of the key requirements of a component is that it be completely self-contained. For a component to
be both self-contained and useable from the outside, it must fully support
introspection.


New Term: Introspection is the mechanism that exposes to the outside world the functionality of a component.

Event Handling

Event handling is the mechanism that enables a component to generate event notifications that correspond to some change in the internal state of the component. When the state of a component changes, the component generates an event notification that is broadcast to all interested parties. These interested parties can be either a parent application or other components. The event handling mechanism is structured in such a way that events can easily be caught and responded to in a consistent fashion.


New Term: An event is something that happens within a component that an application or other component might want to know about and possibly react to.

As an example, recall the button component mentioned earlier in this chapter, which generates an event when it is clicked with the mouse. In this case, the change in the button state is reflected by the fact that the button has been clicked. This state change causes an event to be generated and broadcast to any interested event listeners. Assume that the parent application is the interested listener. The parent application has a special piece of code devoted to handling the button press event, which is executed upon receiving the event notification.


New Term: An event listener is an application or component that is designed to respond to a particular event.

The issue of broadcasting and responding to events such as in the button example might seem simple in a sense that it is very straightforward. However, keep in mind that the whole mechanism of routing events to their respective listeners is something that must be outlined in detail by the component model. Furthermore, this mechanism must be consistent across a wide range of components and event types so any application or component can respond to any event.

Persistence

Persistence is the means by which a component is stored to and retrieved
from a non-volatile location, such as a hard disk. The information about a
component that is actually stored and retrieved is the internal state of the component, along with its relation to a container or other components. Using this information, a component can be safely stored away and re-created at a later time. Persistence is a particularly important issue in design tools, which
enable developers to modify component properties to suit a particular
application.


New Term: Persistence is the means by which a component is stored to and retrieved from a non-volatile location.

Layout

Another important part of any component model is its support for the physical layout of components. Physical layout really applies only to visual components, but it is an important aspect of a component model nevertheless. The layout support provided by a component model can be divided into two parts: the layout of a component within its own space and the layout of a component with respect to other components sharing space in the same container.

Typically, the spatial requirements for a component consist primarily of giving the component a rectangular area in which it can render itself visually. A parent application enables the component to render itself within this area however it chooses. Likewise, the parent application provides a facility by which the component's rectangular surface can be managed in the context of a container that houses other components. This facility is typically used by application builder tools, where a developer lays out components while constructing an application.

Application Builder Support

Throughout the chapter you've learned about application builder tools and how they relate to software components. Support for application builder tools happens to be a major requirement for component models. This support gives users the ability to graphically build complex applications out of components. The specific support required at the component model level is the capability for components to expose their properties and behaviors to application builder tools such as Visual J++. Development tools use these properties and behaviors to enable users to integrate and customize components in the context of a meaningful application.

Most application builder tools enable the user to not only lay out and edit individual components, but also to specify how the components relate to each other, both visually and programmatically. The layout support provided by a component model aids in laying out components visually, the introspection support helps application builder tools determine the capabilities of a
component, and persistence enables the user to save components that have been customized. Specific application builder tool support often consists of dialog boxes that enable the user to graphically edit a component's properties.

Figures 1.1 and 1.2, which you saw earlier in this chapter, are examples of an application builder tool (Visual J++) at work. In Figure 1.1, you saw a dialog box being designed visually using a button component. In Figure 1.2, you saw a group box being used to group a set of buttons in a dialog box. In both examples, components are being manipulated in a development environment, which differs greatly from how the end user interacts with them. For example, the properties of the button component can be edited in Visual J++ by double- clicking the button. Figure 1.3 shows the visual property editor for the button component in Visual J++.

Figure 1.3. The visual property editor for a button component in Visual J++.

This property editor is not part of the Visual J++ environment itself, but part of the button component. The code required to display and work with the property dialog box is a perfect example of the application builder tool support often provided by components.

Distributed Computing Support

The last major part of a component model is support for distributed computing, which has become important recently with the increased popularity of the Internet. It is now becoming not only realistic, but at times imperative, to build applications that are capable of executing in a distributed environment connected across vast networks. Consequently, it is important for component models to address the challenges inherent in building applications engaging in distributed computing.

Not surprisingly, distributed computing brings on a wide range of problems that aren't present in a single-system environment. Distributed systems are subject to both transmission errors and failure, along with limitations on communication speeds. The capability to handle these problems and limitations comes at no small cost; it requires significant overhead to deal with the problems brought on by distributed computing. The overhead is so significant, in fact, that adding it to an object model must be heavily weighed against the added complexity. Directly adding extensive support for distributed computing simply doesn't make sense when a developer is trying to make component models as lightweight and simple as possible.

Another option to implementing direct support for distributed computing is for an object model to leverage this support from an existing technology. With this approach, the single system component model is kept simple and lightweight, while the distributed model is still available via access to a leveraged solution. You learn more about distributed computing and how it affects a real component model in Chapter 15. For now, just understand that support for distributed computing is important in any object model, regardless of whether that support is implemented directly or leveraged from another model.

Summary

This chapter introduced you to a concept fundamental to the JavaBeans technology, software components. You first learned a little background on the state of software and why the software development community is adopting the paradigm of reusable software. You learned that the idea of software reuse is neither unique nor new, but that suitable technologies for exploiting it have only recently surfaced. The premise behind software components was then presented, with explanations of how components can provide an answer to the software reusability problem. You followed up this discussion by learning about the architectural heart of a component, the component model.

Although this chapter hinted at some things to come, it deliberately avoided getting into the specifics of the JavaBeans technology. The reasoning is that by being fully presented with the issues surrounding component software, you'll be better able to judge JavaBeans and decide for yourself how it fares as a component technology. That's not to say I won't have something to say about JavaBeans and how it relates to other component technologies such as ActiveX; I just want you to understand the big picture before jumping into the details of JavaBeans.

Speaking of JavaBeans, it's about time to move on and see what it is all about. Chapter 2, "Welcome to JavaBeans," goes far beyond the generalities of software components and covers exactly what JavaBeans is as a technology and what it aims to accomplish.