Service object sharing is the ability to allow multiple concurrent access to a single instance of a service specific object under the Natural Access framework.
For example, assume that VCE service objects are made sharable. Two applications can then open the same shared prompt file (the service object). Then one application can add messages to the prompt file, while the other application plays the messages that are added.
To share a service object, each client attach to the same context and to the same service object. This gives each client a unique client-side object handle that is associated with the same service object.
The following scenarios describe how a service object can become shared:
Peer-to-peer: In this scenario, clients act as peers; they follow a private protocol to decide when to share service objects and which service objects to share. In this case a mechanism is needed to identify a service object to be shared, to transport that information from one peer to the other, and to attach to the underlying object. All Natural Access services support this scenario.
Query and attach: In this scenario, a Natural Access service provides a client-callable API function to enumerate its own service objects and to attach to those objects. Very few Natural Access services support this scenario.
Unsolicited event: In this scenario, clients share the same Natural Access context but not an associated service specific object. In this case it is entirely possible that an event containing a service object handle will be broadcast to these clients. For those clients not specifically sharing the service object, this event is an unsolicited event. Appropriate attach processing must occur before access to this service object can occur. This scenario can only be supported by asynchronous services.
This section presents:
Clients sharing a service object as peers use a service object descriptor to specify the service object to share. The service object descriptor is a well-formed string that contains service object addressing information. This descriptor can be passed from client to client using any transport mechanism of choice. Upon receipt of the descriptor, a client can then attach to the underlying service object with an API call, adding a new record to the internal mapping table.
Converting a client handle to an object descriptor
The application should convert the client-side handle into an object descriptor that can be used to locate a particular instance of an object within the multi-server Natural Access environment.
The Natural Access development environment provides application writers with ctaGetObjDescriptor, which retrieves the object descriptor associated with a specified object handle. The creation and interpretation of the object descriptor is handled within the Natural Access core. Service developers do not need to provide conversions functions of their own.
Converting client handle to object descriptor
Transporting the object descriptor to another client
Any application that needs to share a service object with another application requires an object descriptor. The descriptor simply identifies to the Natural Access core the particular service object that is to be shared. The Natural Access development environment provides no inherent mechanisms that transparently enable an application to transfer an object descriptor to another application. It is the responsibility of the application writer to translate a service handle into a descriptor (by invoking ctaGetObjDescriptor) and to pass it over to the peer as depicted in the following illustration.
Transporting object descriptor to another client
Since the descriptor is a string of characters, any of several simple mechanisms can be used to pass a descriptor to another application:
One application writes the descriptor to a file. The second application then reads it from the file. The filename can be hard-coded into the application, or passed in as a startup parameter.
Establish a private IPC channel (for example, using a socket or shared memory) between the applications. The descriptor can then be sent from one application to the other over this private channel using common IPC functions.
Each application creates or attaches to an agreed upon context name (for example, TransferCtx). Then an application can use ctaQueueEvent to pass the descriptor within an application event. All clients attached to a shared context receive all events generated within the context. Therefore, the target application client receives the application event containing the object descriptor.
Converting the descriptor back to a handle and attaching objects
When an application receives the object descriptor representing a service object that is being shared with a peer application, it must then turn the descriptor into a client-side service object handle by passing the descriptor to the Natural Access core function ctaAttachObject. ctaAttachObject returns a client-side handle to the service object. The application is then able to operate on the service object using the newly assigned client-side handle just as if it were the application that originally created the service object.
Note: Before invoking ctaAttachObject, the application must attach to the shared context. For more information on the basic concepts of context sharing, refer to the Natural Access Developer's Reference Manual.

Converting descriptor to service object handle and attaching object
A Natural Access service can implement service object sharing using named service objects. The NMS Point-to-Point Switching (PPX) service supports the concept of named objects. Users of this service can create a connection and assign it a name. Subsequently, another application needing to alter the connection (which is a PPX service object) need only open the connection using the assigned name in its call to ppxOpenConnection. ppxOpenConnection returns a client-side service handle to the connection object. At this point, the connection object is shared.
Just as with object descriptors, users of service object names need a mechanism for knowing or agreeing to the object's name before they can share access to the object. Unlike object descriptors, there is no standard Natural Access function equivalent to ctaAttachObject that operates on service object names for performing attachments. Instead, the service developer must create a service specific attach-object-by-name function (xxxAttachObject).
In the query and attach service object-sharing scenario, the service developer implements a query and attaches all capability into the service API. The API allows the application to ask for the number of service objects currently existing in the running instance of the service implementation (xxxGetNumberObjects). After allocating adequate space, the application then calls a function to attach to all objects (xxxAttachAllObjects). xxxAttachAllObjects returns a buffer of client-side service handles that the application can use for normal operations on the service objects.
With this approach, the service interface must get a buffer of service object handles from the service implementation. These handles must then be converted into client-side service object handles within the service interface before they are passed up to the calling application.
In the unsolicited event approach, the service interface automatically creates client-side service handles when it receives service events. The service interface takes advantage of the fact that all clients attached to a shared context receive all of the service events on that context.
The service implementation side sends a service-side object handle in the Natural Access event structure CTA_EVENT. The service interface implements the API function xxxEventProcessing, which Natural Access automatically calls prior to passing the service's event up to the client. xxxEventProcessing causes the service interface to automatically create a client-side service handle (using dispCreateHandle) if one did not already exist for the service object handle contained within the event. (The service interface uses the Natural Access core function dispFindHandle for making this determination.) The modified event is then sent to the client.
This scenario allows an application to automatically deliver a client-side service handle without making any explicit calls. However, a client of the context must make a service API call that results in the generation of a service event, which is then received by all clients attached to the context. No object sharing occurs until this event is generated.
The following code sample illustrates the use of an unsolicited event for creating a client side handle using the xxxEventProcessing client-side binding function:
/*-------------------------------------------------------------------------
dtmEventProcessing
Client-side binding function called by Natural Access dispatcher, whereby:
- object may be attached based on objHd field in event
- object may be destroyed on client side based on event type
-----------------------------------------------------------------------*/
DWORD dtmEventProcessing ( CTA_EVENT* event )
{
DWORD shd = event->objHd; /* server side object handle */
char objName[DTM_OBJ_NAME_LEN];
DWORD ret = SUCCESS;
/* Create a service specific name for this object based upon
data sent in event's size field. */
_buildObjName( event->size, objName);
if (shd != 0)
{
/* Find client-side handle associated with server-side handle */
ret = dispFindHandle(event->ctahd, DTM_SVCID, shd, &(event->objHd));
if ( ret != SUCCESS )
{
/* An entry in the dispatcher's mapping table was not
found for this object. Therefore, create a new entry.
The event objHd field will be set to the new client-side
object handle. */
dispCreateHandle(event->ctahd, DTM_SVCID, shd,
&(event->objHd));
/* Save the object name with the new mapping table entry,
in addition to the server-side object handle. */
dispSetHandleValueEx(event->objHd, shd, objName);
}
else
{
/* A client-side object handle already exists for this
server-side object handle. If this is a DTMEVN_MONITOR_DONE
event, the object entry in the dispatcher mapping must be
now be removed. */
if (event->id == DTMEVN_MONITOR_DONE)
{
dispDestroyHandle( event->objHd );
}
}
}
return ret;
}