Introduction
Table of Contents
Revision History
Audience
Notation
Referenced Documents1 Overview
2 Objective
3 Requirements
4 Framework
5 Use Cases
6 Base Architecture6.1 CRC Cards7 Component Sub-Architectures
6.2 Interaction Diagrams6.2.1 System Initialization
6.2.2 JTAPI Command
6.2.3 Telephony Provider Call Event
6.2.4 Telephony Provider Media Event
6.2.5 Deprecated 1.2 Media Event
6.2.6 Event Registration
6.2.7 Exception Handling7.1 Initialization8 Issue Support
7.2 Object Mapping
7.3 CallId Lifecycle
7.4 Event Propagation
7.5 Exception Management
7.6 Remote Support
7.7 Call Transfer/Conference
7.8 Media Support
7.9 Deprecated 1.2 Media Support
7.10 Fax
7.11 Capabilities
7.12 Extended JTAPI package support
7.13 Telephony Provider Tuning
7.14 Dynamic Domain
7.15 Weak Synchronization7.15.1 Problem
7.15.2 Options
7.15.3 Goals
7.15.4 Similar Problems
7.15.5 Analysis
7.15.6 Weak Synchronization Architecture8.1 Asynchronous vs. Synchronous
8.2 Multi-Threading
8.3 Callback Dispatch
8.4 Scalability
Version Date Author Comment 0.2May 23, 2000 Richard Deadman Rewrite of the original U|Force "UF-GJTAPI-0001-PLUG" document into native HTML with a self-contained focus instead of as a "pluggability" section of a larger document. 0.3May 30, 2000 Richard Deadman Fixed up page colours. Added decorator pattern comment. Enhanced MedaService discussion. Changed "Raw Provider Interface" to "Telephony Provider Interface". 0.4June 27, 2000 Richard Deadman Added section on weak synchronization. Updated event notification threading and dynamic address support. 0.5September 25, 2002 Richard Deadman Minor link and typo corrections.
Note that developers of TelephonyProviders may find the "Generic JTAPI TPI Implementor's Guide" to be more useful.
Monospaced Quoted material from another source Monospaced Italics Example source code (e.g. peer.getProvider("Emulator")) Grey Boxes Indicate proprietary information not to be released past U|Force.
TpiImplementorsGuide.html Generic JTAPI TPI Implementor's Guide http://java.sun.com/products/jtapi/ JTAPI Specification Web Page Design Patterns: Elements of Reusable Object-Oriented Software; Gamma et al., Addison-Wesley Publishing, 1995 Design Patterns
A low-level implementation must be at least an order of magnitude easier to implement than a full-blown JTAPI implementation from scratch.
|
|
We note in particular that the development of a low-level "telephony provider interface" allows us to apply the Decorator Pattern to usages of the Framework. From Gamma et al, we can take the Decorator Intent:
Attach additional responsibilities to an object dynamically. Decorators provide a flexible alternative to subclassing for extending functionality.In essense, a decorator allows an object to be wrapped in an object that delegates off core responsibility to the wrapped object and "decorates" itself with additional capabilities. In the case of the above diagram, the "Optional Remote Proxy" is a decorator for the "Emulator Provider". It delegates off low-level TPI calls to the Emulator Provider but decorates the Emulator Provider with remote accessing capabilities.
To see how these Use Cases are mapped to the proposed low-level pluggable API, see the section outlining the Interaction Diagrams.
JTAPI Package Class Supported Unsupported core Address, Call, Connection, Terminal, TerminalConnection All callcenter All callcontrol CallControlAddress All CallControlCall addParty
conference
consult(TerminalConnection, String)
drop
getConferenceController
getConferenceEnabled
getTransferController
getTransferEnabled
setConferenceController
setConferenceEnabled
setTransferController
setTransferEnabled
transfer(Call)
transfer(String)consult(TerminalConnection)
getCalledAddress
getCalledAddress
getCallingTerminal
getLastRedirectedAddress
offHookCallControlConnection All CallControlTerminal All CallControlTerminalConnection getCallControlState
hold
unholdjoin
leavemedia 1.3 Media (MediaTerminal, MediaProvider, MediaService) All (renamed BasicMediaService to GenericMediaService due to JTAPI specification error) MediaTerminalConnection (1.2 deprecated) All mobile phone privatedata
6.1 CRC Cards
| TelephonyProvider | |
|---|---|
|
|
|
|
Provide
implementation specific properties
|
(Properties
and corresponding file)
|
|
Register
and unregister Listeners
|
|
|
Control
basic telephony functions
|
|
|
Manage
DTMF playing and recording
|
|
|
Manage
audio playing and recording
|
|
|
Manage
Fax sending and receiving
|
|
|
Allow
for the reservation and release of CallIds
|
| TelephonyListener | |
|---|---|
|
|
|
|
Observe
telephony events generated by the TelephonyProvider
|
|
|
Forward
events
|
GenericProvider
|
| RawStateException | |
|---|---|
|
|
|
|
Encapsulate
low-level state exception
|
|
|
Create
a InvalidStateException
|
GenericProvider
|
| CallId | |
|---|---|
|
|
|
|
Encapsulate
TelephonyProvider specific call identity
|
6.2 Interaction Diagrams
The following interaction diagrams do not map directly to JTAPI API calls or Use Cases, but rather to classes of similar behaviour in the system. For instance, the system may be thought of as having several co-ordinated facets:Note: The following diagrams have not been completed at this time.
- Initialization phase, during which the GenericProvider creates, configures and interrogates its TelephonyProvider in order to create an initial state for the system.
- JTAPI command handling, during which commands are sent to the TelephonyProvider to control an aspect of the telephony system.
- Event registration, during which applications register with the framework for JTAPI events. This may lead the framework to turn on low-level event reporting.
- Event handling, in which telephony events from a Telephony Provider are received and used to update the system state machine which in turn generates JTAPI events to registered applications.
- Exception handling from low-level commands. These may optionally be "morphed" into the object-model of the Framework before being reported back to the calling application.
6.2.1 Initialization
- The GenericJtapiPeer is sent the message "Provider getProvider(String param)"
- The GenericJtapiPeer parses the parameter string for a sub-provider name and any appended name-value properties.
- The GenericJtapiPeer checks if the sub-provider name is null and then chooses the default TelephonyProvider class.
- Otherwise the GenericJtapiPeer determines the TelephonyProviderClassName from its look-up table
- An instance of the TelephonyProvider is created.
- The GenericJtapiPeer creates a GenericProvider with the TelephonyProvider and the parameters.
- The GenericProvider initializes the TelephonyProvider with the passed in parameters.
- The TelephonyProvider chooses how to use the parameters with any of its own values.
- The GenericProvider queries the TelephonyProvider for an updated capabilities set, and uses this to build the static Capabilities objects.
- The GenericProvider asks the TelephonyProvider for a lists of all Address names.
- For each address name, the GenericProvider asks the TelephonyProvider for the associated terminal names.
- For each terminal name, the GenericProvider asks the TelephonyProvider if it should instantiate a MediaTerminal instance or a regular Terminal instance.
- The GenericProvider creates its fixed Address and Terminal collections.
7.1 Initialization
When the GenericJtapiPeer is sent the message "getProvider(String foo)", it will always return an instance of GenericProvider. The GenericJtapiPeer will load its own Properties object from a "properties" file that not only defines high-level properties, including maybe default capabilities, but also the following properties:DefaultProvider = Emulator
A set of TelephonyProviderName:TelephonyProviderClassName pairs, with keys prepended with the prefix "PROVIDER", i.e.PROVIDER_Emulator = com.uforce.jtapi.generic.raw.emulator.EmProvider
The basic algorithm is:
- The local peer properties file is read for a list of sub-provider (name : fullyQualifiedClassName) pairs.
- The string foo is parsed for a sub-provider name and any name-value properties. So "Rmi;name=foo;server=bar" will indicate that the RMI sub-provider is requested, with two properties.
- If "foo" is null or an empty string, the default sub-provider is used.
- If "foo" is not a key in the provider list, it is assumed to be the fully qualified path name of the sub-provider.
- The selected sub-provider class is loaded and instantiated.
- The selected sub-provider is initialized with the passed-in properties. It is up to the sub-provider to determine the semantics of these properties, and if they should replace or append any property-file loaded properties.
- The GenericProvider instance asks the sub-provider for any changes to the basic capability set for the five base telephony operations. These new values are used to build the static Capabilities set.
- The GenericProvider instance interrogates the sub-provider for Address and Terminal names and builds its collection of Address and Terminal objects. For each terminal name returned, the sub-provider is asked if that terminal supports media services. If it does, the appropriate MediaTerminal instance is created and stored.
- The GenericProvider is returned to the calling application.
Thus, the Generic JTAPI framework take the responsibility for parsing property strings and initializing a Provider hooked to a plugged-in low-level "raw" telephony provider.
7.2 Object Mapping
One of the goals of the Generic JTAPI framework is to reduce the amount of work required to build a low-level provider. For this reason, the low-level provider is not exposed to the JTAPI object level, but instead deals with call ids, address names and terminal names. We note that these are sufficient to uniquely identify any basic JTAPI object (excluding the Provider, of course):
| Object | CallId | Address Name | Terminal Name |
|---|---|---|---|
| Call | X | ||
| Address | X | ||
| Terminal | X | ||
| Connection | X | X | |
| TerminalConnection | X | X | X |
Thus, while JTAPI may deal with the five objects in the left-hand column, the sub-provider deals with simpler CallId objects and strings. This facilitates easy serialization (over a socket, for instance) of the connection between the JTAPI framework and the sub-provider, as well as decoupling the sub-provider from the intricacies of managing JTAPI object relationships.This mapping is key to understanding some of the requirements of the Generic JTAPI framework. For instance, while most JTAPI exceptions may be thrown directly by the sub-provider, InvalidStateException (which requires a handle on the object with the invalid state) may not. Instead, a RawStateException object, with the same information using primitive types, is thrown instead. The Generic JTAPI framework takes the responsibility for transforming the RawStateException object into the appropriate InvalidStateException object.7.3 CallId Lifecycle
CallIds are unique sub-provider references to logical calls. The Generic JTAPI Framework makes no assumptions about the reference, other than that "equals()" behaves appropriately. CallId instances are mapped to JTAPI Call objects.
Calls can be created in two ways:
- An event is sent from the sub-provider that a new call has appeared. The JTAPI layer will check if the event maps to a known Call object. If it does not, a new Call object is created.
- An application asks the Provider for a new Call object. In this case, the Call object reserves a low-level CallId from the sub-provider. (This pre-reservation requirement is explained in the following discussion)
We have to be careful in the timing of CallId creation and destruction, or we can lead to duplicate Call objects or Call commands send to the wrong Call. During creation, a CallId must be pre-allocated prior to the Call being started. If it is not, there is a risk that the call start will create Call events from the TelephonyProvider that will appear back in the framework before the createCall() method returns. Since no CallId has been pre-allocated, the Framework does not know that this is a call it is in the process of creating and instead creates a duplicate Call object.
Similarly, the TelephonyProvider should not recycle CallIds until the Framework has reported that it has also finished with the Call. Otherwise there is a chance that, due to message latency, the Framework will request a Call action on a CallId that has already gone to idle and been recycled for a new call.
Since no other requirements are placed on CallId other than that they respect "equals", we must be careful during remote serialization. Serialization may cause problems in that "equals" may rely on object "=" which is broken by the deep-copy of RMI (for instance). Serialization also imposes restrictions on how transient and non-transient fields should be assigned to CallId implementations. There are two approaches we could take here:
- Impose extra semantic restrictions on the CallId implementation (i.e. The generation and maintenance of a serialization unique id).
- Delegate the remote identity problem to the remote proxy layer.
As part of the general philosophy of keeping the sub-provider requirements as simple as possible and centralizing the complexity in the re-usable pieces, the latter approach has been taken. See the discussion below on Remote proxies.
7.4 Event Propagation
In the Generic JTAPI Framework architecture, the framework is decoupled from the telephony implementation through the use of the TelephonyProvider and TelephonyListener interface. The TelephonyProvider interface defines how the Generic Framework issues telephony commands to the telephony system. Conversely, the telephony system (board, VOIP, PBX interface) must relay asynchronous state information back to the Generic JTAPI Framework (new call arrived, terminal on hold, connection dropped). The goal is to provide as simple an "event" notification interface to TelephonyProviders as is possible, letting the Generic Framework handle any morphing of event information.
JTAPI, prior to 1.3, used the traditional Observer pattern for indicating object state changes. In the Observer pattern, an event is passed which encapsulates state change type information as well as details. Events could be sent in batches, such as for a series of events related to a transfer.
In JTAPI 1.3, the Observer pattern was deprecated in favour of the more object-oriented Listener pattern. The Listener pattern is more explicit (strongly typed) in that the event change type was moved from parameter type to Listener method selector. Whereas with Observers we would have called:passing in an array of CallEv sub-types, with Listeners we make several calls to the CallListener, such asCallObserver.callChangedEvent(CallEv[] events)
CallListener.callActive(CallEvent event).
One of the restrictions of the Listener pattern is that we lose group event information. To counteract this, JTAPI 1.3 added "meta" events that are used to mark the start and end of batches of call events.
Unfortunately, in the 1.3 spec. the Listener pattern has only been applied to the core package, not sub-packages such as callcontrol (which we use). This leaves us with three different situations in the three JTAPI packages we support;
- In core, Observers are deprecated in favour of Listeners
- In callcontrol Observers are the only model
- In media (which underwent its own drastic change in 1.3) Listeners exist for the new MediaService and Observers for the old MediaTerminalConnection.
In early iterations of the Generic JTAPI Framework, we relied on the TelephonyProvider sending events off to one single RawObserver.update() method. From this point the Generic Framework:
- Placed the events in a queue to be handled by a separate thread (freeing the TelephonyProvider)
- Asked the event to attach itself to the Generic Framework objects.
- Asked the event to send itself to the appropriate Observers and / or Listeners.
The problem with this architecture was that it:
- Is very weakly typed. All selector and id information is encapsulated in a passed parameters. No compile-time checking for invalid types is performed.
- Imposes the JTAPI event set and, consequently, the JTAPI state machine, on the TelephonyProvider.
- Is complex to use:
- Determine the appropriate JTAPI event transition
- Create an instance of the appropriate event
- Populate the event with the right information
- Toss the event into an event queue
As well, the support for callcontrol events was not well mapped out.
Consequently, in version 0.6 of the framework, the callback mechanism was overhauled to replace the RawObserver with a TelephonyListener. This interface defines all the known object transitions that the Generic Framework is able to handle. Instead of "update(BaseEv ev)", the new interface is more strongly and explicitly typed in its method names and only requires basic types in its callback parameters. The telephony provider no longer has to build an appropriate event object and pass it to a generic "update" method.Examples of TelephonyListener method signatures include:
TelephonyListener.callActive(CallId call, int cause);TelephonyListener.connectionAlerting(CallId call, String addressName, int cause);TelephonyListener.terminalConnectionHeld(CallId call, String addressName, String terminalName, int cause);etc.
When the Generic Framework receives one of these messages it:
- The framework looks up or lazily creates the loosely referenced JTAPI object. Note: "drop" or "disconnect" are not lazily created but abandoned if they don't exist.
- The framework creates an appropriate runnable block and place it in a queue for subsequent processing, letting the TelephonyProvider continue
- The runnable block asks the object to change its state
- The object checks the state change for validity (invalid state change means a bug and may be logged or thrown in a RuntimeException).
- The object changes its state
- The object sends an appropriate JTAPI event off to its Observers and/or Listeners.
This provides for a much simpler handling of event notification in a TelephonyProvider. Now, instead of creating a complex JTAPI event and firing it off to a weakly typed method, the TelephonyProvider needs to just call the appropriate TelephonyListener method with a couple of identification parameters.
Note: Since the telephony provider is managed through a low-level (RISC-ish) interface, we do not always have information on the context of a particular state change event. For this reason MetaEvents are currently not well supported. The exception to the is the provision of MetaIds during the generation of "snapshot" events to reflect the current state of Framework JTAPI objects.
Despite the intention to further decouple the telephony provider from the JTAPI state machine, there is none-the-less a high correlation between the two event sets. Considering the shared telephony domain they both describe, this is not surprising. The differences between the two event sets are:
- Unknown is not provided
- ListenerEnded is not, of course, provided
- Connection created is not provided, but rather implied
- Address and Terminal, with no state, have no methods
- There are TelephonyListener callcontrolTerminalConnection listener methods even though this does not yet have Listeners, but only Observers.
- terminalConnectionActive() is replaced by more explicit callcontrol methods (Talking and Held)
- terminalConnectionPassive() (and it's subtypes Bridged and InUse) are not supported
For now, only the following events are supported under media:
Finally, the GenericFramework ensures that the telephony provider will only be provided with one TelephonyListener object handle. This simplifies telephony provider creation, since a collection of TelephonyListeners does not have to be maintained and TelephonyListener events do not have to be dispatched against such a collection.
- disconnected
- player pause and resume
- recorder pause and resume
- signal detector overflow, pattern matched and signal detected.
Listener Manager
The framework provides a ListenerManager class which is responsible for tracking the lifecycle of application-registered Observers and Listeners. This is necessary since the same observer/listener could potentially be associated with a call in various ways, and yet the JTAPI specification dictates that the observer/listener should be notified only once.In particular, observers/listeners can be associated with a call by that call visiting an Address or Terminal on which that observer/listener is registered as waiting for calls. These observers/listeners are only active on the call while it is at the Terminal or Address, unless they are explicitly registered against the call or are registered through another Address or Terminal as well.
The ListenerManager tracks each observer or Listener against a call with three pieces of information:
Directly added observers or listeners are only removed from a call explicitly or by the call's death. For other observers/listeners, though, the ListenerManager checks when they should be removed. Remember that the same listener/observer can be attached to the call in multiple ways. So, when a call leaves a Terminal, for instance, the ListenerManager will:
- The list of Addresses that caused the observer/listener to be added to the call.
- The list of Terminals that cause the observer/listener to be added to the call.
- A flag to note that the observer/listener was directly added to the call.
Thus, the ListenerManager manages the complex lifecyle requirements of JTAPI Observers and Listeners and isolates this behaviour away from the telephony provider.
- Look for the list of observer/listeners that were added to the call through that Terminal.
- For each such observer/listener:
- Ensure that it was not also directly added to the call
- Remove the Terminal from the list of adding Terminals
- Check if it should now be removed from the call (not explicitly added, no longer any Terminals or Addresses on the call that added the observer/listener)
Reporting
For a large system, reporting all call events would bog the JTAPI framework down with callback events, cause needless object creation and chew up possibly expensive monitor resources. Since most of these events may never be reported to an application, the Generic JTAPI framework allows for the "throttling" of telephony provider events if the TelephonyProvider indicates throttling support through the "getCapabilities()" return value of "Capabilities.THROTTLE = "t".Once a CallId is provided to the GenericFramework by the TelephonyProvider, the TelephonyProvider is contracted to continue providing state change events for this call or its components (Connections and TerminalConnections) until such time as the call dies or the Generic Framework turns off Call reporting through the sending of a "stopReportingCall(CallId call)" message. In addition to creating a Call and asking for all calls at an Address or Terminal, the Generic Framework may request future reporting of calls through:
The "report" parameter turns reporting on or off. Note that when reporting is first requested, the telephony provider should send "Snapshot" events up to the framework detailing the current state of a call and its connections and terminal connections.
- "reportCallsOnAddress(String address, boolean report)", indicating that the indicated address should have events reported on all calls associated with the address now or in the future.
- "reportCallsOnTerminal(String terminal, boolean report)", indicating that the indicated terminal should have events reported on all calls associated with the terminal now or in the future.
For some telephony providers, the extra complexity of event throttling is not justified, since they manage so few lines. In that case, the telephony provider can tell the framework that it will report all events, allowing the framework to not bother sending the "report" requests. See the Tuning section for more details.
TelephonyListener Threading
TelephonyListener "state" callbacks may cause problems for TelephonyProvider implimentations if in that they hand off control of a thread to an external entity (the Generic JTAPI Framework). For near real-time systems, like telephony systems, such external processing may cause problems.One option is to create a event handling pool in the Generic Framework that queues up event information for later processing and returns almost immediately to the TelephonyProvider. This solves the "callback" non-deterministic latency problem, but introduces its own. JTAPI specifies the post-conditions that the objects will be in at the completion of a method call. For instance, a transfer method does not return until the call has been transferred. This sort of synchronous paradigm is the most common usage paradigm in JTAPI, although it is sometimes broken, particularly in the media package.
The Generic JTAPI Framework sort-of obeys this paradigm. The "transfer" method does not return until the call has been transferred. That does not mean, however, that the raw TelephonyProvider has necessarily updated the Generic JTAPI object model yet, since we don't know how long the TelephonyListener processing queue is at any given time.
As an example, the Generic Framework is asked to connect a call to a remote number. It makes a "connect" call down to the plugged-in TelephonyProvider which connects the call, issuing the appropriate events back to the TelephonyListener, and then returns the "connect" method. A race condition now exists over whether the asynchronous state update events will actually update the object model before the Generic Framework tells the calling application that the connect has succeeded. If the update events lose, then there is a chance that the application may call another method (i.e. getConnections()) which will return unexpected results such as a "null" Connection set or "InvalidStateException" indicating that the call is IDLE.
Several options exist for ensuring that the command does not return until all of its generated asynchronous events have been processed, but they all have there own problems or complexities. In the end, it was decided to return TelephonyListener callback processing to "in-thread" and constrain the actions that the Generic Framework will perform to:
By limiting the processing of TelephonyProvider state events to these actions, we can provide some guarentee of timely return from an event callback while ensuring deterministic state machine changes in the Generic Framework. In particular, the callback does not directly create application-level JTAPI Listener or Observer events. These are delegated off to a client-dispatch thread for asynchronous processing.
- Creating any new required call domain objects
- Updating the state of one call object
7.5 Exception Management
Seven events may be thrown by sub-provider calls, one of which is a Runtime event:
| Primitive Call | InvalidArgumentException | InvalidpartyException | InvalidStateException | MethodNotSupportedException | PriveledgeViolationException | ResourceUnavailableException | PlatformException (Runtime) | MediaResourceException |
|---|---|---|---|---|---|---|---|---|
| Connect | X | X | X | X | X | X | x | |
| Answer | X | X | X | X | x | |||
| Hold | X | X | X | X | x | |||
| Unhold | X | X | X | X | x | |||
| Join | X | X | X | X | X | x | ||
| Release | X | X | X | X | x | |||
| (media)
play, record, sendSignals, retrieveSignals |
X |
We note:
- We have not listed initialization calls here. It throws a ProviderUnavailable exception
- PlatformException may be thrown by any method. Being a runtime exception, it indicates a dramatic unpredictable failure and should be handled at a top level.
- Four exceptions are always thrown in non-media commands.
- Only InvalidStateException takes a JTAPI object as part of its state.
- Media commands return a MediaResourceException, which wraps an instance of one of the JTAPI media event interfaces.
From this analysis, it was decided that the JTAPI exception set would be extended unchanged down to the TelephonyProvider, with the caveat that InvalidStateException is replaced by a RawStateException. This ensures that the sub-provider has the maximum exception throwing capabilities required.
RawStateException is actually a subclass of InvalidStateException that replaces the JTAPI object handle with the primitive reference types described earlier. In the Generic JTAPI Framework, this exception is caught and, much like the old event handling technique, passed a visitor that allows the primitive types to be mapped into the appropriate JTAPI object for an InvalidStateException exception.
The one problem with this design is that it implies that the sub-provider be able to map its state machine to the JTAPI state machine. An alternative is to assume that the JTAPI objects with catch invalid state problems themselves, but since their may be some race conditions between state event notification and application requests, this cannot be guaranteed. Proper creation of both exceptions and events dictates that similar state machines be used by all telephony-providers, so it may as well be the JTAPI state machines.
The situation for Media resources is somewhat simpler. The JTAPI media methods only define a single MediaResourceException, which simply wraps up one of the media events that describes the problem. The "Telephony Provider Interface" provides four media events for this purpose. As with RawStateExceptions, the framework must ensure that the wrapped event is properly hooked to the appropriate Generic JTAPI Framework media object before it is re-thrown to the calling client application.
7.6 Remote Support
Because the Generic JTAPI Framework is decoupled from the low-level TelephonyProviders, it is possible to interject a remote proxy layer between the two that allows them to optionally be distributed. This has the advantages over building distribution into the architecture in that:
- The cost of distribution (serialization, remote exception handling) is only incurred when it is needed.
- Different remote proxies can be built, providing different time/space/reliability/maintainability tradeoffs.
The current architecture supports the interjection of a remote proxy layer. Implementations, such as RMI, that support object and exception serialization can be easily built. Remote exceptions which indicate communication failure must be presented to the Generic JTAPI Layer in a meaningful way. The suggested architecture is to silently consume any event callback remote exceptions and to throw a JTAPI Runtime PlatformException for calls initiated from the Generic JTAPI Framework. This can be justified since usually once a remote exception occurs, the remote link is broken and it is impossible to easily recover.
7.6.B Multiplexor Support
One of the advantages of the pluggable architecture is that it decouples the components and allows them to be easily recombined in new configurations. On such configuration is to allow multiple low-level providers to be multiplexed together and appear as a single low-level provider to the Generic JTAPI Framework. This would allow for easy scaling of a system, as well as the combining of different low-level provider types into one logical JTAPI provider, say a Dialogic and a Linkon board on the same machine.The current architecture supports this by having all CallId and address names generated by the low-level provider. The multiplexor bridge catches this information and builds an association map. Note that this is the reason that the TelephonyProvider interface requires an address name for the reservation of a CallId; the address name is required to look up which low-level delegate to forward the reservation request to. When when the Generic JTAPI Framework wishes to perform an action, the action's parameters can be checked in the maps to determine which low-level provider to forward the command to. When the Generic JTAPI Framework releases a CallId, the multiplexor releases the CallId from the mapping table.Two problems arise with such a multiplexor:
- Multiplexed low-level providers should not have overlapping address or terminal name spaces (this is a logical restriction).
If a call is made from one low-level provider to a number that gets forwarded to another low-level provider (i.e. Through a 1-800 mapping table), the multiplexor may not be able to determine that the incoming call on the second low-level provider is the same logical call as the outgoing call on the first logical provider. Even if the address names can be matched up, the two low-level providers will be reporting different CallIds. It may be possible to detect this and create a wrapper id, but this will be difficult.7.7 Call Transfer/Conference
Transfer and Conference, while conceptually different, can really be implemented with very similar telephony actions. A transfer can be thought of as simply a conference from which the conference creator has been disconnected. Since JTAPI is a third-party call control API, it needs to know which party in a call is going to perform the transfer. Similarly with Conference, it is possible that two parties are already members of both calls and so it might not be clear which party should create the conference. JTAPI solves this with the concept of a Transfer and Conference Controller which may be assigned to a call.
Within the Generic JTAPI Framework, transfer is simply seen as the combination of joining a call and then dropping the join-creator party from the call. For unattended transfer, the join and drop are performed on a call that is still connecting.
The following table shows how the Generic JTAPI Framework maps JTAPI transfer and conference actions to the TelephonyProvider interface methods. It also notes what the usage status of the relative controller is.
| connect() | join() | release() | hold() | Controller | |
|---|---|---|---|---|---|
| Consult(TerminalConnection) |
|
||||
| Consult(digits) | X | X |
|
||
| Conference(Call) | X |
|
|||
| Transfer(Call) | X | X |
|
||
| Transfer(digits) | X | X | X | X |
|
Note that when the controller is optional, the Generic JTAPI Framework will try to assign a controller to the conference or transfer itself by looking for a Terminal that is part of both calls. The unattended transfer requires that the TransferController be set, since otherwise it has no idea which party on the call should perform the transfer (and therefore leave the call). At this time consulting a TerminalConnection (adding a new Connection to an active call) is not supported.7.8 Media Support
As of JTAPI 1.3, the JTAPI team changed their media architecture to more closely match the ECTF framework model. What is interesting about this is that in a way it now parallels the U|Builder. Essentially they have dropped (well, deprecated) the straight subclassing of JTAPI objects and moved to an architecture which defines:
- MediaService. This encapsulates a group of resources and can act on a call. The highlighted way this is presented is that a System Call Router (ACD, for instance) would detect a call type and forward it to a MediaService registered with a certain name. At this point, the MediaService would have its resources allocated and would wake-up to process the call. Variations include RunnableMediaService which can sit in a pool and be pulled out, configured and run. For our usage, we could create a MediaService that binds to a Call or MediaTerminal directly instead of being managed by some service framework (which JTAPI Media does not define). A well architected MediaService releases its resources when it loses control of a call, reducing the chance that an application can somehow inadvertently tie up resources.
- MediaGroup. This is a low-level holder of media access on a terminal that may be passed between different MediaServices. A MediaService can be subclassed to provide certain behaviour and pass on its held MediaGroup to another MediaService. In essence the MediaGroup acts as the resource holder that is separated from the "services" and may be passed between services.
- Resources. These are the basic media manipulators. Sub-interfaces include Player, Recorder, SignalGenerator and SignalDetector. Fax is promised in the future.
- MediaTerminal. This is a marker interface that denotes terminals that a Resource can interact with.
There are other things as well, such as RTCs (Run Time Controls), Symbols and Media Stream Containers that we will have to deal with.The biggest two problems with the current specification of the media package are:
- The 1.3 version of the Media service provides a reference "BasicMediaService" whose purpose it to act as a default and extendable media service manager. Unfortunately, in version 1.3 of the media specification, this is hard-coded as extending NullMediaService. The state intention is that applications can subclass this and use it. But with NullMediaService as a parent, it is inoperable. The documentation indicates that "actual implementations may extend some other vendor specific class", but this is poor way of providing a framework. Instead of implementing the API, we have to replace it. The JTAPI Provider and Peer take us 90% of the way there, allow us to plug in different implementations on the fly. Then suddenly we have to install on the classpath the right version of the base JTAPI classes support a particular board's media vendor. To support two different Media vendors would require that applications use tricks involving custom classloaders.
The Generic JTAPI Framework replaces BasicMediaService with GenericMediaService which has the same semantics and interfaces but is not a subclass of NullMediaService.
- RTCs and Symbols. The JTAPI Media Service follows the ECTF pattern of using immutable Symbol objects to send media "trigger" and "action" information to the media resources. But these are also not serializable, so the information cannot be easily sent to a remote media resource. This seems to be a by-product of earlier ECTF implementations of Symbol which left it as both a information holder and a type registry. We have contacted the ECTF and provided them with examples of serializable Symbol and RTC classes and they have indicated that this will be fixed in JTAPI 2.0.
In the meantime, the Generic JTAPI framework provides SymbolHolder and RTCHolder utility classes that allow for the serialization and recreation of Symbol information.
Design Options
The initial TPI media design set play, record, detect and generate methods against calls. The JTAPI Media, however, specifies Terminals as the access point (this is a change from 1.2 which used TerminalConnection). The implication is that whatever call is active on the terminal will be connected to the media sockets. One issue is how to handle MediaTerminals:
Unlike other JTAPI packages, media does not use capabilities to determine what is and is not supported. With JTAPI media, a contract paradigm is applied. If a Terminal implements MediaTerminal and the media resources can be acquired (subject, of course, to resource availability) then all media capabilities are guaranteed to be available. During initialization the framework queries the telephony provider using the "isMediaTerminal()" query method that determines if a given terminal name identifies a media terminal. This is used during the initialization of the framework to dynamically determine if an instance of FreeTerminal or FreeMediaTerminal needs to be instantiated for a particular known and managed terminal name. Under "Capabilities", we will discuss the algorithm used to determine media capabilities on Terminals.
Terminals which implement the "MediaTerminal" marker interface by contract support media and all media resources.
Once a Terminal is identified that supports media services, it can be bound to a MediaService. Within the Framework this binding results in the MediaService sending a command to the telephony provider to allocate low-level media resources to that terminal name. The bound resources are low-level equivalents to the logical resources grouped together in the MediaService. When the MediaService is unbound from a terminal, the telephony provider is told to de-allocate the associated low-level media resources.
Currently the four media resources that may be supported are:
Player. For playing a set of audio streams into the active call associated with the MediaTerminal. The audio streams are passed not by data but by an abstract stream id. For the purposed of the Generic JTAPI architecture, these ids will either be file names or URL strings.
Recorder. For recording the audio on the active call at the associated MediaTerminal. The audio is recorded to the file or URL referenced by a passed stream id.
SignalDetector. This is a DTMF receiver that collects all DTMF signals into a buffer and then can be polled for the collected signals. Note that signal detection is not turned off and on. To collect signals from only a certain point in time, the buffer must first be emptied.
SignalGenerator. This causes a series of DTMF signals to be played on the call that is active at the MediaTerminal. While in JTAPI this can be called with either a String or a set of Symbols, the current architecture will coalesce both of these into a single TelephonyProvider calls that delivers a set of Symbols to the low-level DTMF generator.
In addition to the initialization query method, two allocation methods and the four implied methods above, the TelephonyProvider also supports the MediaService stop() method, which basically broadcasts a "stop any current actions" command to all low-level media resources allocation to the terminal.
Within the basic media calls are some other more complex concepts. One is the support for a dictionary of optional service parameters. This may be confusing, since both UserDictionary and Parameters dictionaries are supported. The documentation for 1.3 Media is not very clear in this matter, but careful reading reveals that the UserDictionary is a way for an application object using a MediaService to associate application information with a MediaService's bound MediaGroup. The Media package allows a MediaGroup to be passed between various MediaServices. So, for instance, an application may create several "beans" for handling calls and tag call infomation (User's account number and priority) into a MediaGroup's UserDictionary. As the MediaGroup is passed from one Media Service (menu) to another (record audio) this information can be passed along. It is not used my the low-level media but by the controlling application-level "beans".Parameters, on the other hand, are basically resource configuration holders that the ECTF architects did not want to place into strongly typed initialization parameters or classes, probably in order to reduce interface complexity and provide maximum flexibility. Generally the keys and values in the Parameters dictionary are "p_" and "ev_" named Symbols. The problem with this design is that while there is an agreed "Ontology" specifying the meaning of name-value pairs in the optional parameter dictionary (Defined in various SymbolConstant classes), the name-space is relatively large, making it either very difficult to support all parameters or hard to indicate which are supported. None-the-less, the current Generic JTAPI Framework architecture does allow for these parameter holders to be passed on to the low-level resources. Examples of a possible Parameters entries that may be set for a MediaService include:
p_EnabledEvents -> ev_SignalDetected This indicates that the SignalDetector should send events for each detected signal, on top of any collection in the SignalBuffer.
Finally, the ECTF Media architecture defines Runtime Controls. These are symbol pairs that define how a media resource will respond when certain events occur. The alternative to such a capability is to have the MediaResource listening for events and then sending response commands back to the low-level media resource. The problem with this more traditional approach is one of timing, latency and user perception. If, for instance, a user is using an IVR system that offers a menu of options, the user expects the option menu to stop playing when they select an option (push a button). If the option menu continues to play, the user may believe that their command was not received and push the button again. Then the application catches up and sees multiple received signals and places the user into an unexpected sub-state.
To support Runtime Commands, the TelephonyProvider interface allows RTCs to be passed down to a low-level media resource. It also supports the JTAPI media capability to trigger RTCs in resources by sending "pseudo-events" to the low-level resources through the "triggerRTC()" method. An example of this might be the sending of the Symbol "PlayerConstants.rtca_Stop" to tell the media implementation to stop playing any current output stream. Again, the possible "rtca_" action Symbol space is very large, leading to difficulties in providing consistent or full implementations.MediaGroup Handoff
Basically, ECTF defines a MediaService as a manager of a collection of media resources (a MediaGroup). A MediaService may be written that uses this MediaGroup to play recordings and listen for DTMF, for instance. MediaServices may manually be bound to calls or they may register with a "manager" for calls with a certain profile. When they are done with a call, they can either release it totally or tag it and send it into the pool to be managed by another MediaService. Furthermore, the MediaGroup travels with the call and holds onto call information which can be accessed by each MediaService as it gets control of the call, using the UserDictionary. This functionality has built into the Generic JTAPI Framework.So, for instance, the following is currently possible:
This has been implemented in the Generic JTAPI framework using dictionaries of:
- An application starts up and creates a bunch of MediaService instances and registers them with the media manager for certain types of calls (initial, authentication, email play, stock reporting, ...).
- The application creates a pool of initial MediaServices.
- The application registers Terminal listeners for each incoming line.
- When a call arrives on a Terminal, the application's listener callback function binds the call to an "initial" MediaService from the pool.
- The MediaService plays an initial greeting and looks at the incoming caller id.
- The MediaService then releases it to the appropriately registered service (i.e. authentication).
- The manager finds an idle authentication MediaService and hands the initial MediaService's MediaGroup off to this waiting MediaService.
- The manager starts the authentication MediaService.
- The initial MediaService may now be returned to the pool.
- terminal to MediaService bindings, so we can route low-level media events to the right MediaService
- MediaService to waiting service name, so MediaServices can sit waiting for a request for one of them by a certain name.
- MediaGroup to waiting name. This is for calls that are being handed off but do not yet have a destination MediaService. They sit in this queue for X milliseconds to see if a new MediaService will get dropped back into the manager ready to handle them. If no MediaService shows up, eventually the "bindToServiceName()" call from whence they came will return with a MediaBindException.
7.9 Deprecated 1.2 Media Support
Prior to JTAPI 1.3 media was supported through a more orthodox JTAPI architecture of subclassing one of the basic JTAPI interfaces and adding new methods to it. In the case of the 1.2 media support, the subclassed interface was a TerminalConnection. To implement 1.2 media, then, the JTAPI implementation must add "javax.telephony.media.MediaTerminalConnection" to the set of interfaces implemented by the TerminalConnection class.In order to support the older media interfaces, an attempt was made to map the same functionality onto the 1.3 media paradigm. This allows both the old and new media interfaces to be exposed to the application layer while not adding new and duplicate media control methods to the TelephonyProvider interface that would increase the complexity of building a media-capable telephony provider. Unfortunately, there are some "paradigm" differences between the two media packages that had to be examined and dealt with.
Resource Allocation
Problem
With the 1.3 media classes, MediaServices hold MediaGroups which are in turn bound to a MediaTerminal. Resources can be added to a MediaGroup (Player, Recorder, etc.). Depending on the low-level details, there may be some real cost to associating these resources with a telephony channel (e.g. tying up a DSP). To support this, the TelephonyProvider interface provides a set of methods that are called from a MediaGroup when its resource set changes:boolean allocateMedia(String terminal, int type, Dictionary resourceArgs);boolean freeMedia(String terminal, int type);
The JTAPI 1.2 media's MediaTerminalConnection does not expose the concept of resources tied to a TerminalConnection. So for instance, we may write:if (tc instanceof MediaTerminalConnection)So, how does the Framework tell theTelephony Provider to allocate a signal generator for the terminal?
((MediaTerminalConnection)tc).generateDTMF("2315112");
Options
The options seem to be:
- Always allocate all resources to a media terminal during its life cycle. This could get very expensive and result in ResourceUnavailableExceptions that are unnecessary.
- Allocate and de-allocate specific resources around each call. This may slow things down during a series of media actions on a TerminalConnection. We should probably also track other allocation and free commands to make sure we don't free resources a concurrent thread or MediaGroup is using.
- Variation on number 2: Provide a X-second garbage collection period to allocated resources. This could either mean that resource freeing is delayed by X seconds to speed up subsequent allocations, or it could be true Resource garbage collection, with an idle resource freed after some timeout X.
Solution
The third option was implemented in an effort to minimize unnecessary resource allocation and resource allocation thrashing. This does add to the complexity of the Generic JTAPI Framework, but this cost is shared among all telephony providers and fits with the framework's goals of centralizing complexity in the Framework.When a MediaTerminalProvider is asked to perform a media service it lazily creates or accesses an associated pseudo media service. This pseudo service then allocates the necessary resources and starts the media command. When the command ends, it checks if it is the only media call currently active. If it is, it puts itself into a "FREEING" state and starts a garbage collection thread to wait a few seconds and see if it can still be freed. If another media command is issued while in the "FREEING" state, the state is changed back to "ALLOCATED" so that the garbage collector will not try to free the media resources when it wakes back up.
Problem
JTAPI 1.3 media, and consequently the TelephonyProvider interface, define media playing and recording as synchronous methods that do not return until the playing or recording is complete (including stopped by some event or RTC action).JTAPI 1.2 media, however, defines asynchronous "start" and "stop" pairs for controlling media stream handling. This means that once a MediaTerminalConnection is issued the "startPlaying()" method, it returns immediately. How do we map this to synchronous calls.
Options
The options here are not numerous. Basically we could:
- Alter the TelephonyProvider interface to add new asynchronous play/record commands or flags.
- Change the TelephonyProvider interface semantics to an asynchronous call. This would force the 1.3 media classes to pause its thread until a complete event was received. Worse, it would expose more of the deprecated paradigm to the telephony provider implementor and put the complexity with the new implementation instead of the deprecated implementation.
- Have the 1.2 media classes perform the synchronous media calls in a separate thread so that the command can return immediately.
Solution
The third option was chosen since it isolates the complexity with the deprecated classes and does not change the media paradigm in the telephony Provider interface. The "pseudo media service" can lazily allocate player and recorder threads that take care of the synchronous media call and allow the MediaTerminalConnection's "startPlaying()" and "startRecording()" to return asynchronously."stopPlaying()" and "stopRecording()" are implemented by sending the "PlayerConstants.rtca_Stop" and "RecorderConstants.rtca_Stop" Signals to the telephony media provider.
Consequences
- For a telephony provider to properly support 1.2 media it must properly implement "triggerRTC()" to receive and act on "PlayerConstants.rtca_Stop" and "RecorderConstants.rtca_Stop" Symbols.
Problem
Similar to the asynchronous playing and recording problem, JTAPI 1.2 media asynchronously starts digit collection whereas the 1.3 media call "retrieveSignals()" is synchronous in that it returns with the digits. In this case, there is also an asynchronous method for getting signals under JTAPI 1.3: sending a Parameter to the media device that associates the Symbol key "p_EnabledEvents" with the value Symbol "ev_SignalDetected".Options
Again, we could:
- Redefine the TelephonyProvider interface to add new retrieval methods
- Change the current TelephonyProvider signal retrieval method to act asynchronously.
- Map the 1.2 signal retrieval methods to Parameters entries and update the telephony provider's media Parameters for a terminal.
Solution
The third choice was the obvious one. The telephony provider may be signalled with Parameter set changes through theThis allows us to update a set of Parameters associated with a low-level media resource. When the event is received by the Generic Framework, it must be caught by the pseudo media service associated with the MediaTerminalConnection and turned into a deprecated 1.2 media Observer event.allocateMedia(String terminal, int resources, Dictionary parameters);Consequences
- "allocateMedia()" must not only allow the allocation of new resources, but also the updating of those resources parameter sets.
- A media telephony provider must implement the "p_EnabledEvents" -> "ev_SignalDetected" entry as turning on Signal event reporting through media events.
- Tuning should not turn off media allocation if it is required for the updating of a Parameter set. (See the Tuning section)
None-the-less, Fax support in media applications will be needed by certain applications before the ECTF or the Java Community Process gets around to correcting this deficiency. After analysing the issue, it becomes apparent that there are four options:
The "play" and "record" methods would define fax requests as those where the "streamId"contained stringified URLs with the protocol of:
fax://
PlayerEvent pe = myMediaService.play("fax://http://localhost/docs/12356.jpg", 0, null, null);
JTAPI provides, and the Generic JTAPI Framework supports, five capability concepts:
Packages. The framework provides support for the "core" JTAPI classes, as well as parts of callcontrol (hold, transfer, conference, release), and media. If a JTAPI object implements an interface from a package, it may implement some of that packages functionality. So, for instance, to initiate hold on a call we may perform (assuming "tc" is a TerminalConnection):if (tc instanceof CallControlTerminalConnection) { CallControlTerminalConnection cctc = (CallControlTerminalConnection)tc; try { cctc.hold(); } catch (MethodNotSupportedException mnse) { // whatever } ... // other exceptions... }
MethodNotSupportedException. Most JTAPI calls allow an implementation to opt out of supporting a method by throwing this exception. See the above example. Usually Static capabilities should define which methods will throw this exception.Static capabilities. These are provided for core and callcontrol JTAPI classes. They define which methods are actually implemented.
Dynamic capabilities. These are provided for core and callcontrol JTAPI objects. They combine Static Framework capabilities with instance state information to define what is currently available for a particular object.
Contracts. The new 1.3 media API attempts to move from a capability-based model to a contract-based model. If a Terminal is an instance of MediaTerminal, all media calls should be available to a MediaService attached to it. Of course, reality dictates that the system have some way of throwing an exception indicating that a resource is not available.
The static Capabilities classes for the Generic JTAPI objects are initialized through reading a GenericCapabilities.props properties file. Instead of listing all JTAPI method capabilities, this property file simply lists which TelephonyProvider call control methods (answer, create, hold, join, release) are supported by default. From these five capabilities, the system capabilities are all calculated.
Note that since transfer and conference are built upon the more basic functions, their capabilities are calculated from the function availability:
| Mapping | answer | create | hold
(and unHold) |
join | release |
|---|---|---|---|---|---|
| Consult(digits) | X | X | |||
| Transfer(call) | X | X | |||
| Transfer(digits) | X | X | X | X |
To read this chart, we note that an unattended transfer requires the following actions: place existing call on hold, create a new call, join the calls together, release the transfer controller from the call. When a TelephonyProvider is allocated, it is asked for its set of overriding capabilities, based on the same set of five function groups. It is up to the TelephonyProvider to decide if its capabilities are hard-wired or are themselves loaded from a Properties file.Dynamic Capabilities for a particular instance are calculated using the instance's state and the static capabilities for that class. For instance, if a Call object is asked for its dynamic capabilities, it will first create a clone of the static CallCapabilities object. Then the state of the call is used to further restrict the capabilities. For instance, if the call is in IDLE state, its "conference" capability will be turned off, even if the static capabilities for Call allow conferencing.
For the Generic JTAPI Framework media is supported by providing a telephony provider query method that determines if a given terminal name identifies a media terminal. This is used during the initialization of the framework to dynamically determine if an instance of FreeTerminal or FreeMediaTerminal needs to be instantiated for a particular known and managed terminal name.7.12 Extended JTAPI package support
Currently the Generic JTAPI Framework and sub-providers are intended to only support core, specified call control and some media services. At present, the architecture is not designed to provide for extensibility to all JTAPI packages. The Generic JTAPI Framework was originally architected to provide a trade-off between feature-support and simplicity. This is a common tension in application development, and more so in Framework development, between the desire to provide a rich set of features with as little complexity as possible. The Framework acts as a bridge between the complex JTAPI API and a simpler TPI that allows telephony boards or IP protocols to be piped into the bottom. The framework takes care of threading, distribution, event publishing and other complex but reusable issues and only requires TPI implementations to implement a relatively small interface.Keeping the TPI manageable for implementors was accomplished, in part, by mapping as many functions as possible into a few simpler components (akin to RISC in hardware design). For instance a transfer is mapped to (hold, make-call, join, drop). The other half of the simplification equation was accomplished by deciding to only implement a subset of functionality. See the Use Cases for a listing of supported functionality.
So, what happens when someone wants to add offhook support to CallControlCall? There is no method in TelephonyProvider that allows this information to be passed to the telephony implementation. And every time we add a new method to TelephonyProvider, we break all existing TelephonyProvider implementations. This may be fine while the implementations are all in-house, but as the number grow and the Generic JTAPI framework starts to be used, we have a serious version issue.
The problem isn't constrained to version control on the TelephonyProvider interface, either. There is also the problem of interface bloat and JTAPI implementation typing.
To review, JTAPI provides hint as to what is implemented in three ways:
How, then, are we to implement this is the Generic JTAPI framework. There are, for instance, several sub-interfaces to Terminal -- AgentTerminal, CallControlTerminal, MediaTerminal, MobileTerminal, PhoneTerminal. Do we have to create all possible permutations of these and then have them delegate off to package controllers as appropriate?
- Interface inheritance. An application can see if a Call has CallControl support by checking if it implements the CallControlCall interface (i.e. call instanceof CallControlCall).
- Capabilities. An application can ask for the capabilities of the system and use these object to determine what is available. For instance if an application asks the Provider for the CallCapabilities and casts these to CallControlCallCapabilities, it can then send the Capabilities object the message "canOffHook()", which returns false. (There are also dynamic capabilities that factor in the current state of the object, but that is slightly different).
- MethodNotSupported exception. Just because the Call implementation implements CallControlCall doesn't mean it provides all CallControlCall methods. It is permissible to implement most JTAPI interface methods by simply throwing the MethodNotSupportedException. This should be accompanied by the appropriate Capabilities entry.
Goals
- Allows new functionality to be added to the Generic JTAPI Framework without breaking existing TelephonyProvider implementations.
- Gives reasonable JTAPI implementation information.
- Allows a TelephonyProvider to implement a set of functionalities and report which exist to the framework.
- Defines "functional set" dependencies. An extension that supports callcenter may require functionality only available if callcontrol is also supported. There is no sense in a telephony provider implementing an extension function set that can't be used since another required functional set is not provided.
- Attempt to, as much as possible, leave the current TPI API alone.
Options
The major problem with the second architecture is that it hard-codes the extension functionality into a telephony-provider implementation. For a proxy implementation, such as a remote proxy, this static capability determination will not work since we need to reflectively determine the real sub-provider's capabilities.
- The current TPI provides an initialization call "public Properties getCapabilities()" that allows a TPI to return a dictionary of values that defines its operation. Currently these consist of:
We could add to this:
- Base capabilities (i.e. "answer = t" indicates that the TPI allows calls to be answered. This is more for creating actual capabilities than changing the framework's behaviour, but it does indicate that the TerminalConnection.answer() method will probably return MethodNotSupported from the TelephonyProvider implementation).
- Implementation tuning (i.e. "media = f" indicates that the TPI does not support media. Terminals that are returned from the system will thus be of type FreeTerminal instead of FreeMediaTerminal.) This also allows TPI calls that are NOPs to not be sent (i.e. "allMediaTerminals = t" for an TPI that supports media means that we don't have to ask the TPI is a particular terminal should be a FreeMediaTerminal).
What would be a appropriate value?
- ExtensionPackage naming. The key namespace beginning with "Extension" is reserved. This is used to map an extension name to a value of some sort.
- The obvious one is passing a class name. So for instance, if the JTAPI Framework adds a new extension package called "CallCenter", an TPI that chooses to implement TlephonyCallCenter would return, for instance, com.foo.EmCallCenter. So, for instance, the capabilities Properties dictionary may contain "Extension_CallCenter -> com.foo.EmCallCenter". The problem with this is that the framework is than going to have to instantiate this without hooking it into the rest of the telephony provider implementation.
- We could ignore the value and use the existence of the key to indicate that the TelephonyProvider also implements TelephonyCallCenter.
- Return a method name that can be called on the TelephonyProvider implementation class using reflection to get the appropriate class handle. So, if "Extension_CallCenter" points to "getCallCenter", the framework could use reflection to call the method "getCallCenter()" on the telephony provider and return a handle on a new object that implemented the new telephony call control interface.
- As an alternative to Using the capabilities, why not just inspect the current TelephonyProvider implementation for known sub-interfaces? Two options are:
- Define a method that can be called using reflection on the TelephonyProvider instance to get the extension provider.
- Just inspect the instance with "instanceof". So we would issue:
if (raw instanceof TelephonyCallCenter) { callCenterRaw = (TelephonyCallCenter)raw; }- Provide one new method that is an interface lookup method. This could be in the TelephonyProvider interface or a sub-interface. If it was in the sub-interface "ExtTelephonyProvider", we could get a low-level "callcontrol" interface by doing:
<FreeCall.java> ... public CallCenterTrunks[] getTrunks() { TelephonyProvider raw = this.getProv().getRaw(); if (raw instanceof ExtTelephonyProvider) { // test if we have a dispatch interface Object o = ((ExtTelephonyProvider)raw).getExtension("CallCenter"); if (o != null && o instanceof CCTelephonyProvider) { // test if interface found String[] trunkNames = ((CCTelephonyProvider)o).getTrunks(this.getCallId()); // ask CC TelephonyProvider for trunks ... // munge into CallCenterTrunk array and return } } }Give the remaining two options, the last seems preferable since it is conceptually simpler, easy to implement and does not yet again overload the "capabilities" Properties object. Note that at this time, an extension mechanism has not yet been implemented.
Example
Say we have the Generic JTAPI being used and with existing TelephonyProviders and we decide to add CallCenter to it. These are the steps, with players:Alternatively, the telephony implementation could return another object that implements the telephony interface requested.
- <Framework>Define a new TelephonyProvider interface, such as "CCTelephonyProvider".
- <Framework>Update the Generic JTAPI Framework to make FreeCall also implement CallCenterCall. Likewise we update the Capabilities classes and the Capabilities default properties file.
- <Framework>Publish the new low-level Telephony interface, any new Capabilities Properties entries which may optionally be added, and the "lookup" name (CCTelephonyInterface.LOOKUP_NAME = "CallCenter").
- <Telephony Implementor>Decide if we wish to implement it. If we do...
- <Telephony Implementor>Extend our TelephonyProvider implementation class to also implement the required interface.
- <Telephony Implementor>Have "getExtension()" return "this" if "CCTelephonyInterface.LOOKUP_NAME" is passed as the parameter.
7.13 Telephony Provider Tuning
The framework is loosely coupled from the telephony providers that provide it with its telephony functions and do not have hard-coded interior knowledge of the workings of these telephony providers. For this reason, the framework must take a conservative approach to system management. For instance, the framework will explicitly request allocation of media resources whenever it thinks these are required. For many telephony providers, however, media resources may essentially be free. In that case, the extra messaging cost, particularly if a remote proxy provider is used, is a needless waste of processing cycles (and bandwidth). For this reason, the framework provides, through the "capabilities" Property object passed back from "getCapabilites()", the ability to tune the framework.The four "tuning parameters that may be set are:
Key Default Value Description throttle t This indicates to the framework that the telephony provider does not by default send events for all calls.  If 't' is set, the framework will notify the telephony provider of all event requests through the "reportCall()", "reportCallsOnAddress()" and "reportCallsOnTerminal()" TelephonyProvider methods.
media t See Section 7.15 Weak Synchronzation This indicates whether the telephony provider supports media. If it does not, the framework will not bother querying "isMediaTerminal()" when determining which class to create a new Terminal instance from, since it knows that this method will always return false.
allMediaTerminals f If a telephony provider does support media, turning this value to "t" will indicate to the framework that all terminals support media and so it does not need to call "isMediaTerminal()" when determining which class to create a new Terminal instance from, since it knows that this method will always return true. allocateMedia t Some telephony providers may have very cheap media resources, in which case it is more efficient to always have them allocated to each terminal rather than receiving a series of allocation and free calls. If this value is set to "f", the framework will not bother sending "allocateMedia()" and "freeMedia()" methods to the telephony provider, unless the "allocateMedia()" method is being used to update the media Parameters dictionary.
dynamicAddresses f See Section 7.14 If this is "t", then the Address and Terminal sets associated with the JTAPI domain are not static.
7.14 Dynamic Domain
JTAPI assumes that the Address and Terminal set for a domain remain static over the life of the application. For some systems, particularily in the VOIP space, this is overly restrictive.The Generic JTAPI Framework allows TelephonyProviders to signal through their "getCapabilities()" return Properties that their Address and Terminal spaces are not static. See section 7.13 Tuning. If this is set to True or "t", then the Framework will allow applications to query for Addresses or Terminals that were not reported in any earlier "getAddresses()" or "getTerminals()" call. This query is passed onto the TelephonyProvider to see if the Address or Terminal now exists.
Since JTAPI does not support the concept of Listener events reporting new Address or Terminal availability, the Framework does not support such a concept.
7.15 Weak Synchronization
Problem
The Generic JTAPI Framework without throttling assumes that the TelephonyProvider will report all state information on all calls (and Connections and TerminalConnections) in its domain. This may cause problems for some Telephony implementations. In particular, some implementations may manage a large domain with a great deal of activity. Collecting and reporting state changes for all domain objects may, therefore, become prohibitively expensive due to:
- Implementation monitoring costs. Some platforms may have significant costs associated with monitoring line or channel behaviour. Invoking this cost in order to retrieve information that may never be used may not be pratical.
- Memory size. If thousands of Calls must be maintained in memory with associated state, Connection and TerminalConnection information, the JVM memory requirements may get very significant.
- Processing. Receiving and thousands of call events per second may strain the JVM implementations and lead to poor performance of unacceptable command latency.
- Network cost. If a TelephonyProvider proxy exists between the telephony platform and the Generic JTAPI server, then all state update events must be serialized across the network pipe. This may add significant network load, including increased collisions, and may cause latency and responsiveness degradation.
Options
We are, therefore, left with two options: limit the intended domain of the Generic JTAPI Framework to small and medium-sized systems with moderate activity levels; or provide a lazy state synchronization mechanism.Goals
Primary goals of a lazy state synchronization architecture include:We should analyze the weak reference access scenarios to establish what sort of caching, if any, we will require.
- Delay reporting of Call information until the Generic Framework has requested it.
- Allow Address#getConnections() and Terminal#getTerminalConnections() to lazily fetch their call association information.
- Provide soft caches to enable Call information to be cached but reclaimed by the garbage collector when memory becomes tighted.
- Allow for the building of static TelephonyProviders that do not need to worry about lazy object requests.
Note that we do not require that the framework analyze dynamic access patterns in order to change the caching mechanisms of the fly (as HotSpot does with JVMs to optimize calls that are frequently being called).
Similar Problems
The problem of maintaining an object-hierarchy that is not fully in-memory is reminiscent of the techniques that are used in Object-Oriented databases to allow for the flushing in of objects from a persistent store. Usually such systems allow for a tree of objects to be "trimmed" such that only a certain depth of the tree is returned and the rest of the tree is replaced with a placeholder that allows for later flushing out if that part of the tree is traversed. The cost trade-off here is between memory usage and initial "fetch" expense versus latter traversal lazy fetching.Analysis
First, we should look at the JTAPI architecture that must be managed. The following diagram presents the relationship between the Provider and it's Addresses, Terminals and Calls (Connections being associations between Addresses and Calls and TerminalConnections being the association between Connections and Terminals.
Figure 1: Basic Generic JTAPI class diagram From the JTAPI specification, we can see that the following are the access methods:
We note that we basically have two sets of dynamically loadable information:
Accessor Accessed Method Type Provider Address getAddresses() throws ResourceUnavailableExceptiongetAddress(String name)Domain Provider Terminal getTerminals() throws ResourceUnavailableExceptiongetTermnal(String name)Domain Provider Call getCalls() throws ResourceUnavailableExceptionCall Address Connection getConnections()Call Address Terminal getTerminals()Domain Terminal TerminalConnection getTerminalConnections()Call Terminal Address getAddresses() Domain The following diagram shows these two sets as blocks within the object domain.Domain (Address <-> Terminal)
These are the sets of Addresses and Terminals that make up the provider's domain. An application may ask for all the Addresses or Terminals, or look them up by name. As well, Each Address may have a number of Terminals associated with it and each Terminal will have one or more Addresses associated with it. These are static to the domain.Call
This is transient information about current call activity. Each Address may have any number of Connections associated with it (which are basically Address to Call association objects). Similarily a Terminal my have zero or more TerminalConnections associated with it.Figure 2: Object Groupings and Accessors We would like to keep these two dynamic sets separate. So, for instance, one TelephonyProvider implementation may be able to give a purely static set of Addresses and Terminals which is of a manageable size, but may not want to automatically incur the cost of reporting all call events on these sets.
Thus we see that we have two dynamic "fetching" scenarios:
From Figure 2 we can also note some other things of importance:
- Domain Object Interrogation. Here the Provider is asked for its set of Addresses or Terminals, or for an Address or Terminal by name. In the above diagram, the FreeAddress and FreeTerminal classes are requested. The API allows the implementation to return "ResourceUnavailableException" to the set accessors but not the name-lookups. It would make sense to have a Provider that allows "DynamicDomain" to throw the ResourceUnavailableException and then allow lazy look-ups of individual Terminals and Addresses.
- Call Interrogation. Here the Provider asks for the set of all Calls or the Address or Terminal asks for its set of associated calls (through the Connection or TerminalConnection association objects). Here the bottom three classes, FeeCall, FreeConnection and FreeTerminalConnection, are requested. The API allos the implementation to return "ResourceUnavailableException" to the global call set accessor, but not the Address or Terminal call set accessors.
- Terminals and Addresses may be looked up by name or by association with each other and are also referenced by any active calls that are associated with them. Therefore it is not sufficient to refetch an Address or Terminal each time it is looked up, since this may corrupt object identity if there is already another copy of this object in the system.
- Note that Addresses and Terminals are related, with a Terminal knowing all the Addresses on it, and an Address knowing all Terminals that contain it. There are two possibilities for paging in the cross references between Addresses and Terminals:
- Assume that the Terminal-Address graph is not too large. When an Address name is returned from the TelephonyProvider that is not currently cached in our system, we perform a recursive search until all newly reachable Addresses and Terminals have been returned.
- Don't assume that the Address - Terminal sub-graphs are of moderate size since this may not be a valid assumption. Say an Address is available on every one of 400 Terminals in a call centre sub-department. Furthermore, some of these Terminals also hold Addresses on other distant Address groups. Theoretically there is no reason that doing a full graph flush may not result in a large number of TelephonyProvider calls and the flushing out of information on every Address and Terminal in the domain, if they are all reachable. Instead we should, for Address, track all of its Terminal names and only use these names to look up Terminals when the name is traversed. Delaying the graph traversal until first needed may add some initial lookup time, but will reduce Address lookup, memory requirements and TelephonyProvider invocations.
- Calls and their Connections and TerminalConnections cannot expand without bound across the whole TelephonyProvider's Call domain, unless there is only one call currently active. Active calls tend to have a limited number of Connections associated with them.
Weak Synchronization Architecture
Paradigm
The Generic JTAPI Framework will maintain both Domain and Call information either statically (by default) or dynamically, based on TelephonyProvider Capabilities. If looked up dynamically, the reference will be "softly" or "weakly" held in a reference cache so that the reference may be cleared once no longer directly accessed by a strong link. Strong links may include Listeners (since if a listener is registered on a Call, we want to to get it's state updates and keep the call in memory), application code, or other directly held dynamic objects (An Address referenced by a Call that is held by an application).Class Diagram
Figure 3: Basic Object partitionReference Determination
The following table indicates two things:The TelephonyCapabilities property that triggers the use of dynamic lookup and weak caching The type of cache used. SoftCaches release softly-reachable items before a MemoryOutOfError exception is thrown. WeakCaches release weakly-reachable items during the next garbage collection.
Accessors Dynamic trigger Cache Style when dynamic Domain Provider->AddressProvider->TerminalResourceUnavailableException during initialization SoftCache
(These are domain objects and are likely to be looked up again once initially active) Address->TerminalTerminal->AddressSoftCache Call Address->ConnectionTerminal->TerminalConnectionthrottle = t WeakCache
(These are transient domain objects that are not as likely to be accessed in the future)Shadow References
In order to reduce the coupling between object, particularily those that are not used together frewuently, we need to provide a way of creating weak or shadow references that do not keep objects from being garbage collected but do allow for objects to be refetched (paged, lazily fetched) from the TelephonyProvider when needed.Here are the references between objects and notes on how the references are flushed out when needed:
Reference Holder
(Source)Target Reference Type Flushing Notes Address Terminal String Asks the DomainMgr for the Terminal with the given String name. If the DomainMgr has let the Terminal be garbage collected, it recreates it. These are the Terminals associated with an Address. This information is queried from the TelephonyProvider through "getTerminals(String address)" Terminal Address String Asks the DomainMgr for the Address with the given String name. If the DomainMgr has let the Address be garbage collected, it recreates it. These are the Addresses associated with a Terminal. This information is queried from the TelephonyProvider through "getAddresss(String terminal)" Address Connection ConnectionHolder The ConnectionHolder has a weak handle to the Connection as well as storing the CallId and Address name so that the CallMgr can be asked to refetch the Connection from the TelephonyProvider if needed. Instead of an Address holding onto all the Connections on the Address, it holds a collection of ConnectionHolders that act as smart weak references to the Connection. Terminal TerminalConnection TermConnHolder The TermConnHolder has a weak handle to the TerminalConnection as well as storing the CallId, Address name and Terminal name so that the CallMgr can be asked to refetch the TerminalConnection from the TelephonyProvider if needed. Instead of an Terminal holding onto all the TerminalConnections on the Terminal, it holds a collection of TermConnHolders that act as smart weak references to the TerminalConnection. Connection Address String Asks the DomainMgr for the Address with the given String name. If the DomainMgr has let the Address be garbage collected, it recreates it. This is the Address that identifies this particular leg of a call. TerminalConnection Terminal String Asks the DomainMgr for the Terminal with the given String name. If the DomainMgr has let the Terminal be garbage collected, it recreates it. This is the Terminal that identifies this particular TerminalConnection part of a Connection. Note that whereas Addresses and Calls are decoupled from each other, Call components (Call -> Connection -> TerminalConnection) are tightly coupled since a call isusually a relatively small set of related objects that are highly dependend on each other.
Manager Class Diagram
The following diagram outlines the new manager objects that make up the core of the Generic JTAPI Architecture.
Manager CRC Cards
These are the simple Class-Responsibility-Collaborator cards for the major "manager" objects at the core of the Generic JTAPI Framework:
GenericProvider Responsibility Collaborator Act as JTAPI Provider Hold CallMgr CallMgr Hold DomainMgr DomainMgr Delegate Provider messages off TelephonyProvider Create a TelephonyProvider state callback handler RawEventHandler
CallMgr Responsibility Collaborator Hold weak cache of Calls Fault or page Call in when requested TelephonyProvider
DomainMgr Responsibility Collaborator Hold soft cache of Addresses Hold soft cache of Terminals Fault in Address when requested TelephonyProvider Fault in Terminal when requested TelephonyProvider
RawEventHandler Responsibility Collaborator Receive call state change events TelephonyProvider Delegate off application Listener and Observer events in a separate thread BlockManager
ListenerManager Responsibility Collaborator Track Listeners and Observers on a Call Determine when a Listener is no longer appropriate for a Call Ease of Implementation
The addition of dynamic state synchronization to the Generic JTAPI Framework should not impose undue burden on TelephonyProviders that support static state updates (i.e. that report all state transitions on all Domain objects and all Calls). To accomplish this, the following is a requirement of the new TelephonyProvider changes:
- The new methods may be implemented as NO-OPs if the provider does not throw ResourceUnavailableException for getAddresses() and does not have "throttle" set to true.
- A new abstract TelephonyProvider will be provided that remove the additional methods from the list of methods a class must implement. TelephoyProviders may choose to extend this abstract class.
Snapshot Data Holders
In order to allow for lazy call state fetching, some helper classes are needed for the simple indication of call state information:public class CallData { public int callState; public ConnData[] connections; }public class ConnectionData { public int connState; public String address; public boolean isLocal; public TCData[] terminalConnections; }public class TCData { public int tcState; public TermData terminal; public String[] terminals; }public class TermData { public String terminal; public boolean isMedia; }8 Issue Support
These subsections detail how the proposed low-level API provides support for various key framework requirements.8.1 Asynchronous vs. Synchronous
We've decided to follow the JTAPI paradigm as closely as possible, i.e. actions are started more or less immediately. The telephony provider may have to hold a thread until an asynchronous event returns. We thought this was better than making the TelephonyProvider asynchronous, since if the vendor's API is synchronous, we end up doing needless waiting and event triggering.8.2 Multi-Threading
Wherever modifications are made to a key collection (i.e. the active call set), care is taken to update the set in small synchronized methods. Threads are not blocked by other actions unless absolutely necessary. That is, the API and framework does not define the synchronization aspect of most calls. Care must be taken within any implementation to watch out for feature interactions, and keep any required synchronized blocks as small as possible.8.3 Callback Dispatch
The event handling model is to have all application Listener or Observer event dispatch create a Runnable "block" that is placed on a queue to be picked up and run by a Framework event thread. This architecture accomplishes two things:
- Event dispatch returns in a timely fashion to the Framework thread, which may originate from a TelephonyProvider's state callback method, eliminating the need for the telephony provider to worry about blocking event calls and setting up its own event dispatch threads.
- Since only one event management thread empties the pool, thread creation costs are not a problems and event ordering is preserved.
8.4 Scalability
The Generic JTAPI framework architecture and TelephonyProvider API tries to facilitate scalability by ensuring that:
- Methods are only synchronized when absolutely necessary, and in the smallest methods or blocks possible.
- The pluggable layer allows for the insertion of proxy layers that allow for the downloading of processing to other system nodes.
The current JTAPI specification relies on a JTAPI provider having a fixed set of addresses that it can manage. It is possible that for VOIP networks, the set of managed addresses and terminals may be subject to flux during the life of the provider. This is an issue that should be raised with the JTAPI specification committee.
© Richard Deadman, Deadman Consulting
http://www.deadman.ca
2002


Platform
{{platform}}
Version
{{osVersion}}
UUID
{{uuid}}
Model
{{model}}
Connection
{{connectionType}}


RT @willmanduffy: I forgot about that episode of Star Trek where Tasha Yar died and they buried her in the Windows XP wallpaper https://t.c…
5/27/2016, 8:22:16 PM
Favs: 0
Retweets: 0
link--- layout: tweet ---
RT @willmanduffy: I forgot about that episode of Star Trek where Tasha Yar died and they buried her in the Windows XP wallpaper https://t.c…
5/27/2016, 8:22:16 PM
Favs: 0
Retweets: 0
link


As cody tries to get back to the surface he notices his legs are moving funny he looks down to see a MERMAN tail where his legs should be,he can't go back looking like a merperson, so he sets off to find answers,leaving his family,friends and dreams behind,cody sets off on the advednture of a lifetime
As Cody travels the ocean he notices a mermaid being chased by monsters with with stingray heads


Manage Announcement
Home > Manage Announcement
{{announcementsDrafted.title | capitalizeFirst}}
{{announcementsDrafted.message | capitalizeFirst}}
{{announcementsDrafted.sticky | capitalize}}
{{announcementsDrafted.auto_post_on | date: 'd/M/y'}}
-
{{announcementsDrafted.valid_till | date: 'd/M/y'}}
-
{{announcementsDrafted.created_at | date:'y/M/d'}}
Edit
{{announcementsPublished.title| capitalizeFirst}}
{{announcementsPublished.message | capitalizeFirst}}
{{announcementsPublished.sticky | capitalize}}
{{announcementsPublished.valid_till | date: 'd/M/y'}}
-
{{announcementsPublished.created_at | date:'y/M/d'}}
{{announcementsPublished.created_by.username | capitalize}}


What about ISAMA
ISAMA is a marketing foundation located in Riyadh
built on the talent of creation that leads to a modern
concept of professionalism. At ISAMA we believe even
if you are good at what you do, you have a great prod-
uct or you provide an excellent service.  Simply we give your business
the perfect image.
Why we exist
Reaching customer satisfaction through providing
them with cutting-edge technologies that give clients
accessto a wide range of tools, ensuring efficient
and results-oriented communication solutions, which
grant them a special character that distinguishes them
from the others in the business.


-
Get your new habit started with a bang! Go get yourself a fancy new water bottle—something that will make you want to pick
it up throughout the day—and then come back and check this task off as complete.
-
Lorem ipsum dolor sit amet.
-
Lorem ipsum dolor sit amet.


| MPI_SCATTER( sendbuf, sendcount, sendtype, recvbuf, recvcount, recvtype, root, comm) | |
| IN sendbuf | address of send buffer (choice, significant only at root) |
| IN sendcount | number of elements sent to each process (non-negative integer, significant only at root) |
| IN sendtype | data type of send buffer elements (significant only at root) (handle) |
| OUT recvbuf | address of receive buffer (choice) |
| IN recvcount | number of elements in receive buffer (non-negative integer) |
| IN recvtype | data type of receive buffer elements (handle) |
| IN root | rank of sending process (integer) |
| IN comm | communicator (handle) |
int MPI_Scatter(void* sendbuf, int sendcount, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm)
MPI_SCATTER(SENDBUF, SENDCOUNT, SENDTYPE, RECVBUF, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR)
<type> SENDBUF(*), RECVBUF(*)
INTEGER SENDCOUNT, SENDTYPE, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR
void MPI::Comm::Scatter(const void* sendbuf, int sendcount, const MPI::Datatype& sendtype, void* recvbuf, int recvcount, const MPI::Datatype& recvtype, int root) const = 0
MPI_SCATTER is the inverse operation to MPI_GATHER.
If comm is an intracommunicator, the outcome is as if the root executed n send operations,
MPI_Send(sendbuf+i· sendcount· extent(sendtype), sendcount, sendtype, i,...),
and each process executed a receive,
MPI_Recv(recvbuf, recvcount, recvtype, i,...).
An alternative description is that the root sends a message with MPI_Send(sendbuf, sendcount·n, sendtype, ...). This message is split into n equal segments, the i-th segment is sent to the i-th process in the group, and each process receives this message as above.
The send buffer is ignored for all non-root processes.
The type signature associated with sendcount, sendtype at the root must be equal to the type signature associated with recvcount, recvtype at all processes (however, the type maps may be different). This implies that the amount of data sent must be equal to the amount of data received, pairwise between each process and the root. Distinct type maps between sender and receiver are still allowed.
All arguments to the function are significant on process root, while on other processes, only arguments recvbuf, recvcount, recvtype, root, and comm are significant. The arguments root and comm must have identical values on all processes.
The specification of counts and types should not cause any location on the root to be read more than once.
Rationale.
Though not needed, the last restriction is imposed so as
to achieve symmetry with
MPI_GATHER, where the corresponding restriction (a multiple-write
restriction) is necessary.
( End of rationale.)
The ``in place'' option for intracommunicators is specified by passing
MPI_IN_PLACE as
the value of recvbuf at the root. In such case,
recvcount and recvtype are ignored, and root
``sends'' no data to itself. The scattered vector is still assumed to
contain n segments, where n is the group size; the root-th
segment, which root should ``send to itself,'' is not moved.
If comm is an intercommunicator, then the call involves all processes in the intercommunicator, but with one group (group A) defining the root process. All processes in the other group (group B) pass the same value in argument root, which is the rank of the root in group A. The root passes the value MPI_ROOT in root. All other processes in group A pass the value MPI_PROC_NULL in root. Data is scattered from the root to all processes in group B. The receive buffer arguments of the processes in group B must be consistent with the send buffer argument of the root.
| MPI_SCATTERV( sendbuf, sendcounts, displs, sendtype, recvbuf, recvcount, recvtype, root, comm) | |
| IN sendbuf | address of send buffer (choice, significant only at root) |
| IN sendcounts | non-negative integer array (of length group size) specifying the number of elements to send to each processor |
| IN displs | integer array (of length group size). Entry i specifies the displacement (relative to sendbuf from which to take the outgoing data to process i |
| IN sendtype | data type of send buffer elements (handle) |
| OUT recvbuf | address of receive buffer (choice) |
| IN recvcount | number of elements in receive buffer (non-negative integer) |
| IN recvtype | data type of receive buffer elements (handle) |
| IN root | rank of sending process (integer) |
| IN comm | communicator (handle) |
int MPI_Scatterv(void* sendbuf, int *sendcounts, int *displs, MPI_Datatype sendtype, void* recvbuf, int recvcount, MPI_Datatype recvtype, int root, MPI_Comm comm)
MPI_SCATTERV(SENDBUF, SENDCOUNTS, DISPLS, SENDTYPE, RECVBUF, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR)
<type> SENDBUF(*), RECVBUF(*)
INTEGER SENDCOUNTS(*), DISPLS(*), SENDTYPE, RECVCOUNT, RECVTYPE, ROOT, COMM, IERROR
void MPI::Comm::Scatterv(const void* sendbuf, const int sendcounts[], const int displs[], const MPI::Datatype& sendtype, void* recvbuf, int recvcount, const MPI::Datatype& recvtype, int root) const = 0
MPI_SCATTERV is the inverse operation to MPI_GATHERV.
MPI_SCATTERV extends the functionality of MPI_SCATTER by allowing a varying count of data to be sent to each process, since sendcounts is now an array. It also allows more flexibility as to where the data is taken from on the root, by providing an additional argument, displs.
If comm is an intracommunicator, the outcome is as if the root executed n send operations,
MPI_Send(sendbuf+displs[i]· extent(sendtype), sendcounts[i], sendtype, i,...),
and each process executed a receive,
MPI_Recv(recvbuf, recvcount, recvtype, i,...).
The send buffer is ignored for all non-root processes.
The type signature implied by sendcount[i], sendtype at the root must be equal to the type signature implied by recvcount, recvtype at process i (however, the type maps may be different). This implies that the amount of data sent must be equal to the amount of data received, pairwise between each process and the root. Distinct type maps between sender and receiver are still allowed.
All arguments to the function are significant on process root, while on other processes, only arguments recvbuf, recvcount, recvtype, root, and comm are significant. The arguments root and comm must have identical values on all processes.
The specification of counts, types, and displacements should not cause any location on the root to be read more than once. The ``in place'' option for intracommunicators is specified by passing MPI_IN_PLACE as the value of recvbuf at the root. In such case, recvcount and recvtype are ignored, and root ``sends'' no data to itself. The scattered vector is still assumed to contain n segments, where n is the group size; the root-th segment, which root should ``send to itself,'' is not moved.
If comm is an intercommunicator, then the call involves all processes in the intercommunicator, but with one group (group A) defining the root process. All processes in the other group (group B) pass the same value in argument root, which is the rank of the root in group A. The root passes the value MPI_ROOT in root. All other processes in group A pass the value MPI_PROC_NULL in root. Data is scattered from the root to all processes in group B. The receive buffer arguments of the processes in group B must be consistent with the send buffer argument of the root.


Toggle navigation
Org.nized
Home
Attendance
Notes
Surveys
Announcements
Reports (Officer Only)
People
Class Bonus
Advisor/Admin Only
Admin Page
Login
Notes
Create
Title
Person
Public to Person?
The Note
Actions
Edit
Delete


use HideBoy for text encryption
, the entered key for encryption creates an unique cryptography, and even with
open cryptography algoritm
is impossible to decrypt without the correct key. Try it!
Encrypt (hide text)
Decrypt (discover text)
{{app.inputLabel}}
{{app.inputTip}}
Key
{{app.keyTip}}
{{app.outputLabel}}
{{app.successMessage}}
{{app.commandName}}
{{app.subCommand1Name}}
{{app.subCommand1Name}}


Test JWT
Token expires every minute
GetJWT
Try Me!
TestJWT
Try Me!
Get an API Key
Try Me!
//ToDo secure this to admins only


--- layout: post title: "No Title" ---
This perfectly sums up the ridiculousness of climate change skeptics. Via peterwknox.


10 January, 2016
It is real and it is magnificent. Let's start with a big hamburger made of pure meat and cheese. Then add fresh tomato, lettuce and onion with tomato sauce, mustard and mayonnaise. It's more than good, it's magnificent.
Read more10 January, 2016
Hot, crispy and delicious. Enjoy our world famous potatoes, from the first to the last.
Read more