Sie sind auf Seite 1von 30

ch03.

qxd

7/16/2001

7:10 AM

Page 41

CHAPTER

Java and HAVi

TO P I C S I N T H I S C H A P T E R
M APPLICATIONS M HAVIJAVA APIS M AN EXAMPLE

Applications
Now that you know what HAVi is and have seen an overview of how it works, you can start looking at how to build applications. As you have seen, HAVi applications are based on software elements. Generally an application creates a single software element which then registers itself and uses the services of existing software elements on the network. It finds other software elements by querying the Registry service. It can be notified of events by subscribing to the Event Manager. By sending requests to DCM and FCM software elements, the application can control the operation of target devices. It can also request the services of the Resource Manager or Stream Manager. In designing a HAVi application, a key decision is whether the application is portable or not. Portable applications run on any full (FAV) controller. However, to assure portability, the application 1) must be written in Java, and 2) must confine itself to a set of packages identified by HAVi.

ch03.qxd

7/16/2001

7:10 AM

Page 42

42

HAVi Example by Example

Not all HAVi applications need be portable and, when developing an application intended for a specific controller, there may be advantages to dropping the restrictions imposed by portability. Nonportable applications need not be written in Java or, if written in Java can use additional packages to those allowed for portable applications. Nonportable applications are also free to use any of the native software on the controlleroperating system calls, windowing libraries, networking APIs, etc.

Havlets
A portable HAVi application is called a havlet. The analogy to the familiar applet is intentional. Like applets, havlets are downloaded from a remote entity and then installed and run locally. While applets are downloaded from HTTP servers, havlets are downloaded from special software elements. There are two types of software elements that provide this havlet download service: Device Control Modules (DCMs) and Application Modules. You have not yet encountered Application Modules in this book, but these are simple software elements whose sole purpose is to act as a source for havlets. Havlets are transferred to the controller in JAR file format. In addition to providing an API for the controller to download the havlet, DCMs and Application Modules also provide an API that returns the havlet profile. This is a description of the memory requirements of the havlet. By first examining a havlets profile, a controller can estimate whether it has sufficient memory to run the havlet and so avoid the potential confusion of having the havlet fail to launch.

Controller-Specific Applications
Java plays a clear role in developing havlets which, as explained above, need to be portable. You can also use Java to develop controller-specific (i.e., nonportable) HAVi applications. This type of application is not intended to be runnable on all HAVi controllers but rather on a particular controller (or family of controllers) chosen by the developer. The advantage to the developer is being free to use any of the Java packages known to be on the controller, rather than the restricted set available to havlets.

HJA Applications
The set of packages defined by HAVi for developing in Java is called HJAthe HAVi Java APIs. In this book we use the term HJA application to indicate a HAVI application written in Java. HJA applications include both havlets and controllerspecific applications. If you are writing a havlet, you can use only the packages appearing in HJA. Controller-specific applications can use HJA packages and other Java packages appearing on the controller.

ch03.qxd

7/16/2001

7:10 AM

Page 43

3 JAVA and HAVi

43

HJAThe HAVi Java APIs


The HJA consists of the following packages: M org.havi.constants M org.havi.types M org.havi.system M org.havi.fcm.* M org.havi.iec61883 M org.havi.ui M org.havi.ui.event In addition, the following packages may be used by havlets: M java.lang, as defined the Java 1.1 Core API* M java.util, as defined in Java 1.1 Core API* M java.util.zip, as defined in Java 1.1 Core API* M java.io, as defined in the Java 1.1 Core API* apart from the following classes: File, FileInputStream, FileNotFoundException, FileOutputStream, FileReader, FileWriter, FilenameFilter and RandomAccessFile. M java.net.URL and java.net.MalformedURLException as defined in the Java 1.1 Core API* M a subset of java.awt

HAVi does not require controller devices to have a display and or to support UI functionality. Controllers without displays need not support the java.awt and havi.ui packages and cannot run havlets. However, displayless controllers can upload and run bytecode DCMs.

org.havi.constants
To assure interoperability, HAVi software elements must agree on the interpretation of messages. Many of the messages used by software elements contain parameters that take specific values defined by HAVi. Because there are a large number of such values, they have been collected together as interfaces in the org.havi.constants package.
*Java Development Kit (JDK) 1.1 Core API specification http://java.sun.com/products/ jdk/1.1/docs.html

ch03.qxd

7/16/2001

7:10 AM

Page 44

44

HAVi Example by Example

For example, in the description of the Registry, you saw that there are several Registry attributes defined by HAVi. To obtain the value of a specific attribute, you must provide a constant that identifies the attribute. The constants for HAVi-defined attributes are grouped together in the interface shown in Example 3-1.

Example 3-1

Constants for Registry Attribute Names ConstAttributeName { final int ATT_SE_TYPE final int ATT_VENDOR_ID; final int ATT_HUID final int ATT_TARGET_ID final int ATT_INTERFACE_ID final int ATT_DEVICE_CLASS final int ATT_GUI_REQ final int ATT_MEDIA_FORMAT_ID final int ATT_DEVICE_MANUF final int ATT_DEVICE_MODEL final int ATT_SE_MANUF final int ATT_SE_VERS final int ATT_AV_LANG final int ATT_USER_PREF_NAME

public interface public static public static public static public static public static public static public static public static public static public static public static public static public static public static }

= = = = = = = = = = = = = =

0x00; 0x01; 0x02; 0x03; 0x04; 0x05; 0x06; 0x07; 0x08; 0x09; 0x0a; 0x0b; 0x0c; 0x0d;

Using ConstAttributeName, application developers can refer to the symbolic names for Registry attributes and need not be aware of their actual values. However, to assure interoperability, it is essential that all implementations of the HAVi system use the same values.

org.havi.types
org.havi.types groups together a set of simple classes used by many software

elements. These classes primarily define get/set methods. The classes are: M Structured data types appearing in HAVi messages. For example, SEID represents software element identifiers and ResourceNegotiateRecord represents a structure used by the Resource Manager. M Holder classes used to store replies from asynchronous requests sent to software elements. M HaviException and its subclasses.

ch03.qxd

7/16/2001

7:10 AM

Page 45

3 JAVA and HAVi

45

org.havi.system
The org.havi.system package contains the core functionality of HAVi. Within this package are classes for accessing DCMs and the system software elements the Event Manager, Registry, and others. Two key classes in this package are: M SoftwareElementAllows you to create software elements and service requests sent by other software elements. M HaviClientProvides local proxies, or stubs, for sending requests to software elements.

org.havi.fcm.*
HAVi 1.0 specifies ten FCMs, nine of which have corresponding packages. These nine are called:
org.havi.fcm.tuner org.havi.fcm.vcr org.havi.fcm.clock org.havi.fcm.camera org.havi.fcm.avdisc org.havi.fcm.amplifier org.havi.fcm.display org.havi.fcm.modem org.havi.fcm.webproxy // // // // // // // // // access access access access access access access access access a Tuner FCM a VCR FCM a Clock FCM a Camera FCM an AV Disc FCM an Amplifier FCM a Display FCM a Modem FCM a Web Proxy FCM

The tenth FCM, the AV Display, provides display and amplifier services. Applications access the services of AV Display FCMs by using both the org.havi.fcm.display and org.havi.fcm.amplifier packages. Common data structures and constants used by FCMs are collected in the org.havi.fcm.constants and org.havi.fcm.types packages.

org.havi.iec61883
Audio, video, and other streamed data types are transferred over an IEEE 1394 (i.LINK) network using a packet format defined by a standard called IEC 61883. org.havi.iec61883 provides two classes that allow applications to read and write streaming data:
public class Iec61883InputStream extends java.io.InputStream {} public class Iec61883OutputStream extends java.io.OutputStream {}

ch03.qxd

7/16/2001

7:10 AM

Page 46

46

HAVi Example by Example

The read and write methods of these two classes do not take into account the timing requirements of transferring streaming data. It is the applications responsibility to assure that data is produced and consumed at the proper rate ; otherwise, buffers used by Iec61883OutputStream or Iec61883InputStream will underflow or overflow, respectively.

org.havi.ui and org.havi.ui.event


The classes within the org.havi.ui and org.havi.ui.event allow havlets to construct a graphical user interface and respond to user input events. Java provides the java.awt package for this purpose. However, java.awt is based on traditional computer-oriented UI conceptsmenus, windows, pointingand does not meet the UI requirements of CE devices. org.havi.ui uses a subset of java.awt that excludes most of the computer-oriented widgets. org.havi.ui then adds new classes for such things as remote control support and graphics overlays on video.

org.havi.ui and org.havi.ui.event are new additions to HAVi and are undergoing interoperability testing and revision. Since these packages are still being validated, we do not use them in our examples.

HJA Conventions
HAVi services are specified in IDL, the Interface Definition Language, as mentioned in Software Element APIs in Chapter 2. The HAViJava APIs have been generated automatically from the IDL form using an IDL to Java mapping. This mapping, described in the HAVi specification, introduces several conventions to the HJA. These conventions are described in the following subsections.

The IDL-to-Java mapping was designed for automatic generation. Unfortunately, the mapping introduces slightly idiosyncratic Java class definitions in some cases (e.g., when mapping IDL unions). An alternative would have been to handcraft the Java APIs. The HAVi Organization took the approach of automatically generating the HJA, since it was concerned about the difficulty of maintaining both an IDL and a Java version of the specification.

ch03.qxd

7/16/2001

7:10 AM

Page 47

3 JAVA and HAVi

47

Constant Naming
Java interfaces that specify constant values appear in the packages org.havi.constants and org.havi.fcm.constants. Their names are of the form Const<xx>. For instance:
org.havi.constants.ConstStreamType org.havi.constants.ConstSystemEventType org.havi.fcm.constants.ConstWriteProtectStatus

Event Information
HAVi events, i.e., those sent by the Event Manager, carry an event type and additional information associated with the event. This additional information is represented by a class in org.havi.types with a name of the form <EventType>EventInfo, as in Example 3-2.

Example 3-2

Some EventInfo Classes

org.havi.types.ConnectionChangedEventInfo org.havi.types.NewSoftwareElementEventInfo

Asynchronous and Synchronous Service Requests


Software elements request the services of other software elements using either a synchronous or an asynchronous interface. When a software element issues a synchronous request, it will block until a response is returned or a timeout occurs. With asynchronous requests, the software element does not block, and the response is delivered via a callback-like mechanism. Since each service can be invoked in two ways, the following naming convention is for methods corresponding to software element service requests. These methods belong to HaviClient subclasses and have names of the form: <ServiceName> if the method issues an asynchronous request, and <ServiceName>Sync if the method issues a synchronous request. Example 3-3 shows this for two methods of DcmClient.

Example 3-3

Sync and Async Methods

public class DcmClient extends HaviClient { void getDeviceManufacturer( ); void getDeviceManufacturerSync(timeout, ); // }

ch03.qxd

7/16/2001

7:10 AM

Page 48

48

HAVi Example by Example

You should keep in mind that a synchronous request just blocks until a response is returnedit need not block until all actions initiated by the request are completed. For instance, the synchronous play requests supported by some FCMs just block until playout commences rather than completes.

Synchronous Request Timeouts


All methods of HaviClient (and its subclasses) that issue a synchronous service request have a timeout parameter. HJA throws an exception if the Messaging System does not receive a response prior to the specified timeout. Timeout values are measured in milliseconds. If timeout is set to 0, the Messaging Systems default timeout of 30 seconds is used.

Example 3-4

Timeout Parameter

int timeout = 0; // default timeout: 30 seconds myDcm.getDeviceManufacturer Sync(timeout, ); int timeout = 1000; // 1 second myDcm.getDeviceManufacturerSync(timeout, );

Holder Classes
The Interface Definition Language (IDL) used by HAVi allows service interfaces to specify multiple out parameters. When a service is invoked, the values of out parameters are returned by the service provider. Java methods, however, allow only a single return parameter. The IDL-to-Java mapping used by HAVi solves this problem by mapping out parameters to holder classes. These classes have getValue and setValue methods for accessing the encapsulated value. Holder classes have names of the form <DataType>Holder; they extend HaviHolder and are located in the org.havi.types package. Some holder classes are listed in Example 3-5.

Example 3-5

Some Holder Classes

org.havi.types.IntHolder org.havi.types.IntSeqHolder org.havi.types.SEIDHolder

ch03.qxd

7/16/2001

7:10 AM

Page 49

3 JAVA and HAVi

49

HJA does not define holder classes for all IDL out and inout parameters. If the class used to represent an IDL data type is not immutable (does not extend HaviImmutableObject), then it can be used for an out parameter and a holder class is not necessary.

HAVi Messaging
HAVi is essentially a distributed programming environment and so provides mechanisms for applicationssoftware elements in HAVi terminologyto communicate with each other across the network. Now lets look at the HJA classes that play a key role in allowing software elements to exchange requests and replies.

HAVi RMI
Software elements communicate through the HAVi Messaging System. The Messaging System is divided into two levels: M A lower level that provides basic support for exchanging messages between software elements. This level deals with fragmentation and assembly of messages and supports two transfer modes: simple (unacknowledged) and reliable (acknowledged). M An upper level that supports a protocol called HAVi Remote Method Invocation (HAVi RMI). This protocol defines how requests for services are sent to software elements and how replies to service requests are returned. Figure 3-1 shows a software element on one device sending a request to a software element on a second device. The structure of the request and how it is placed in the payload of a message are defined by HAVi RMI. The receiver processes the request and sends a response. The structure of the response and how it is placed in a message payload are also defined by HAVi RMI. Figure 3-2 shows the message formats used by the Messaging System and for HAVi RMI. A message consists of a 28-byte header followed by a variable-length payload. The header contains the source and destination SEID, the message length, and other fields used by the Messaging System. The message header also includes a protocol, type field. If this field indicates the HAVi RMI protocol, then the message payload contains a service request or response and has the structure shown in the bottom of Figure 3-2. The HAVi RMI header contains three fields: M Operation code (3 bytes)Specifies the service being requested or that is responding.

ch03.qxd

7/16/2001

7:10 AM

Page 50

50

HAVi Example by Example

Software Element Device #2 Service Request Software Element Software Element

Software Element Application

Service Response

Software Element Software Element

Software Element

Software Element

Device #3 Device #1

FIGURE 3-1 HAVi RMI Communication between Software Elements

M Control flag (one byte)Contains a flag indicating whether the message is a service request or service response. M Transaction ID (4 bytes)An integer allowing the Messaging System to match responses with requests.

28 bytes HAVi message header

0 to 64 Kbytes payload

8 bytes HAVi RMI request or response HAVi RMI header request/response parameters

FIGURE 3-2 HAVi Message Formats

ch03.qxd

7/16/2001

7:10 AM

Page 51

3 JAVA and HAVi

51

Marshalling
The parameters that appear in service requests and replies are marshalled into a bit stream before writing to the network. This process is similar to Java object serialization but produces a bit stream based on IDL data types rather than Java objects. Marshalling and unmarshalling is performed for you by HaviClient and its subclasses, so many applications do not need to worry about marshalling. The situations in which an application may have to perform explicit marshalling or unmarshalling are: M Applications that create software elements that offer their own services or that do not use HaviClient (subclasses) to send requests. M Applications that use asynchronous communication to invoke services. M Applications that register for Event Manager events or other asynchronous notifications. M Applications that use Registry attribute values. A marshalled bit stream is created using the HaviByteArrayInputStream. Any object that implements the Marshallable interface can then be placed in the bit stream (and removed from the bit stream). Marshallable is defined as:
public interface Marshallable { public void unmarshal(HaviByteArrayInputStream hbais) throws HaviUnmarshallingException; public void marshal(HaviByteArrayOutputStream hbaos) throws HaviMarshallingException; }

The Marshallable interface is implemented by two abstract classes: HaviObject and its subclass, HaviImmutableObject.
public abstract class HaviObject extends java.lang.Object implements java.lang.Cloneable, Marshallable {} public abstract class HaviImmutableObject extends HaviObject {}

Instances of the HaviImmutableObject class represent values that cannot be changed. Invocation of unmarshal() on these objects throws an exception.

ch03.qxd

7/16/2001

7:10 AM

Page 52

52

HAVi Example by Example

If you define a class that extends HaviObject and objects of this class have internal state, then you will need to override the default implementation of Marshallable and add explicit marshalling of the state variables used by your class.

In addition to classes that implement Marshallable, many of the primitive data types can be marshalled and unmarshalled using methods of HaviByteArrayInputStream and HaviByteArrayOutputStream. Example 3-6 shows how to create a bit stream containing marshalled values and how to extract the values from the bit stream. The example first marshals three values, an int, String, and SEID object, into a HaviByteArrayOutputStream. The marshalled bit stream is then obtained from the HaviByteArrayOutputStream object; this would typically form part of the payload of a message. However, this example just uses the bit stream to unmarshal the original values.

It is crucial to unmarshal objects in precisely the same order as they were marshalled; otherwise, their values are not likely to be preserved.

Example 3-6

Marshalling and Unmarshalling Values hbaos; hbais bitStream; myInt; myString; mySEID;

HaviByteArrayOutputStream HaviByteArrayInputStream byte[] int String SEID

// assign values to myInt, myString and mySEID // marshall // hbaos = new HaviByteArrayOutputStream(); hbaos.writeInt(myInt); hbaos.writeHaviString(myString); mySEID.marshal(hbaos); // get the bit stream bitStream = hbaos.toByteArray();

ch03.qxd

7/16/2001

7:10 AM

Page 53

3 JAVA and HAVi

53

// unmarshall // USE SAME ORDER AS MARSHALLED // hbais = new HaviByteArrayInputStream(bitStream); myInt = hbais.readInt(); myString = hbais.readHaviString(); mySEID = new SEID(hbais);

Example 3-6, line , uses writeHaviString() to marshal the String value. Generally, HAVi uses UNICODE strings (two bytes per character). writeHaviString() marshals myString by writing the length of myString, followed by each two-byte character, followed by a two-byte null value \u0000. Line shows how to unmarshal an immutable object. The SEID class is a subclass of HaviImmutableObject and so does not support unmarshall(). Instead of attempting to change the value of mySeid using
mySeid.unmarshal(hbais); // Error

the example creates a new SEID with the SEID(HaviByteArrayInputStream) constructor.

Service Requests
HAVi uses an operation code to uniquely identify each type of service request. If you write software elements that only request the services of HAVi software elements, then operation codes are constructed for you automatically by the HaviClient subclasses. However, you must explicitly construct and examine operation codes if you write either a software element that offers services to other software elements, or a software element that requests nonstandard services (i.e., services not specified by HAVi). An operation code contains two parts: M API codeIdentifies a family of software element APIs, e.g., the services provided by the Registry, the Event Manager, etc. API codes for the software elements defined by HAVi are in org.havi.constants.ConstApiCode. HAVi reserves API codes from 0x0000 to 0x7fff for system services. Applications are free to use API codes from 0x8000 to 0xffff. M Operation IDIdentifies a particular service within a family, e.g., the Registry query service or the Event Manger post event service. The OperationCode class allows you to create and examine operation codes as illustrated in Example 3-7.

ch03.qxd

7/16/2001

7:10 AM

Page 54

54

HAVi Example by Example

Example 3-7

Creating an Operation Code Object

import org.havi.types; import org.havi.constants; OperationCode opCode = new OperationCode( ConstApiCode.REGISTRY, ConstRegistryOperationId.GET_ELEMENT);

Once an OperationCode object has been created, the API code and operation ID values can be extracted using the getApiCode() and getOperationId() methods.

Service Responses
You can issue a service request via HaviClient methods or by accessing the Messaging System through the SoftwareElement class described in the next section. In either case, a HAVi message is sent to the software element providing the service. This message includes an operation code identifying the service and marshalled parameters. The response includes the marshalled return values plus a status value. A status value contains: M API codeIdentifies the interface to which the service request belongs. M Error codeIdentifies a particular error condition from the service provider. Each type of software element can define a set of error codes for the API codes that it implements. HJA provides a Status class for handling status values. Example 3-8 shows how a Registry software element could create a status value using the Status class.

Example 3-8 import import Status

Creating a Status Object

org.havi.types; org.havi.constants; responseStatus = new Status( ConstApiCode.REGISTRY, ConstRegistryErrorCode.ATTRIBUTE_NAME);

When a client receives a status value, it can examine the API code and error code fields using the getApiCode() and getErrorCode() methods of the Status class. Some errors reflect conditions that can occur with many different software elements. HAVi calls these general errors, and reserves error codes in the range 0x0 to 0x7f for such values. Table 3-1 lists all general errors defined by HAVi. These values are defined in the ConstGeneralErrorCode interface.

ch03.qxd

7/16/2001

7:10 AM

Page 55

3 JAVA and HAVi

55

TABLE 3-1 org.havi.constants.ConstGeneralErrorCode Constant


SUCCESS UNKNOWN_MESSAGE ACCESS_VIOLATION UNIDENTIFIED_FAILURE NOT_IMPLEMENTED RESERVED INVALID_PARAMETER RESOURCE_LIMIT PARAMETER_SIZE_LIMIT INCOMPLETE_MESSAGE INCOMPLETE_RESULT LOCAL STANDBY

Description
Normal return status, no error. The destination software element does not support the requested service. The requested service is only available to trusted software elements and the client is not trusted. An error of unknown origin has occurred. The request is for an optional service and it is not implemented by the destination software element. The provider is reserved by another client. One or more parameters in the service request contain invalid values. The request failed due to resource limits at the destination. One or more parameters in the service request exceed size limits specified by HAVi. The request is incomplete. One or more parameters in the response are correct but incomplete. The requested service is only available locally but the client is not local (is on a different device). The destination software element is on a device in power standby state and cannot service the request.

The SoftwareElement Class


HJA applications create software elements by constructing a SoftwareElement object. The definition for this class is shown in Example 3-9.

Example 3-9

The SoftwareElement Class

public class SoftwareElement extends java.lang.Object { public SoftwareElement(); public SoftwareElement(HaviListener hl); // public final void addHaviListener(HaviListener hl); public final void addHaviListener(HaviListener hl, SEID targetSeid); public final void removeHaviListener(HaviListener hl);

ch03.qxd

7/16/2001

7:10 AM

Page 56

56

HAVi Example by Example

public final void public final SEID public final SEID

close(); getSeid(); msgGetSystemSeid(SEID seid, int softwareElementType); public final boolean msgIsTrusted(SEID seid); public final void msgSendRequest(SEID destSeid, OperationCode opCode, HaviByteArrayOutputStream buffer, IntHolder transactionId); msgSendRequestSync(SEID destSeid, OperationCode opCode, int timeout, HaviByteArrayOutputStream bufferIn, HaviByteArrayInputStream bufferOut, StatusHolder returnCode); msgSendResponse(SEID destSeid, OperationCode opCode, int transferMode, Status returnCode, HaviByteArrayOutputStream buffer, int transactionId); msgSendSimple(byte protocolType, SEID[] destSeidList, HaviByteArrayOutputStream buffer); msgSendReliable( byte protocolType, SEID destSeid, HaviByteArrayOutputStream buffer); msgWatchOff(SEID destSeid); msgWatchOn(SEID destSeid);

public final void

public final void

public final void

public final void

public final void public final void }

The SoftwareElement class is the link between an HJA application and the HAVi Messaging System. Methods of the SoftwareElement class can be divided into several groups as summarized in Table 3-2.

TABLE 3-2 SoftwareElement Methods


addHaviListener removeHaviListener close Software element initialization and termination

ch03.qxd

7/16/2001

7:10 AM

Page 57

3 JAVA and HAVi

57

getSeid msgGetSystemSeid msgIsTrusted msgSendRequest msgSendRequestSync msgSendResponse msgSendSimple msgSendReliable msgWatchOn msgWatchOff

SEID operations

Service requests and responses (HAVi RMI)

Direct access to HAVi messaging Software element supervision (low-level support for monitoring whether a software element is present, not typically used by applications)

Creating Software Elements


Before sending requests to software elements, your application must create its own software element. HJA gives you two ways to create a new software elementthe constructors of the SoftwareElement class:
SoftwareElement mySe = new SoftwareElement(); SoftwareElement mySe = new SoftwareElement(HaviListener hl);

The hl parameter in the second constructor is an instance of a class that extends HaviListener. A HaviListener object is installed for a software element either via the SoftwareElement constructor or via the addHaviListener() method. HAVi listeners determine how a software element handles incoming messages.

The HaviListener Class


HJA defines HaviListener as:
public abstract class HaviListener extends java.lang.Object { public abstract boolean receiveMsg(boolean haveReplied, byte protocolType, SEID sourceId, SEID destId, Status state, HaviByteArrayInputStream payload); }

Since receiveMsg() of HaviListener is abstract, extensions of this class must implement this method.

ch03.qxd

7/16/2001

7:10 AM

Page 58

58

HAVi Example by Example

receiveMsg()returns true if it receives an incoming HAVi RMI service request that it will handle; in all other cases it returns false.

The haveReplied parameter shows whether some other listener has already replied to the message. If haveReply is true, then recieveMsg() should not also reply (and so should return false), although it is free to inspect the message. The protocolType parameter in receiveMsg() indicates whether the message uses the HAVi RMI protocol or some private (application-specific) protocol. If the message is a HAVi RMI service request or response, then protocolType will have the value ConstProtocolType.HAVi_RMI. The state parameter shows whether any error condition has arisen in the Messaging System during delivery of the message. The two SEID parameters indicate the sender (sourceId) and receiver (destId) of the message. destId will be the same as the SEID of the software element that installed the listener. payload is the message payload from which request parameters can be unmarshalled. Messages sent to a software element are passed to matching HaviListener objects installed on the associated SoftwareElement object. M Listeners installed by addHaviListener(HaviListener) match all messages. M Listeners installed by addHaviListener(HaviListener, SEID) match messages from the specified software element. An incoming message should be processed by only one listener. If you add several listeners to a software element, you should check the incoming message, for instance by examining its operation code, so that the message is processed by only one listener. This is shown in Example 3-10.

Example 3-10

A HaviListener

public class MyListener extends HaviListener { private short _myApiCode = 0x8000; private short _myOperationId = 0x00; private OperationCode _myOpCode = new OperationCode(_myApiCode, _myOperationId); public boolean receiveMsg(boolean haveReplied, byte protocolType, SEID sourceId, SEID destId, Status state, HaviByteArrayInputStream payload)

ch03.qxd

7/16/2001

7:10 AM

Page 59

3 JAVA and HAVi

59

{ // check haveReplied, protocolType, status and // the HAVi RMI header // see Example 3-15 for details OperationCode opCode = new OperationCode(payload); if(!opCode.equals(_myOpCode)) return false; // this message is for this listener, < process the message now and send reply, or do so in separate thread > return true; } } MyListener will process only messages containing the specific operation code created in line . The API code used to create _myOperationCode is 0x8000; this is in the range for applications rather than the predefined HAVi services. Before checking the operation code in the incoming message, MyListener first checks (as indicated by line ) that the message actually contains a HAVi RMI service request, in which case the first value in the message payload is the operation code. In Line , the operation code of the message can then be unmarshalled and used to create an OperationCode object.

SoftwareElement Threads and HaviListener

A SoftwareElement object has its own thread to call the HaviListener.receiveMsg() callbacks; it does not block other SoftwareElement objects or the underlying Messaging System while performing these callbacks. Consequently, there are no restrictions on the implementations of the (application-provided) HaviListener.receiveMsg() method: The method does not have to be treated as an interrupt. However, you must be careful when using SoftwareElement.msgSendRequestSync() in the HaviListener.receiveMsg() method, since this will block the calling software element until the response to the request is received. While the msgSendRequestSync() is blocked, no other incoming messages can be processed by the software element. This may result in a deadlock.

The HaviClient Class


HaviClient is an abstract class that is extended by all classes that create proxy objects, or stubs, that allow you to access software element services.

ch03.qxd

7/16/2001

7:10 AM

Page 60

60

HAVi Example by Example

public abstract class HaviClient extends java.lang.Object { // methods of HaviClient }

For instance, RegistryClient extends HaviClient and provides access to Registry services; EventMangerClient extends HaviClient and provides access to Event Manger services; and so on. See Example 3-11.

Example 3-11

A HaviClient Class

public class DcmClient extends HaviClient { public DcmClient(SoftwareElement se, SEID destSeid); // globally accessible DCM APIs }

The constructor in line identifies a software element that will be a client of DCM services; this is typically a software element created by the application. The second parameter identifies the SEID of the software element that will provide the services. This should be the SEID of a DCM; otherwise, an exception is thrown. To access a DCM, you first create an instance of DcmClient. Specific DCM services are then invoked via the methods of DcmClient:
dcm = new DcmClient(mySe, aDcmSeid); dcm.getDeviceIcon(< arguments omitted >);

In many cases, a software element may provide services that are accessible only to local software elements, i.e., software elements running on the same controller. This is reflected in HJA by subclassing the client class:
public class DcmLocalClient extends DcmClient { public DcmLocalClient(SoftwareElement se, SEID destSeid); // locally accessible DCM APIs }

The constructor of DcmLocalClient tests that destSeid (identifying the DCM) is on the same controller as se (identifying the client of the DCM). An exception is thrown if these do not match.

HaviException Classes
HJA maps HAVi status values to exception objects. This means that if you invoke services using a HaviClient subclass, then you can just catch exceptions rather

ch03.qxd

7/16/2001

7:10 AM

Page 61

3 JAVA and HAVi

61

than examine status values. HJA defines a large hierarchy of exceptions. Figure 3-3 shows the overall structure of this hierarchy. Exceptions that result from failed service requests derive from HaviException. For instance, all the general errors listed in Table 3-1 correspond to subclasses of HaviGeneralException. In addition, HJA defines exceptions classes that are related to: M marshallingHaviMarshallingException and HaviUnmarshallingException; M constructing HJA objects that correspond to IDL data structuresHaviInvalidValueException and HaviUnionException; and M Messaging System listenersHaviMsgListenerExistsException and HaviMsgListenerNotFoundException. Since HAVi errors are mapped to Java exceptions, you can make full use of Javas exception handling mechanisms. Also, the structure of the HaviException hierarchy helps in organizing exception handling code, as shown in Example 3-12.

Example 3-12

Catching HAVi Exceptions

dcm = new DcmClient(mySe, aDcmSeid); try { dcm.getDeviceIcon(< arguments omitted >); } catch (HaviDcmException e) { // problem with the DCM } catch(HaviException e) { // some other failure System.err.println(HAVi Error: + e.getMessage()); System.err.println( API code = + e.getApiCode()); System.err.println( error code = + e.errCode()); }

Figure 3-3 shows the structure of the HaviException class hierarchy. For brevity, not all exceptions classes are shown.

SEID Access
When a SoftwareElement object is created it is assigned a SEID; the value can then be retrieved using getSeid(), i.e.,
SEID mySeid = mySe.getSeid();

ch03.qxd

7/16/2001

7:10 AM

Page 62

62

HAVi Example by Example

java.iang Exception

HaviException

HaviGeneralException

HaviMsgException

HaviRegistryException

HaviUnknownMessageException HaviUnidentifiedFailureException HaviNotImplementedException HaviReserveException HaviInvalidParameterException HaviResourceLimitException HaviResourceSizeLimitException HavicompleteMessageException HaviincompleteResultException HaviLocalException HaviStandbyException

HaviMsgAckException HaviMsgAllocException

...

HaviMarshallingException HaviUnmarshallingException HaviInvalidValueException HaviUnionException HaviMsgListenerExists HaviMsgListenerNotFound

FIGURE 3-3 HAVi Exception Hierarchy

msgGetSystemSeid() is a convenient way to find the SEIDs of system software

elements on the same host as a specific SEID. Example 3-3 shows how to find the SEID of the local Registry.

Example 3-13

Using msgGetSystemSeid()

SEID mySeid = mySe.getSeid(); SEID regSeid = mySe.msgGetSystemSeid(mySeid, ConstSoftwareElementType.REGISTRY);

ch03.qxd

7/16/2001

7:10 AM

Page 63

3 JAVA and HAVi

63

The msgIsTrusted()method of SoftwareElement tests whether a software element is trusted (see Trusted and Untrusted Software Elements in Chapter 2); this is done by examining its SEID.

Sending Service Requests and Responses


Once you have created a software element, you can use the methods of SoftwareElement to send service requests and responses. You do not have to use these methods if communicating with a software element using a HaviClient subclass, since it sends the request for you. However, if you implement a software element that provides new services or if you write a software element that communicates with another software element for which there is no HaviClient, then you need to use the SoftwareElement methods for sending service requests and responses. The SoftwareElement class has three methods related to service requests and responses: M msgSendRequest()Sends an asynchronous service request. M msgSendRequestSync()Sends a synchronous service request. M msgSendResponse()Sends the response to an asynchronous or synchronous service request. Example 3-14 shows how to a send a synchronous request to a software element, in this case an unregister element request to the local Registry. Code similar to this would be used to implement the unregisterElementSync() method of RegistryLocalClient.

Example 3-14

Sending a Service Request

HaviByteArrayOutputStream hbaos = new HaviByteArrayOutputStream(); OperationCode opCode = new OperationCode( ConstApiCode.REGISTRY, ConstRegistryOperationId.UNREGISTER_ELEMENT); SoftwareElement mySe = new SoftwareElement(); SEID mySeid = mySe.getSeid(); SEID regSeid = mySe.getSystemSeid(mySeid, ConstSoftwareElementType.REGISTRY); mySeid.marshal(hbaos); int timeout = 2000; try {

ch03.qxd

7/16/2001

7:10 AM

Page 64

64

HAVi Example by Example

StatusHolder returnCodeH = new StatusHolder(); mySe.msgSendRequestSync(regSeid, opCode, timeout, hbaos, null, returnCodeH); } catch (HaviGeneralException e) { // code for general exceptions } catch (HaviMsgException e) { // code for Messaging System exceptions }

The parameters that need to be marshaled into the payload of msgSendRequestSync() or msgSendRequest() are determined by examining the IDL specification of the service. For the unregister element, this is:
Status Registry::UnregisterElement(in SEID seid) // IDL

Registry::UnregisterElement takes a single input parameter: the SEID of the

software element that is being removed from the Registry. Line shows this SEID being marshalled into the input byte array. Line sets the timeout for the request to 2000 milliseconds. The request is then sent in line , returnCodeH will hold the Status object that is returned. The fifth argument of msgSendRequestSync() is null, since unregister element does not return any values (other than the status value).

Direct Access to the HAVi Messaging System


The three service request and response and methods of SoftwareElement msgSendRequest(), msgSendRequestSync(), and msgSendResponse() implement HAVi RMI. This protocol is built on top of lower-level core HAVi Messaging System functionality. A complete protocol stack is shown in Figure 3-4. Direct access to the lower-level functionality of the HAVi Messaging System is provided by SoftwareElement through the methods msgSendSimple() and msgSendReliable(). M msgSendSimple()Sends a HAVi message to one or more software elements. No acknowledgment is given by the destination Messaging Systems. M msgSendReliable()Sends a HAVi message to a single software element. If this method returns without error, the destination software element has received the message.
msgSendSimple() and msgSendReliable() allow you to implement a private

protocol directly on top of the HAVi Messaging System core. However, if your

ch03.qxd

7/16/2001

7:10 AM

Page 65

3 JAVA and HAVi

65

HJA app

HJA app

HaviClient classes

service request methods msgSendRequest msgSendRequestSync msgSendResponse msgSendSimple msgSendReliable

HAVi Messaging System Low-level

HAVi RMI

HAVi Messaging

IEC 61883 FCP

IEEE 1394

FIGURE 3-4 HAVi Protocol Stack

software elements must interoperate with other software elements, then HAVi RMI is appropriate.

Software Element Example


You are now ready to put the pieces together and construct a fully functional software element. For this example, you will build a software element that offers two services: a hello world service that simply prints a string, and a goodbye service that causes the software element to terminate gracefully.

Example 3-15

The Hello and Goodbye Software Element

import org.havi.system.*; import org.havi.types.*; import org.havi.constants.*; // an HJA application that creates a software element // with two services: // Helloprint hello // Goodbyeclose the software element

ch03.qxd

7/16/2001

7:10 AM

Page 66

66

HAVi Example by Example

// public interface ConstMyService { public static final short apiCode = 0x8123; public static final byte helloId = 0x00; public static final byte goodByeId = 0x01; } public class MyApp { private SoftwareElement private MyListener

// unreserved // print hello // terminate

_mySe; _myListener;

public MyApp() { try { _myListener = new MyListener(this); _mySe = new SoftwareElement(_myListener); _mySe.add HaviListener(_myListener); } catch(HaviException e) { System.err.println(HAVi Error: + e.getMessage()); } } protected SoftwareElement getSoftwareElement() { return _mySe; } protected void helloServiceHandler() { System.out.println(MyApp: hello); } protected void goodByeServiceHandler() { System.out.println(MyApp: goodbye); _mySe.removeListener(_myListener); _mySe.close(); }

// MyListener inner class // public class MyListener extends HaviListener { private MyApp _myApp; private SEID _destSeid; private OperationCode _opCode; private byte _controlFlags; private int _transactionId; public MyListener(MyApp myApp) {

ch03.qxd

7/16/2001

7:10 AM

Page 67

3 JAVA and HAVi

67

_myApp = myApp; } public boolean receiveMsg(boolean haveReplied, byte protocolType, SEID sourceId, SEID destId, Status state, HaviByteArrayInputStream payload) { _destId = destId; if(haveReplied) { // another listener has replied // just ignore return false; } if(state.getErrorCode() != ConstGeneralErrorCode.SUCCESS) { // Messaging System problem // just ignore return false; } if(protocolType != ConstProtocolType.HAVi_RMI) { // incoming message is not a // HAVi RMI service request or response, // just ignore return false; } // unmarshal the HAVi RMI header // _opCode = new OperationCode(payload); _controlFlags = payload.readByte(); _transactionId = payload.readInt(); if((_controlFlags & 0x01) == 1) { // incoming HAVi RMI message // is a service response, // just ignore return false; } if(_opCode.getApiCode() != ConstMyService.apiCode) { // incoming HAVi RMI service request

ch03.qxd

7/16/2001

7:10 AM

Page 68

68

HAVi Example by Example

// uses an unknown/unsupported API code return false; } switch(_opCode.getOperationId()) { case ConstMyService.helloId: _myApp.helloServiceHandler(); sendMsg(ConstGeneralErrorCode.SUCCESS); return true; case ConstMyService.goodByeId: // reply before calling handler since // it will close us down sendMsg(ConstGeneralErrorCode.SUCCESS); _myApp.goodbyeServiceHandler(); return true; default: // unknown operation id; return false; } } // sendMsg() sends a HAVi RMI response // to the software element that has // sent us a HAVi RMI service request // public void sendMsg(short err) { Status returnCode = new Status( _opCode.getApiCode(), err); SoftwareElement se = _myApp.getSoftwareElement(); se.msgSendResponse(_destSeid, _opCode, ConstTransferMode.SIMPLE, returnCode, null, _transactionId); } } }

In Example 3-15, the constants used for API code and operation IDs are defined in the public interface ConstMyService. This interface is public since software elements that want to request the hello or goodbye service would need to know these values. In line , the value for the API code is set to 0x8123; this is in a range available to application developers.
receiveMsg() handles incoming messages to the software element created by the MyApp constructor. It first checks haveReplied and state. If haveReplied is

ch03.qxd

7/16/2001

7:10 AM

Page 69

3 JAVA and HAVi

69

true, then another listener has replied to the message. This will not happen in MyApp since only one listener is installed, but its good programming style to make the check. The state parameter tells whether an error has been detected by

the Messaging System (such as the sender of the message terminating). If no error is present, state.getErrorCode() will return ConstGeneralErrorCode.SUCCESS. Next, receiveMsg() examines protocolType to determine whether the message is a HAVi RMI service request or response. receiveMsg() then unmarshals the HAVi RMI header using the code repeated in Example 3-16.

Example 3-16

Unmarshalling a HAVi RMI Header

// payload is a HaviByteArrayInputStream // _opCode = new OperationCode(payload); _controlFlags = payload.readByte(); _transactionId = payload.readInt();

Recall from HAVi RMI earlier in this chapter that the HAVi message payload will contain the HAVi RMI header followed by any service-specific parameters. The HAVi RMI header contains the operation code, the control flags field, and the transaction ID. After unmarshalling the operation code in Example 3-16, the control flags and transaction ID are unmarshalled in lines and . The control flags are needed to distinguish between a service request and a service response (MyListener is not expecting service responses, but they may be sent erroneously by other software elements). The transaction ID is needed by sendMsg() to send the response to the requested service. Referring back to the body of receiveMsg() in Example 3-15, the Hello and Goodbye services do not take any parameters, so after unmarshalling the HAVi RMI header, no further unmarshalling is needed. receiveMsg() then checks the control flags and API code. If these indicate a request for a supported service, it does a switch on the operation ID of the requested service and invokes the service handlers supplied by MyApp and sends a response using sendMsg().

Summary
The HAVi Java APIs, or HJA, allow you to construct software elements that communicate over an IEEE 1394 (i. LINK) network. You can write two types of HJA application: havlets and controller-specific applications. Havlets are portable; they run on any controller supporting HJA. Controller-specific applications make use of features found on specific controllers and so are not portable.

ch03.qxd

7/16/2001

7:10 AM

Page 70

70

HAVi Example by Example

High-level classes like HaviClient, HaviListener, and SoftwareElement abstract the underlying HAVi Messaging System. These classes support a protocol called HAVi Remote Method Invocation (HAVi RMI) that is used by software elements to send service requests and responses over the Messaging System.

Das könnte Ihnen auch gefallen