Package org.epics.pvaccess.client.rpc
Support code for implementing channelRPC.
PVService
This page documentation needs to be updated!
2011.08.22
CONTENTS
Introduction
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:
- factoryRPC
- A string field that is the name of a factory that implements the specific RPC service.
- arguments
- A structure that defines the arguments for the RPC.
This package provides:
- Client - The client code that interfaces to PVAccess, i.e. manages channel access communication with the service
- Server - Code that implements Support code for a record instance that implements a service. It calls service specific code.
A sevice implementation must implement the following interfaces, which are described in detail below.
- Server - Defined in javaIOC. package org.epics.ioc.pvAccess
interface RPCServer { void destroy() Status initialize(...); void request() }
- Client
interface ServiceClientRequester extends Requester{ void connectResult(...); void requestResult(...); }
The rest of this document describes the following:
- client
The java interfaces and factories this project provides for a service client. - server
The java interfaces and factories this project provides for a service server. - Examples:
- table
An example that returns data that can be interpeted as a table. - example
A example of a service that returns a somewhat complex structure.
- table
Client
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:
- connectResult
- This is called when ServiceClient has connected to the service or when
a timeout occurs. It has the methods:
- status
- The status as descibed in project pvData.
- pvArguments
- The arguments structure defined in the service record.
- bitSet
- A bitSet for pvArguments. The client must call bitSet.set for any fields it changes in pvAguments before issuing a request.
- requestResult
- This is called when the ServiceClient receives the request data from
the service. It has the methods:
- status
- The status of the request as described in project pvData.
- pvResult
- The pvStructure created by the service.
ServiceClient is created by ServiceClientFactory. It has the methods:
- destroy
- Called by the client when it no longer requires the service.
- waitConnect
- Called by the client to wait until a connection has been made to the service or a timeout occurs.
- sendRequest
- Called by the client to send a request to the service.
- waitRequest
- Called by the client to wait until the request response has been returned by the service.
ServiceClientFactory, which is also implemented by this project, has the following method:
- create
- Creates a ServiceClient and connects to the service. It has the
arguments:
- serviceName
- The name of the channel, i.e. record, that implements the service.
- requester
- The serviceChannelRequester as described above.
Server
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:
- destroy
Called when a client disconnects from the ChannelRPC.
- initialize
- Called when a client creates a ChannelRPC. It has the arguments:
- channel
- The channel that is connecting to the service.
- pvRecord
- The record that implements the service.
- channelRPCRequester
- The remote pvAccess server implements this and passes the information back to the client.
- pvArgument
- The arguments structure as defined in the record.
- bitSet
- A bitSet for arguments. The service can use this to determine what has changed since the last request.
- pvRequest
- An optional pvStructure than can be passed between client an d server. See pvAccess for details.
- request
- Called when a client calls channelRPC.request. The service is expected
to create a new pvStructure and call:
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:
- create
- Called by org.epics.ca.server.impl.local.ChannelServerFactory when the PVRecord for the service is initialized.
Examples
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.
Running the examples
The example package has a file pvService.zip that runs the example. To run the example do the following:
- Copy pvService.zip to some test directory and unzip it.
- change directory location to pvService.
- Edit the source file so that it has the correct locations for WORKSPACE and for the org.eclipse.swt definitions.
- Open two windows in the pvService directory
- In one window execute the command:
./serviceExample
- In other window execute the command:
./clientExample
- In other window execute the command:
./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 service record
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.
- exampleService
- This is the record for clientExample
- tableSevice
- This is the record for clientTable
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>
-
Interface Summary Interface Description RPCClient Interface that is called by a service client.RPCClientRequester The interface implemented by a service requester. -
Class Summary Class Description RPCClientFactory The factory to create a RPCClient.RPCClientImpl