|
|
©1996,1997 Enterprise Computer Telephony Forum
This document is copyrighted and all rights are reserved by the Enterprise Computer Telephony Forum (ECTF). " ECTF technical implementation agreements are considered public domain and may be copied, downloaded, stored on a server or otherwise re-distributed."
| May 20, 1997 | 0.1 | Spencer Dawkins |
|
| June 4, 1997 | 0.2 | Spencer Dawkins |
|
| June 12, 1997 | 0.3 | Spencer Dawkins |
|
| June 30, 1997 | 0.4 | Spencer Dawkins |
|
| July 15, 1997 | 0.5 | Spencer Dawkins |
|
| Sept 26, 1997 | 0.6 | Spencer Dawkins |
|
| Nov 15, 1997 | 0.7 | Spencer Dawkins |
|
(Unchanged for now) Post comments to the ECTF Portable API Mailing List: ectf-tgpapi@ectf.org
Thanks to all reviewers for their comments and feedback.
1. The Java Telephony API *
1.1 Overview of Contents *
3.1.1 Structural Call Model *
3.1.2 Dynamic Call Model *
3.1.3 State in Call Model Objects *
3.2 Sample JTAPI Application Flow *
3.3 Obtaining a Provider *
3.4 Investigating Call Model Objects *
3.5 Determining Capabilities *
3.6 Registering Observers *
3.7 Making JTAPI Requests *
3.8 Beginning and Ending Calls *
3.8.1 "Terminal-less Addresses" and "Out-of-Provider-Domain" Connections *
3.8.2 Using JTAPI to end a Connection *
3.8.3 When "the far end" ends a Connection *
3.8.4 The end of Call Observation *
3.8.5 Ending Connections and ending Calls *
5. Frequently Asked Questions *
5.2 What is the relationship of JTAPI to other telephony APIs? *
5.3 Where can I get the class files for JTAPI? *
5.4 What Java packages are included in JTAPI? *
5.5 What do implementers need to implement? *
5.6 Is JTAPI "blocking" or "non-blocking"? *
5.7 Why are there so many kinds of observers? *
5.8 How can I make JTAPI do "X"? *
This document provides an introduction to JavaSoft?s JTAPI (Java Telephony API).
JTAPI is the product of JavaSoft and several "partner" companies. The specific release described in this document is JTAPI 1.2.
The reference specification for JTAPI is here.
The rationale for a Java-based Telephony API comes in two stages.
The driving force behind the use of Java for this specification is the desire to maximize application portability across vendor implementations. "Application Portability" is literal - the application itself, in compiled form, may be loaded onto any conforming implementation and executed.
The Java programming language is used for this specification because of its support for "write once, run anywhere" application development.
JTAPI is intended to be a simple API as well. JTAPI still requires application developers to be knowledgeable about telephony, but reduces the amount of implementation-specific knowledge required to develop applications.
The range of "targets" for JTAPI ranges from the largest call centers, to desktop systems, to network computers, to "network telephones". This range is the reason for the "core plus extensions" organization of JTAPI, discussed below.
JTAPI blurs borders. It blurs the distinction between first-party and third-party call control, and it blurs the distinction between call control and media control.
JTAPI isn't "just another telephony API" - although JTAPI can be implemented without existing telephony APIs, it was also designed to allow implementers to build on top of these existing telephony APIs.
This section of the document describes JTAPI at the 50,000-foot level. More detail is available in the Overviews of the various JTAPI packages, which in turn point to the actual specifications - the final arbiter of correctness.
The reader may find it useful to refer to the JTAPI specifications for detailed definitions of JTAPI constants (shown in all caps, for example, ACTIVE) and methods (shown with parenthesized parameter lists, for example, addObserver()).
Note: several references are made to "a well-behaved JTAPI application" in this section, in the context of what "well-behaved JTAPI applications" do and don?t do. These comments indicate desirable attributes of JTAPI applications wishing to be as robust, and as portable, as possible. For instance, JTAPI does not require applications to register as object observers; applications have the option of investigating call model objects on their own. "Well-behaved JTAPI applications" don?t do this, because an unregistered JTAPI application has no way to monitor call model objects for state changes except for polling.
When a JTAPI implementation initializes, before it knows about any calls, it looks like Figure 1. The JtapiPeerFactory and JtapiPeer (used only to help applications locate the proper Provider), the Provider itself, and all configured Addresses and Terminals are known to the implementation.
The point to notice here is that the relationship between logical and physical endpoints is modeled as a many-to-many relationship between Addresses and Terminals.
This allows Terminals to have multiple Addresses, and allows Addresses to appear on multiple Terminals.
This "Structural Call Model" is sufficient to allow JTAPI applications to start executing.
Again, the point to notice here is that JTAPI applications have access to both logical and physical endpoints in the call.
The relationship between the Call and a logical endpoint (Address) is called a Connection; the relationship between the Connection and a physical endpoint (Terminal) is called a TerminalConnection.
The relationship between Calls and Connections is zero-to-many. IDLE Calls have no Connections; ACTIVE Calls have at least one Connection. Each Connection is tied to a single Address.
The relationship between Connections and TerminalConnections is zero-to-many. This allows JTAPI implementations to support multiple active Terminals for the same Address, if the underlying telephony environment allows this.
Placement of JTAPI methods in this call model is based on whether the application is working with an entire Call, a single Address in the Call, or a single Terminal in the Call. For instance, JTAPI applications
Not all call model objects have internal state. These call model objects do:
For instance, the Core Connection state CONNECTED corresponds to the Call Control Connection states INITIATED, DIALING, NETWORK_REACHED, NETWORK_ALERTING, and ESTABLISHED.
Core Observers see Core events, while extension package observers see extension package events.
The precise strategy the application uses to investigate call model objects is very application-dependent. Common strategies include:
Capabilities takes two forms:
Many static capabilities can be determined at initialization time, but dynamic capabilities can come and go. For this reason, a well-behaved JTAPI application will query relevant capabilities at initialization time, in order to "gray out" unsupported/unavailable features in user interface displays, but will check again when preparing to invoke the relevant method. This will minimize the number of exceptions the application will encounter.
A JTAPI application can still be "well-behaved" without checking capabilities, as long as it catches MethodNotSupportedException and InvalidStateException. This approach is simple, but does not allow the application to present an accurate user interface (the user may attempt actions which aren?t allowed by the implementation).
Capabilities are aligned one-to-one with methods; if a method isn?t implemented in all environments, a capability exists to allow the application to check whether it is available at execution time.
Every JTAPI call-model object has an associated capability object:
This is done using a mechanism called "entity-observer-events", loosely based on the "monitor" facility described in C.001, and commonly used in existing telephony APIs:
Events correspond one-to-one with call model state transitions. In the general case, an application wishing to learn about state changes in JTAPI object X invokes the method X.addObserver(), providing an "event handling routine" as a parameter. Upon returning from X.addObserver(), the application will start to see the event handler called whenever the observed call model object changes state. These events will continue to arrive until the application invokes X.removeObserver().
When a JTAPI implementation has finished adding a new observer, it will send events to the observer which bring the application?s view of the call model?s state in line with the implementation?s view. This process is called "snapshotting".
Snapshotting happens automatically when applications register observers.
It is not necessary for the implementation to synthesize every event that has happened in the history of the call - if a party has been one-step-conferenced in, and then disconnected, the snapshot need not include these events. Only the events required to bring the Observer "up to speed" are required.
Call Observers extend the single-object observer model. Call Observers get events for all the call model objects in the call.
A variant exists for Addresses and Terminals. The application invokes Address.addCallObserver(), providing an "event handler routine" as in the previous examples. Each time a Call arrives at the Address, the implementation will add the event handler as a Call Observer for that call. The application?s event handler will receive events for the call until one of these things happens:
Terminal.addCallObserver() and Terminal.removeCallObserver() are exactly analogous to the Address.addCallObserver() and Address.removeCallObserver() methods.
Because telephony events can happen at any time, and because JTAPI methods can block for an arbitrarily long period of time, well-behaved JTAPI applications will use at least two threads (one for invoking methods on the implementation, and another for receiving events). More threads may be desirable, depending on the application and its environment.
Well-behaved JTAPI applications will also not invoke (potentially blocking) JTAPI methods in the execution thread it uses to receive events, because these methods may generate additional events while the Observer is blocked.
Fortunately, Java makes multithreading relatively painless.
Outgoing Calls are created by the implementation at the request of JTAPI applications, by invoking Provider.createCall(). Incoming calls are created by the implementation when it receives an indication of an incoming Call through normal telephony signaling.
Calls are created in IDLE state, with no Connections. When a JTAPI application invokes the "Call.connect()" method, to place an outgoing call, or when the implementation creates a Call to represent an incoming call, two Connections are created and associated with the Call.
When a Call gets its first Connection, it becomes an ACTIVE Call, and it remains an ACTIVE Call until it has no Connections in the CONNECTED state.
Typically, Connections are associated with one or more TerminalConnections. This is how a path to a logical endpoint - an Address - is mapped to a physical endpoint - a Terminal.
In some cases (discussed in Section 3.8.1), no Terminal/TerminalConnection is created for the Connection.
When a JTAPI application originates an outgoing Call, the "near-end" Connection advances to the CONNECTED state, and the corresponding TerminalConnection advances to ACTIVE, reflecting the real-world phenomenon of "dial tone".
When a JTAPI application issues TerminalConnection.answer(), to answer an incoming Call, or when the implementation receives an indication via normal telephony signaling that an outgoing call has been answered, the "answered" Connection is advanced to the CONNECTED state, and the corresponding TerminalConnection is advanced to the ACTIVE state. This is what an average person would consider to be a useful phone call - an end-to-end path between two sets of logical/physical endpoints.
A fully-established JTAPI call looks like Figure 4.
Implementations may also create Terminals dynamically. This is appropriate when the implementation allows an application to manipulate Terminals and TerminalConnections on Connections to "out-of-Provider-scope" Addresses.
In two cases, JTAPI Connections may not create Terminals dynamically, and may not create TerminalConnections corresponding to a Connection.
Methods like Provider.getAddresses() and Provider.getTerminals() return only Addresses and Terminals "within the Provider's domain".
A fully-established JTAPI Call which includes a Connection to a Terminal "outside the Provider?s domain" may look like Figure 5.
When a JTAPI application decides to end a Connection - an Address?s association with a Call - it invokes "Connection.disconnect()" on one of the Connections associated with the Call. From JTAPI?s perspective, either Connection will do; there is no concept of "originating" or "terminating" Connections in JTAPI. In many environments, implementations may limit the application?s ability to disconnect every Connection in the Call, based on the user?s permissions; "well-behaved" JTAPI applications invoke "canDisconnect()" to make sure they are disconnecting "the right" connection.
Connection.disconnect() advances the Connection?s state to DISCONNECTED, and advances the state of all TerminalConnections associated with this Connection to DROPPED. When Connection.disconnect() returns control to the application, this action is complete, so the application can ignore events associated with this invocation of this method.
When "the far end" user (JTAPI or otherwise) ends her association with the Call, the JTAPI implementation is notified that "the connection has gone away", via normal telephony signaling, and the JTAPI implementation advances the appropriate Connection to DISCONNECTED state. Registered CallObservers are notified that this has happened by the implementation, using ConnDisconnectedEv ("Connection Disconnected Event") and TermConnDroppedEv ("Terminal Connection Dropped Event").
When an ACTIVE Call has only one CONNECTED Connection, the implementation may choose to set the remaining CONNECTED Connection to DISCONNECTED. In the case where a far-end party hangs up, this would be appropriate.
However, having only one CONNECTED Connection does not automatically end the Call. If the implementation knows it is executing a "call transfer", and the implementation receives an indication that the "transferred from" Connection is DISCONNECTED, the implementation should not end the Call, because it is expecting to receive an indication that another Connection is being added to the Call as well.
Because implementations are better placed to know when calls should be ended, implementations, and not applications, are responsible for detecting situations where the Call has only one CONNECTED Connection, and isn?t expected to add Connections. In these situations, the implementation should DISCONNECT the remaining Connection, remove all Connections from the Call, and advance the Call state to INVALID.
So JTAPI applications should not attempt to detect the end of Calls and tear down Connections. They should, however, dereference the Call and its associated Connections and TerminalConnections when the implementation advances the Call state to INVALID.
In a Core JTAPI two-party call, disconnecting a Connection is equivalent to ending the call, because Core JTAPI does not include transfer and conferencing capabilities - there?s no way to add Connections to a Call with only one CONNECTED Connection. The Call Control package includes a CallControlCall.drop() method, to provide a short-cut when the application wants to end a Call which may have three or more ACTIVE Connections - this method is equivalent to disconnecting all Connections.
From Jim Wright?s presentation at 1997?s JavaOne conference: JTAPI " Enables portable Java TM applications to setup, control and tear down calls (and control their associated data streams) to and from public and private networks, on a broad spectrum of host telephony platforms ".
It's important to note that JTAPI isn?t just a call control API - it also controls associated media streams. Providing a single API that covers both these areas is one of JTAPI?s design goals.
As shown in Figure 6, JTAPI is independent of existing telephony APIs, but can be implemented using these APIs as primitives.
Most of the JTAPI implementations we are aware of are based on these APIs, but as shown in Figure 6, JTAPI can be implemented entirely in Java if a switching platform supports this.
We should mention that diagrams like this may give the impression that the JTAPI implementation has to run on the same platform as an existing telephony API, but this isn?t true. Figure 7 shows a very typical implementation architecture, called "thin-client", which uses Java?s Remote Method Invocation (RMI) technology to access a telephony server across a network. Other networking technologies could be used as well (JOE, etc.), as long as the client and the server understand the same technology. JTAPI is neutral on this issue.
The JTAPI API provides a unified view of diverse underlying telephony environments. For instance, the JTAPI call model can express either first-party or third-party call control, although underlying implementations will typically support one or the other.
This diversity, hidden from applications, falls squarely on JTAPI implementers. We believe it?s infeasible to write a JTAPI implementation that is portable across the underlying telephony APIs.
So, unlike many Java APIs, you don?t download Java class files and run your application. JTAPI requires an implementation, specific to your telephony environment, in order to function. To meet this requirement, vendors provide JTAPI implementations that run in specific telephony environments.
JTAPI uses a "core plus extensions" structure. The packages included in JTAPI 1.1.1 are:
These packages are available from here.
JTAPI 1.2 adds (with associated "events" and ""capabilities"):
At the very least, implementers must support the javax.telephony, javax.telephony.capabilities, and javax.telephony.events packages. These packages constitute "Core JTAPI".
Additional packages may be supported as necessary.
The correct answer is "yes".
JTAPI has design goals of minimizing application complexity and portability. Most JTAPI methods do not immediately return control to the application. Instead, most methods guarantee "post-conditions" when they return control to the application.
These post-conditions are documented in comments on each method in the detailed specification.
For instance, javax.telephony.connection.disconnect() guarantees that, when control is returned to the application, the connection has been DISCONNECTED, and the associated terminal connection has been DROPPED (among other post-conditions).
This approach requires application execution threads to block until these post-conditions are met. The application doesn?t have to check to make sure these state transitions are really happening.
So JTAPI is, strictly speaking, blocking. Application developers are responsible for knowing when their applications are likely to suspend execution. In particular, observer event delivery threads should not make potentially blocking JTAPI method calls, because this could lead to circular waiting deadlocks (the observer is waiting on the response to the method call, which the implementation can?t deliver because the observer is blocked).
The exception to this rule is that JTAPI methods tend to wait on machines, but not on humans. Javax.telephony.connection.disconnect() waits until the connection is actually disconnected, because this happens fairly rapidly. Javax.telephony.call.connect() does not wait until the call is actually connected, because this would block the application while the called party wakes up, gets out of bed, walks down the hall, and answers the phone.
And this is why a blocking API also uses an "entity-observer-event" model!
JTAPI doesn?t cover every possible situation in every possible telephony environment, and it never will.
JTAPI wasn't designed top-down, to anticipate all requirements of computer telephony. The contents of JTAPI to date have been determined pragmatically. When people working on the specification encountered a situation or application that isn't covered, they contribute proposals extending JTAPI, and, if there is sufficient interest, the specification is extended to include these proposals as modified by the "JTAPI team".
If JTAPI would be perfect for your application except that it doesn?t "do X", these are the suggested guidelines:
This section of the document describes the "rules of engagement" for JTAPI.
Participants in the JTAPI specification team come from two primary sources:
