7.4.1 Abstract Windows ToolkitJava AWT is the basic Java GUI library. It hides the underlying details of the GUI at a high level of abstraction. The documentation for the package is available at java.sun.com [AWT]. The structure of the AWT is rather simple. Components are added to, and live within, Containers. The layout of the components within their containers is controlled by Layout objects. Available are a variety of event handling, menu, fonts, and graphics classes in addition to those two. Use of threads is allowed, as well as video, audio, I/O, and networking classes alongside the AWT. Figure 7.2 present the AWT subset associated with components and containers. 7.4.1.1 ContainersContainers are Frames, Dialogs, Windows, and Panels. They can contain components and are themselves components, thus can be added to Containers. Containers usually handle events that occurred to the Components, although nothing prevents the handling events within the component. In short all classes derived from Container can be one. All Containers have common functionality, due to the fact they are derived from Container class which includes many pre-defined event handling methods called listeners or callbacks. These events are useful for handling user input in specialized Container classes which override the default behavior by overriding the Container's class methods. 7.4.1.2 ComponentsComponents are generally with what the viewer interacts . Components include Windows, Buttons, TextAreas, Scrollbars, and so on., which are added to a container and allow displaying Windows and Buttons, lists, selectors, and edit boxes. 7.4.1.3 LayoutsLayouts control how Components are laid out within a Container. An abstract class called the LayoutManager is used to manage layouts; because it is abstract, to be used it is subclassed and extended with functionality. There are a number of layouts built-into the AWT framework:
To use a layout within a Container one needs to invoke the setLayout() method of that Container, with an instance of a subclass of the LayoutManager class. The interfaces used with each layout are different. For example, with BorderLayout one needs to specify the location of a component to be one of north, south, east, west, or center. 7.4.1.4 EventsGUIs and Windowing systems use the event-driven model rather than the old procedural-grab-the-input-yourself model. The operating system is polling for events, and when it finds one, it forwards that event to the appropriate component. The component receives the event through a registered listener, or callback. By default, no listeners are registered and events are ignored. AWT Events could be classified into Mouse, Keyboard, Window, and Action events. Mouse events occur when the mouse pointer moves over, into, or out of a rectangle associated with a component. Keyboard events occur when a key in the remote-control is pressed or released; they are routed to the component with the input focus at the time the event occurs. Window events occur as the window is shown, hidden, moved or resized. Finally, action events are application-specific events used to allow an event-driven programming model. 7.4.1.5 Mouseless OperationiTV environments differ from typical computer environment in that they are not mouse-driven (if at all available, a remote-control track ball is often more practical than a mouse). As a result, mouseless operation is critical for usability of iTV applications. Java AWT 1.0 does not provide any explicit facilities for building mouseless operation into Java programs, except where the native peer components provide it by default (i.e., tabbed focus traversal, spacebar activation, and so on). For JDK 1.1, however, some baseline support was added to better enable mouseless mode in Java programs. Middleware implementations implementing the HAVi Level 2 GUI API perform much of what is described next using HAVi classes. However, the concepts and approach is similar [HAVI]. Focus TraversalFocus traversal is defined as the ability to use keystrokes (not the mouse) to traverse components capable of accepting keyboard focus. Those keystrokes are defined to be <Tab> to move forward and <Shift-Tab> to move backward. Once the focus is owned by a component then it should be possible to activate/drive that component with further defined keystrokes (e.g., <space> to press a button). It is the responsibility of the component (not the AWT) to implement the proper activation once it has focus. The AWT internally tracks which component has the focus so that it can move the focus forward or backward in response to a Tab or Shift-Tab keyboard event. This is handled by a private FocusManager object that is registered on the Window. The FocusManager can manage this focus migration correctly, no matter how deeply nested a window's containers are. The order of this traversal is the same order of the components contained in the containers; by default this is the same order in which the children were added to the container, however the Container.add(Component c, int pos) method can be used to control this ordering. The FocusManager automatically checks to see if a focusTraversable component is both visible and active before it assigns it the focus (hence, the isFocusTraversable() method need not take this state into account for its return value). A component capable of accepting focus should always render some form of visual feedback when it gets focus. Typically, in iTV environment, this feedback takes the form of a colored bounding box drawn around the component. The native toolkits on each platform provide varying degrees of support for focus traversal by default. In AWT, the Focus traversal API is extremely simple; it consists of the method isFocusTraversable() that returns true if the component is a type inherently capable of accepting keyboard focus and returns false otherwise . The reason this method exists for the peer class is because the native peer components that are created by the AWT components have different traversal rules on different platforms. This allows the tailoring of this attribute appropriately on each platform. All AWT components should have this attribute set properly by default. Implementers have the option of subclassing a component and overriding this method. In particular, when subclassing java.awt.Canvas to build a custom component that is designed to take keyboard focus, one should override isFocusTraversable() to return true, catch the mouse-down event on the component, invoke requestFocus() , and when the component gets focus, provide visual feedback (e.g., highlighting the bounding box) to indicate that it has indeed received the focus. Menu ShortcutsThe goal for the AWT Shortcut API is to provide an easy way for application developers to provide shortcuts as an aid to menu navigation. This API only addresses menu shortcuts and does not touch on any other mouseless menu navigation issues. A shortcut is defined to be a keyboard equivalent of a menu command, such that invoking the appropriate key combination causes the same action to be initiated as if the menu item had been selected. Shortcuts are also known as keyboard equivalents or accelerators. The AWT Shortcuts API consists of a class java.awt.MenuShortcut , and the following java.awt.MenuItem methods: public MenuItem(String label, MenuShortcut s) public MenuShortcut getShortcut() public void setShortcut(MenuShortcut s) public void deleteShortcut(); java.awt.MenuBar has the following additional methods: public MenuItem getShortcutMenuItem(MenuShortcut s); public Enumeration shortcuts(); boolean handleShortcut(KeyEvent e); public void deleteShortcut(MenuShortcut s); Although most of the shortcut API is implemented in shared code, the getMenuShortcutKeyMask() method was added to java.awt.Toolkit to return the appropriate modifier per platform. 7.4.1.6 The Platform GlueFrom the point of view of a middleware developer, execution environment implementer or platform integrator, the java.awt.Toolkit class is key, as JDK 1.1.8 is common to all iTV middleware specifications. It is the abstract superclass of all actual implementations of the AWT. The toolkit is used to bind the various components to a particular native implementation. These methods (Table 7.4) are the glue that joins the platform-independent classes in the java.awt package with their counterparts in java.awt.peer . Some methods defined by Toolkit query the native operating system directly. Most applications should not call any of the toolkit methods directly. Table 7.4. The java.awt.Toolkit Methods
7.4.1.7 Binding Graphics ContextsOne of the critical aspect of an iTV platform implementation is the binding of graphics libraries. Since the java.awt.Graphics class is an abstract class, applications cannot call its constructor directly. Graphics contexts are obtained from other graphics contexts or are created by calling getGraphics() on a component. The Graphics.create() method on a Graphics of a components is often used internally to create a new Graphics object with a translation and clip area. Although the HAVi API overrides most of the Java AWT APIs, it does not override the getGraphics() method of the AWT component. Therefore, the getGraphics() method remains an important link to the graphic drivers. 7.4.2 Java ReflectionReflection is one important innovative concept that the Java technology has introduced. It enables Java programmers to manipulate code in a fashion that was previously solely the realm of debuggers . It enables Java code to discover information about the fields, methods, and constructors of loaded classes, and them within a fully controlled security environment. This enables, for example, discovering which APIs a receiver execution environment supports, as well as detecting which components are bundled with a JavaTV Xlet or a plug-in. One should avoid the temptation to use the reflection mechanism when other tools more natural to the language would suffice. Nevertheless, the reflection API accommodates applications that need access to either the public members of a target object (based on its run-time class) or the members declared by a given class. More specifically , the reflection API enables the following operations:
For each class, the Java Run-time Environment (JRE) maintains an immutable Class object which represents, or reflects, the class [JRE]. The reflection API allows invoking methods on that Class object which return Constructor , Method , and Field objects. One can also invoke Class methods to find out about an interface's modifiers, methods, and public constants. However, not all of the Class methods are appropriate when a Class object reflects an interface. For example, it is not appropriate to invoke getConstructors() when the Class object represents an interface. 7.4.3 Java Class LoadersTypically, the JVM instantiates classes from the local file system in a platform-dependent manner. For example, on UNIX and Windows systems, the JVM loads classes from the directory defined by the CLASSPATH environment variable. The class ClassLoader is an abstract class, which can be subclassed to extend the manner in which the JVM instantiates classes. The methods and constructors of objects created by a class loader may reference other classes. To determine the class(es) referred to, the JVM invokes the loadClass() method of the class loader that originally created the referring class. To determine the existence of a class, there is no need to know its superclass, in which case resolution is disabled by setting the resolve flag to false. However, if an instance of the class is being created or any of its methods are being called, the class must also be resolved. In this case the resolve flag is set to true, and the resolveClass() method should be called. Consider an application that creates a custom class loader to download class files from a DSM-CC transport (see Example 7.3). In this example, the DSM-CC class loader must define the method loadClass() to load a class from the MPEG DSM-CC transport. Once it has downloaded the data bytes that make up the class, it should use the method defineClass() to create a class instance (see Example 7.4 for a sample implementation). Example 7.3 Creating a class using a custom class loader.ClassLoader loader = new DSMCC_ClassLoader(TSID, CarouselID, ModuleID, ObjectrKey); Object main = loader.loadClass("XletMain", true).newInstance(); Example 7.4 Customization of the class loader.class DSMCC_ClassLoader {int TSID, int carouselID, int moduleID, String objectKey) { Hashtable cache = new Hashtable(); private byte loadClassData(String name)[] { // code to load the class data from the MPEG DSMCC transport } public synchronized Class loadClass(String name, boolean resolve) { Class c = cache.get(name); if (c == null) { byte data[] = loadClassData(name); c = defineClass(data, 0, data.length); cache.put(name, c); } if (resolve) resolveClass(c); return c; } } Because overriding class loaders opens the door for malicious code to perform unexpected operations or even damage the system, most implementations and iTV standards prohibit its usage by the downloaded JavaTV Xlet. It should only be used by code authorized by the manufacturer of a platform. |