This package provides support for services that are implemented as an RPC (Remote Procedure Call). PVAccess provideds two flavors of RPC: putProcessGet and channelRPC.
If the service is accessed via a putProcessGet the record that implements the RPC has the structure
record serviceName
// may be optional fields
structure arguments
// sevice specific
structure result
// service specific
If the service is accessed via a channelRPC the record that implements the RPC has the structure:
record serviceName
// may be optional fields
structure arguments
// sevice specific
The main difference between the two types of service is that for a putProcessGet the structure of the result is fixed and for a channelRPC a completely new structure is returned for each request.
This package provides support for channelRPC: It provides client and server support for implementing a network accessable service that uses PVData for all data communication between a client and the service. The service is implemented via a PVRecord that is present in a javaIOC. The client communicates with the server via a ChannelRPC (Remote Procedure Call) as defined by pvAccess.
The record name is the name of the service. The record has the following fields:
This package provides:
A sevice implementation must implement the following interfaces, which are described in detail below.
interface RPCServer {
void destroy()
Status initialize(...);
void request()
}
interface ServiceClientRequester extends Requester{
void connectResult(...);
void requestResult(...);
}
The rest of this document describes the following:
The client is implemented via the following interfaces and factory:
interface ServiceClientRequester extends Requester{
void connectResult(Status status,PVStructure pvArguments,BitSet bitSet);
void requestResult(Status status,PVStructure pvResult);
}
interface ServiceClient {
void destroy();
void waitConnect(double timeout);
void sendRequest();
void waitRequest();
}
class ServiceClientFactory {
public static ServiceClient create(String serviceName,ServiceClientRequester requester);
}
ServiceClientRequester, which must be implemented by each client, has the following methods:
ServiceClient is created by ServiceClientFactory. It has the methods:
ServiceClientFactory, which is also implemented by this project, has the following method:
The service is implemented via the following interfaces and factory:
//RPCServer defined in org.epics.ca.server.impl.local
public interface RPCServer {
void destroy();
Status initialize(
Channel channel,
PVRecord pvRecord,
ChannelRPCRequester channelRPCRequester,
PVStructure pvArgument,
BitSet bitSet,
PVStructure pvRequest);
void request();
}
class XXXServiceFactory {
public static RPCServer create();
}
RPCService, which is implemented by each service, has the following methods:
Called when a client disconnects from the ChannelRPC.
channelRPCRequester.requestDone(okStatus, pvTop);where pvTop is the newly created pvStructure.
Also the service must implement a XXXServiceFactory, which is specified in the record.factory field of the PVRecord. It has the following method:
The project provides examples in package (org.epics.pvService.example). This section describes ExampleClient and ExampleServiceFactory, which are the client and server sides of the example. The example is skeleton code for a service that, given a search string, returns a set of pvnames. Each pvName can have associated properties. The example ignores the search request. Instead it just makes up two pvnames (pvName0 and pvName1) and makes up some properties for each pvname.
The example package has a file pvService.zip that runs the example. To run the example do the following:
./serviceExample
./clientExample
./clientTable
In the window where clientExample is run you should see:
structure
{
0 = structure
{
name = pvName0
properties = structure
{
a = structure
{
value = avalue
owner = aowner
}
b = structure
{
value = bvalue
owner = bowner
}
}
}
1 = structure
{
name = pvName1
properties = structure
{
a = structure
{
value = avalue
owner = aowner
}
b = structure
{
value = bvalue
owner = bowner
}
}
}
}
all done
In the window where clientTable is run you should see:
mrk> ./clientTable
structure table
int nrows 2
structure columns
string[] name [name0,name1]
double[] value [10.0000,20.0000]
structure[] timeStamp
structure timeStamp
long secondsPastEpoch 946702800
int nanoseconds 582000000
structure timeStamp
long secondsPastEpoch 946702801
int nanoseconds 582000000
timeStamp[] [ 2000-01-01 00:00:00.582, 2000-01-01 00:00:01.582]
structure table
int nrows 5
structure columns
string[] name [name0,name1,name2,name3,name4]
double[] value [10.0000,20.0000,30.0000,40.0000,50.0000]
structure[] timeStamp
structure timeStamp
long secondsPastEpoch 946702800
int nanoseconds 582000000
structure timeStamp
long secondsPastEpoch 946702801
int nanoseconds 582000000
structure timeStamp
long secondsPastEpoch 946702802
int nanoseconds 582000000
structure timeStamp
long secondsPastEpoch 946702803
int nanoseconds 582000000
structure timeStamp
long secondsPastEpoch 946702804
int nanoseconds 582000000
timeStamp[] [ 2000-01-01 00:00:00.582, 2000-01-01 00:00:01.582, 2000-01-01 00:00:02.582, 2000-01-01 00:00:03.582, 2000-01-01 00:00:04.582]
all done
The xml file that implements the example service is:
<database>
<record recordName = "exampleService" extends = "org.epics.pvService.service">
<scalar name = "factoryRPC">org.epics.pvService.example.ExampleServiceFactory</scalar>
<structure name = "arguments">
<scalar name = "search" scalarType = "string" />
</structure>
</record>
<record recordName = "tableService" extends = "org.epics.pvService.service">
<scalar name = "factoryRPC">org.epics.pvService.example.TableServiceFactory</scalar>
<structure name = "arguments">
<scalar name = "search" scalarType = "string" />
<scalar name = "number" scalarType = "int" />
</structure>
</record>
</database>
This creates two records.
Note that both records are created by extending org.epics.pvService.service. This is defined in pvService.xml.structure.service.xml:
<structure structureName = "service"> <scalar name = "factoryRPC" scalarType = "string" /> <structure name = "arguments" /> </structure>