TeamCall / CAP JTAPI Application Developer's Guide
Version: $Revision: 1.15 $
Created on: $Date: 2017-02-22 17:36:02 $
Contents:
2.1 Terminals and Address objects
2.2 Synchronous event notification
2.3 JTAPI method calls in event handler methods
2.4 Supported methods
2.5 Behaviour of thetransfer()
method
2.6 Event notification for call control observers
2.7 Empty meta event cycles for call listeners
2.8 Private extensions
3. Examples
3.1. Obtaining a provider instance
3.2. Registering a call observer on an address
3.3. Placing a call
3.4. Answering a call
5. References
JTAPI is Sun's
definition of a vendor-neutral object oriented telephony API for Java. It consists of a number of interfaces
that define the methods and behaviour of the abstractions for real-world
objects such as a telephone number, a device, a call, etc.. Objects
are the source of events that report certain changes of an object's state.
A JTAPI application client first obtains a
Provider instance, then
asks the provider for an Address object, the
logical representation of a phone number. Afterwards, it may register
a call listener or observer on that address to be notified of events arriving.
It may also actively make calls, answer inbound calls, create conferences, etc..
To use the CAP JTAPI implementation, you must first install a few jar files. Please refer to the CAP JTAPI Installation Guide
for further information.
Note: JTAPI 1.3 is not compatible with Java 2 SE 1.4.
javax.telephony.ProviderUnavailableException
defines a getCause()
method
that returns an int
containing information why a provider is unavailable. Java 2 SE 1.4
re-declares the method getCause()
on java.lang.Exception
to return a
java.lang.Throwable
. For now (until JTAPI 1.4 is released) there is no way to use a
JTAPI implementation in Java 2 SE 1.4. Use Java 2 SE 1.3.1 instead.
This implementation supports the basic interface methods from javax.telephony plus some additional functions from the call control package javax.telephony.callcontrol. There are certain restrictions which will described in the next few chapters.
2.1 Terminals, Address and Provider objects
The implementation is limited to a first party only view. This means that all remote connections of a Terminal are
modelled as "out-of-the-provider-domain", including devices
that are in the same PBX . Application clients may need to obtain
a local version of the remote object (via calling getAddress() on the Provider object). This object
may support certain call control operations, that are disabled on the
remote objects. Please see the JTAPI
white paper's section about "out-of-the-provider-domain" objects
for further details.
Please also note that the implementation supports a dynamic address
space only, the addresses are not known to the provider implementation
before they are requested. Calling getAddresses()
on the Providerwill always return null.
The JTAPI specification allows an Address to have multiple Terminal
objects assigned, this implementation will always return only one instance
(one-to-one mapping).
The Provider connects to the SCC(P) upon creation. Thus it is always "IN SERVICE"
as soon as JtapiPeer.getProvider()
returns an instance without an exception.
The provider will not send a javax.telephony.events.ProvInServiceEv
to any observer
or listener that is registered at any time. Don't wait for this event.
When the provider looses its connection to the SCC(P),
it notifies all listeners and observers by sending a javax.telephony.events.ProvObservationEndedEv
.
References to the provider instance should be removed from the client application and a new provider
instance should be obtained from the JtapiPeer
.
2.2 Synchronous event notification
Event messages are sent synchronously, i.e. each event handler is called one after the other directly from the underlying message transport thread. Clients are responsible for dispatching time critical operations in separate threads. The whole application is blocked until the event handler's method call returns. Using a fully synchronous callback mechanism gives the application developer a better control over the (otherwise excessive) thread generation during dispatching.
2.3 JTAPI method calls in event handler methods
Due to the synchronous callback mechanism it is not possible to perform JTAPI method calls directly from within the callback handler. This has to be done in a separate (or perhaps newly created) thread. Please also see the JTAPI white paper's section about blocking calls.
To check whether a method is support by a specific object, please obtain the Capabilities from the object.
The capabilities for Call
, Connection
and TerminalConnection
are call control capabilities that
can be casted to their call control version (e.g. CallControlTerminalConnectionCapabilities
) and then queried for extended
call control features.
NOTE: The capability object returns "true" for some call control methods, which may in fact only work on certain combinations of PBX type,
phone configuration, remote party type and call state. Please check your specific configuration manually by writing a short test program,
as these methods (e.g. hold, transfer) are not guaranteed to work on all configurations.
2.5 Behaviour of the transfer()
method
In contrast to the JTAPI specification for CallControlCall.transfer()
, both calls involved
might go directly to state INVALID
after calling transfer()
. This is due to the
nature of the underlying monitoring concept. An observer on the transferring device will receive two
CallInvalidEv
events, since the transferred and the receiving party might be out of the
provider domain and thus the clearing of the call would not be reported to this observer.
2.6 Event notification for call control observers
Observers that registered as call control observers (by implementing
javax.telephony.callcontrol.CallControlCallObserver
) will
receive additional call control events directly after the normal event notification,
i.e. they will receive two events for the same underlying state change.
Observers therefor should check not to perform duplicate actions when receiving
events. Example:
javax.telephony.callcontrol.events.CallCtlConnDisconnectedEv
andjavax.telephony.events.ConnDisconnectedEv
.getCallControlCause()
), that might be useful for the observer.2.7 Empty meta event cycles for call listeners
Call listeners may expirience situations, when only meta events are delivered to the listener. No actual call event is delievered between the starting and ending meta event. This behaviour results from the fact that certain call control events don't have an equivalent event in the standard package and the meta events are distributed whenever an event (call control or normal) occurs. Future versions of JTAPI will include listeners for the call control package and the problem will be re-adressed.
The JTAPI specification lacks support for certain important events and methods. To offer those additional functions, this implementation offers additional private extensions.
The following extensions are available:
de.ilink.cti.cstajtapi.extensions.ExtendedCallControlCall
:blindTransfer(Call aCall)
). See ECMA TR/82 for additional
information about blind transfers in general.de.ilink.cti.cstajtapi.extensions.ExtendedAddress
:getDeviceState()
method that returns the physical state of the address.
Addresses that are out of the provider domain always return DEVICE_STATE_UNKNOWN
.de.ilink.cti.cstajtapi.extensions.ExtendedAddressObserver
:de.ilink.cti.cstajtapi.extensions.ExtendedTerminal
:getDeviceState()
method that returns the physical state of the terminal.
Terminals that are out of the provider domain always return DEVICE_STATE_UNKNOWN
.de.ilink.cti.cstajtapi.extensions.ExtendedTerminalObserver
:The following examples show some of the typical usages of the JTAPI package.
3.1. Obtaining a provider instance
To obtain a JTAPI provider instance, perform the following steps:
a) Get a JTAPI peer for the implementation:
JtapiPeer peer = JtapiPeerFactory.getJtapiPeer("de.ilink.cti.cstajtapi.JtapiPeerImpl");NOTE: JTAPI implementation may also support a "default peer" implementation that is created when
JtapiPeerFactory.getJtapiPeer()
is called with a null
parameter. This function is NOT supported by this implementation, since it is most likely that this feature
will be dropped in the next release of JTAPI. The lookup mechanism used by JtapiPeerFactory
is incompatible with certain restrictions
of Java 1.4 (all classes must be in packages).<port>@<hostname>
format, the application identifier for the ACSE authentication request
("applicationID") and an optional username
and password for authentication ("login","passwd").String providerString = "26535@test;applicationID=CAP;login=testUser;passwd=testPass";
Provider myProvider = peer.getProvider(providerString);
The provider should now be ready and connected to the remote CSTA XML server. If the initial authentication fails or the remote side signals that it is out of service, an exception is thrown during creation of the provider object.
3.2 Registering a call observer on an address
a) Get an address object from the provider:
Address addr = myProvider.getAddress("123");
Address addr = myProvider.getAddress("+49(30)12345-123");
CallControlCallObserver callObs = new MyObserver();
addr.addCallObserver(callObs);
Whenever call related events on the addr object occur, the callObs object's callChangedEvent method will be called. Note that in conformance with the JTAPI specification only call events for calls that were started after the observer was registered are reported.
This example shows how to place a call from the phone specified by
the Address object addrto the phone number "5678":
a) Obtain a terminal instance from the Address:
Terminal[] termArr = addr.getTerminals();
Terminal term = termArr[0];
Call call = myProvider.createCall();
Connection[] connections = call.connect(term,addr,"5678");
connections[0].disconnect();
No matter whether the connection is disconnected manually or programmatically, all events that report the dropped connection are send to the observers. See the JTAPI documentation for the details of the event flow.
This example shows how to answer a call using an event handler method.
Note that the actual answer() method call
has to be performed in a separate thread to avoid circular deadlocks.
a) Create a class that implements javax.telephony.callcontrol.CallControlCallObserver.
Register an instance of this class on the address you want to answer calls on.
In the callChangedEvent() method of
the class check for a TermConnRingingEv
arriving on your observed address (via instanceof)
public class MyObserver
implements CallControlCallObserver
{
public void callChangedEvent(CallEv[] anEventArr)
{
if (anEventArr[0] instanceof TermConnRingingEv) {
final TerminalConnection
tc = ((TermConnRingingEv)anEventArr[0]).getTerminalConnection();
new Thread() {
public void run() {
try {
tc.answer();
} catch (Exception ex) {
ex.printStackTrace();
}
}
}.start();
}
}
}
In your main program:
CallControlCallObserver callObs = new MyObserver();
addr.addCallObserver(callObs);
Whenever a call arrives on the given address, a TermConnRingingEv is fired by the JTAPI implementation. The observer will then answer the call automatically by calling answer() on the affected TerminalConnection object. Real world applications could also present the user a popup window and ask whether they should answer the call or not.
For special cases, TeamCall JTAPI supports a few optional configuration switches that subtly change the behavior in order to support non-standard situations.
These cases are not documented here, ilink support will let you know to use a specific configuration if that should become necessary.
The configuration switches are specified in a configuration file jtapi-config.properties which needs to be located in the Java working directory (i.e. the path specified by the Java environment variable user.dir).
JTAPI API documentation
JTAPI white paper
JTAPI installation guide
ECMA TR/82 - Scenarios for Computer Supported Telecommunications Applications (CSTA) Phase III