Gather is a sevice that "gathers" data from a set of channels and makes the data available via arrays of data.
This package provides two services:
This overview discusses the following topics:
CreateGatherFactory creates a client that connects to a createGather record, which implements the createGather service.
class CreateGatherFactory {
public static CreateGather create(String serverName,Requester requester);
}
The arguments to create are:
interface CreateGather {
void destroy();
Status connect();
Status waitConnect(double timeout);
Status sendRequest(String[] channelNames,boolean channelsAreArrays,String gatherRecordName,
boolean temporary,boolean monitor);
Status waitRequest();
}
where:
After creating a new implementation of createGather the client must connect and then wait for connection to complete. Connect and waitConnect are separate calls so the client can do other things while connecting.
Once the connection is complete the client can call sendRequest and waitRequest. Again these are separate requests so that the client can do other things while sendRequest is active.
When the client is done with createGather.destroy should be called.
Thus life cycle for a client must follow the following order:
CreateGather createGather = CreateGatherFactory.create(...)
createGather.connect(...)
createGather.waitConnect(...)
REPEAT
createGather.sendRequest(...)
gather.waitRequest(...)
ENDREPEAT
createGather.destroy()
If the order is violated an exception is thrown.
The Status return should always be checked to see that status.isOK() returns true.
If waitRequest returns status.isOK() true then the gather record has been created. If the record already exists status.isOK() is true but requester.message is called with a warning message stating that the record already exists.
public class CreateGatherRecords {
private static final String requesterName = "createGatherRecords";
private static final String serverName = "createGather";
private static String putGetPrefix = "putGetExample";
private static String putGetRecordName = putGetPrefix;
private static int numberPutGetRecords = 5;
private static String gatherPrefix = "gatherExample";
private static String gatherRecordName = gatherPrefix;
private static int numberGatherRecords = 5;
private static String arrayPrefix = "array";
private static String arrayRecordName = arrayPrefix;
private static int numberArrayRecords = 3;
public static void main(String[] args) {
org.epics.pvaccess.ClientFactory.start();
Requester requester = new RequesterImpl();
CreateGather create = CreateGatherFactory.create(serverName, requester);
Status status = create.connect();
if (!status.isSuccess()) messageAndExit(status);
status = create.waitConnect(1.0);
if (!status.isSuccess()) messageAndExit(status);
String[] channelNames = new String[numberPutGetRecords];
for (int i = 0; i < numberPutGetRecords; i++){
channelNames[i] = putGetPrefix + String.format("%04d", i);
}
status = create.sendRequest(channelNames, putGetRecordName,false,false,false);
if (!status.isSuccess()) messageAndExit(status);
status = create.waitRequest();
if (!status.isSuccess()) messageAndExit(status);
channelNames = new String[numberGatherRecords];
for (int i = 0; i < numberGatherRecords; i++){
channelNames[i] = gatherPrefix + String.format("%04d", i);
}
status = create.sendRequest(channelNames, gatherRecordName,false,true,false);
if (!status.isSuccess()) messageAndExit(status);
status = create.waitRequest();
if (!status.isSuccess()) messageAndExit(status);
channelNames = new String[numberArrayRecords];
for (int i = 0; i < numberArrayRecords; i++){
channelNames[i] = arrayPrefix + String.format("%04d", i);
}
status = create.sendRequest(channelNames, arrayRecordName,false,true,true);
if (!status.isSuccess()) messageAndExit(status);
status = create.waitRequest();
if (!status.isSuccess()) messageAndExit(status);
create.destroy();
}
private static void messageAndExit(Status status) {
System.out.printf("status %s message %s%n", status.getType().name(),
status.getMessage(), status.getStackDump());
System.exit(1);
}
private static class RequesterImpl implements Requester {
public String getRequesterName() {return requesterName;}
public void message(String meage, MessageType messageType) {
System.out.printf("%s %s%n", messageType.name(), message);
}
}
}
The definitions for are:
class GatherFactory {
public static Gather create(String serverName,boolean channelsAreArrays,Requester requester,
String commands,String properties);
}
The GatherFactory is called to create a new client that connects to a gather record with the name serverName. The caller must implement interface Requester. Once a Gather is created the client can call it as many times as desired.
The arguments to create are:
The properties the client will access from GatherData. This can be any combination of "value,isBad,isConnected,severityIndex". If a property is not specified here then GatherData will return a null value for that property when it is requested. For each of isBad, isConnected, and severityIndex the gather client creates a monitor on the corresponding field of the gather record if the property is requested.
interface GatherMonitorRequester {
void monitorEvent();
}
interface GatherMonitor {
boolean poll();
}
interface Gather {
void destroy();
Status connect();
Status waitConnect(double timeout);
GatherDataScalar getGatherDataScalar();
GatherDataArray getGatherDataArray();
Status createMonitor(GatherMonitorRequester gatherMonitorRequester);
Status waitCreateMonitor();
GatherMonitor getGatherMonitor();
Status processGet();
Status waitProcessGet();
Status get();
Status waitGet();
Status putBad(boolean[] isBad);
Status waitPutBad();
Status putValue(double[] value);
Status waitPutValue();
}
where:
After creating a new implementation of gather the client must connect and then wait for connection to complete. This is done via separate calls so the the client can do other things while connecting.
Once the connection is complete the client can issue a single createMonitor request and multiple get and wait requests. Each has a separate request and wait. These are separate so that the client can do other things while the request is being implemented.
When the client is done with the gather destroy should be called.
Thus life cycle for a client must follow the following order:
Gather gather = GatherFactory.create(...)
gather.connect(...)
gather.waitConnect(...)]
gather.getGatherDataScalar()
or
gather.getGatherDataArray()
IF_WANT_MONITOR
gather.createMonitor()
gather.waitCreateMonitor()
gather.getMonitor()
ENDIF_WANT_MONITOR
REPEAT
gather.get(...)
gather.waitGet(...)
and/or
gather.processGet()
gather.waitProcessGet()
and/or
gather.putBad()
gather.waitPutBad()
and/or
gather.putValue()
gather.waitPutValue()
ENDREPEAT
gather.destroy()
If the order is violated an exception is thrown.
The Status returns should always be checked to see that status.isOK() returns true.
After the client has successfull connected to the gather record either a GatherDataScalar or a GatherDataArray is created. It holds data obtained for the client. For isBad, isConnected, and severityIndex a monitor is placed on the corresponding field of the gather record. GatherData is updated when a monitor occurs. The value field is updated either because of a get request or because gatherMoitor.poll() is called. Thus the update of the value field is under the complete control of the client.
interface GatherData {
Alarm getAlarm();
TimeStamp getTimeStamp();
int getNumberChannels();
boolean anyBad();
boolean isBad(int index);
boolean badChange();
boolean allConnected();
boolean isConnected(int index);
boolean connectionChange();
int getSeverityIndex(int index);
boolean severityIndexChange();
}
interface GatherDataScalar extends GatherData {
double[] getValue();
}
interface GatherDataArray extends GatherData {
double[] getValue(int index);
}
where
GatherDataScalar extends GatherData. It is implemented only if the gather record accesses channels that are each a scalar. It implements the following method:
GatherDataArray extends GatherData. It is implemented only if the gather record accesses channels that are each an array. It implements the following method:
As shown above a client can ask to monitor a gather record. In this case the client must implement interface GatherMonitorRequester, which has a single method monitorEvent. This method is called whenever a monitor is sent from the gather record. The client calls gatherMonitor.poll() to see if more monitior events are queued for the client. If there is more, the data is put into GatherData. Thus the client has code like:
if(monitorEvent) {
while(true)
if(!gatherMonitor.poll()) break;
// data is in gatherDataScalar or gatherDataArray
}
}
An example client and a caV3 database is provided in gather/test/org/epics/pvService/gather/example/gather.zip. Somewhere unzip this file and:
../../bin/<arch>/example st.cmd
./serviceExample
./clientExample
File gather/test/org/epics/pvService/gather/example/package.html provides more details about running the examples.
The client side of createGather implements the methods of CreateGather as follows:
The gather create service is implemented via support. The xml definitions for the gather create support and record are defined in pvService/xml/structure/gather.xml:
<structure structureName = "org.epics.pvService.createGatherFactory">
<scalar name = "supportFactory" scalarType = "string">
org.epics.pvService.gather.support.CreateGatherFactory</scalar>
</structure>
<structure structureName = "org.epics.pvService.createGather" extends = "generic">
<structure name = "alarm" extends = "alarm"/>
<structure name = "timeStamp" extends = "timeStamp" />
<structure name = "arguments">
<auxInfo name = "supportFactory" scalarType = "string">org.epics.pvService.createGatherFactory</auxInfo>
<array name = "channelNames" scalarType = "string" />
<scalar name = "gatherRecordName" scalarType = "string" />
<scalar name = "temporary" scalarType = "boolean" />
<scalar name = "channelsAreArrays" scalarType = "boolean" />
<scalar name = "monitor" scalarType = "boolean" />
</structure>
<structure name = "result">
<scalar name = "status" scalarType = "string" />
</structure>
<scalar name = "removeRecordRecord" scalarType = "string" />
</structure>
An example of creating records for createGather is given in the zip file for the example. The file is gather.xml:
<database>
<import name = "org.epics.ioc.*" />
<import name = "org.epics.pvData.*" />
<record recordName = "recordRemoveRPC" extends = "recordRemove" />
<record recordName = "createGather" extends = "org.epics.pvService.createGather" >
<scalar name = "removeRecordRecord">recordRemoveRPC</scalar>
</record>
</database>
The two records are:
When a gather create record is processed the gather support does the following:
The client must call GatherFactory.create, which has the arguments:
Create returns interface Gather. The client side of gather implements the methods of Gather as follows:
The gather service is implemented via support. The xml definitions for the gather support and record are defined in pvService/xml/structure/gather.xml:
<structure structureName = "org.epics.pvService.gatherFactory">
<scalar name = "supportFactory" scalarType = "string">
org.epics.pvService.gather.support.GatherFactory</scalar>
</structure>
<structure structureName = "org.epics.pvService.gatherScalar" extends = "generic">
<structure name = "alarm" extends = "alarm"/>
<structure name = "timeStamp" extends = "timeStamp" />
<scalar name = "command" scalarType = "string">get</scalar>
<scalar name = "options" scalarType = "string" />
<array name = "value" scalarType = "double" />
<array name = "isBad" scalarType = "boolean" />
<array name = "isConnected" scalarType = "boolean" />
<array name = "severityIndex" scalarType = "byte" />
<array name = "channelNames" scalarType = "string">
<auxInfo name = "supportFactory" scalarType = "string">org.epics.pvService.gatherFactory</auxInfo>
</array>
</structure>
<structure structureName = "org.epics.pvService.gatherArrayElement">
<scalar name = "value" scalarType = "double" />
</structure>
<structure structureName = "org.epics.pvService.gatherArray" extends = "generic">
<structure name = "alarm" extends = "alarm"/>
<structure name = "timeStamp" extends = "timeStamp" />
<scalar name = "command" scalarType = "string">get</scalar>
<scalar name = "options" scalarType = "string" />
<array name = "value" scalarType = "structure" extends = "org.epics.pvService.gatherArrayElement" />
<array name = "isBad" scalarType = "boolean" />
<array name = "isConnected" scalarType = "boolean" />
<array name = "severityIndex" scalarType = "byte" />
<array name = "channelNames" scalarType = "string">
<auxInfo name = "supportFactory" scalarType = "string">org.epics.pvService.gatherFactory</auxInfo>
</array>
</structure>
These definitions must be part of the structures defined in the javaIOC master database. The gather create support uses these definitions to create gather records. Note that a gather record has array fields for the data of interest to clients.
For each channelName, the gather support creates a caV3 channel for communication with the caV3 channel. The support also has support to get and put values to the caV3 channels.