EPICS pvAccessJava

EPICS v4 Working Group, Working Draft, 14-Dec-2011

This version:
pvAccessJava_20111214.html
Latest version:
pvAccessJava.html
Editors:
Marty Kraimer, BNL

Abstract

This document describes the Java implementation of EPICS v4 pvAccess.

For more information about the EPICS, please refer to the home page of the Experimental Physics and Industrial Control System.

Status of this Document

This is the 14-Dec-2011 version of the Java implementation of pvAccess. It is a complete implementation of pvAccess as currently defined.

CONTENTS

Introduction


This product is available via an open source license

This document is the project and package overviews for pvAccessJava. The javaDOC is available at JavaDoc

The javaDOC package overview documents for this project are not complete but the packages of interest to people writing client code or connecting an application that wants to start a pvAccess server is complete. What remains is to fully document the implementation. This project overview gives a brief description of the packages provided by this project.

This project implements pvAccess, which is an implementation of Channel Access that fully supports pvData. Package org.epics.ca.client is of interest to anyone who wants to write client code for pvAccess and is also of interest to anyone who wants to write a server that interfaces to other system. The other packages are mainly of interest to those who want to understand the internals of the implementation.

If your interest is only to write client code go directly to org.epics.ca.client

This project provides the client and server networking spport for the interfaces defined in org.epics.ca.client. The javaIOC provides a local implementation of Channel, which registers itself with the server support provides by this project. Other implementations of Channel can also be provided.

This package also allows the following:

  1. An application can be created that provide a pvAccess server that provides full support for pvData. This is done by starting a local PVDatabase, calling org.epics.ca.LocalFactory.start(), and calling org.epics.ca.ServerFactory.start().
  2. An extensible set of monitoring algorithms is supported. Monitoring is defined by project pvData. pvAccess provides access to this facility. A default set of monitoring algorithms is provided by pvData but other algorithms can be implemented. The code that implements an algorithm must extend org.epics.pvData..monitor.AbstractMonitor and register with org.epics.ca.server.ChannelServer.
  3. A query facility is supported. A client can ask that a network query request can be made. For example "get the channel list of all Beam Position Monitors". A query faciity is registered via a call to (TO BE DETERMINED).
  4. A gateway between pvAccess and other systems can be implemented. For example project javaIOC provides gateway code between caV3 and pvAccess. It allows a caV3 client to talk to a pvAccess server and allows a pvAccess client to talk to a caV3 server. For a pvAccess client the gateway implements interface Channel by using JCA/CAJ version 3. It implements a caV3 server by accessing the local PVDatabase. See project javaIOC (org.epics.ioc.caV3) for an example of what to do. It is complex because it is translating between different ways of defining data.

User Interface Packages


This section briefly describes the interfaces used by a pvAccess client and by an application that supports a pvAccess server. It only describes how things are connected, i.e. it does not describe interface Channel or any of its related interfaces because they are described in the package overview for org.epics.ca.client.

org.epics.ca

This package provides the factories that start the various components of pvAccess:

ClientFactory
This starts the client side of the network support for pvAccess. This is the only support that needs to be started by a stand-alone client. The example shown in the previous section calls this.
ServerFactory
This must be started in order to allow pvAccess clients to access the local PVDatabase. For example the javaIOC can start this.

org.epics.ca.client

This package provides everything required for a pvAccess client. See the package overview for details. This section only describes how to connect to a channel and how to register monitor algoritms and channel providers.

To connect to a channel a client does the following:

    // define the following
    private static final ChannelAccess channelAccess
         = ChannelAccessFactory.getChannelAccess();

    // to connect to a channel must know providerName and ChannelName
    String providerName = "pvAccess";
    String channelName = "someChannel";
    // then
    ChannelProvider channelProvider = channelAccess.getProvider(providerName);
    Channel = channelProvider.createChannel(
        channelName, this, ChannelProvider.PRIORITY_DEFAULT);

This package defines the interfaces a client uses to comnmunicate with a pvAccess server. This project fully supports all the interfaces. If a server is implemented for other systems, it is OK to implement a subset of the interfaces. For example the caV3 server implemented by the javaIOC does not support ChannelPutGet because an EPICS V3 IOC does not provide an equivalent facility.

Except for ChannelAccessFactory, this class contains only Java interface and enum definition. ChannelAccessFactory provides a complete implementation of interface ChannelAccess and two static public members:

public class ChannelAccessFactory {
    public static ChannelAccess getChannelAccess();
    public static void registerChannelProvider(ChannelProvider channelProvider);
}

where

getChannelAccess
This gets the single instance of ChannelAccess
registerChannelProvider
This registers a ChannelProvider. User code does not call this. It is called via the factories in org.,epics.ca.

ChannelAccess is defined as:

interface ChannelAccess {
    ChannelProvider getProvider(String providerName);
    String[] getProviderNames();
    PVStructure createRequest(String structureName,String request);
}

where

getProvider
Get the channel provider.
getProviderNames
Get the names of all the providers.
createRequest
A convenience method for clients see the package overview for details.

ChannelProvider has a method:

Channel createChannel(String channelName, ChannelRequester channelRequester,short priority);

This is the method a client calls to connect to a Channel. See the package overview for details.

org.epics.ca.server.plugins

Matej? What to say?


Problems and Future Plans


Query Facility

This needs to be defined and implemented.

Access Security

Something like how csV3 implements access security is required. A complication is that for caV3 a client attaches to a single scalar or array field. For pvAccess a client attaches to an arbirary set of fields in a record. Takes some thought to decide what to do.

User Controlled Send Queues

Currently a user can only ask to send a message immediately, i. e. a client has no control over when a message is sent. This can result in many short network packets. Perhaps the following should be provided: Allow a client, for each send request, to specify the following options:

immediate
Immediately queue a request to the send thread.
periodically
Put requests on a periodic send queue. At some periodic rate the queue is transfered to the send thread.
user queue
Client keeps a private queue for requests. The client decides when the queue should be transfered to the send thread.

Network Protocol


Must be described.


Helper Packages


This is set of packages that are used by other parts of this project

org.epics.ca

This has the following:

ClientFactory
Starts the client side of remote pvAccess.
ServerFacyory
Starts the server side of remote pvAccess.
CAConstants
A set of constants for pvAccess
CAException
An extension to Exception for pvAccess
Version
Defines the version.

org.epics.ca.util

This has the following:

ArrayFIFO
A FIFO queue.
BasicMutex
Provides lock/unlock. This is used instead of java.util.concurrent.locks.ReentrantLock because recursive locking is not desired.
CircularBuffer
A fixed size circular buffer. If full a new element replaces the oldest.
GrowingCircularBuffer
A circular buffer that holds an unlimited number of elements.
Heap
A heap based priority queue. QUESTION: Is this better than java.util.PriorityQueue?
HexDump
Converts a byte array to hex and writes to System.out.println.
InetAddressUtil
Convience methods for INET address conversion.
IntHashMap
An integer hash map. This is used instead of java.util.HashMap so that Integer objects do not have to be allocated.
ShortHashMap
A short hash map. This is used instead of java.util.HashMap so that Short objects do not have to be allocated.
Timer
QUESTION: Why not use pvData.misc.Timer? It does not require a new to add something to the list. Additional methods may have to be implemented for pvData.misc.Timer in order to provide the same functionality.
TimeStamp
QUESTION: Why not use pvData.property.TimeStamp? It can be changed to implement hashCode and equals.
WildcharMatcher
This is implemented instead of java.util.regex.Pattern because of code efficency.

org.epics.ca.util.logging

A logging facility based on java.util.logging. MATEJ can you describe?

org.epics.ca.util.sync

MATEJ can you describe?


Implementation Packages


These packages provide implementation classes and interfaces shared by both the client and server code for pvAccess

org.epics.ca.impl.remote

This package contains enums, interface, and abstract class definitions common to both the client and server implementation.

org.epics.ca.impl.remote.tcp

This contains the code that sends and receives tcp messages. It creates a send and a receive thread for each tcp connectrion.

org.epics.ca.impl.remote.udp

This contains the code that sends and receives udp messages. It creates a send and a receive thread for each udp connectrion.

org.epics.ca.impl.remote.utils

Some network utility support.


Client Implementation Packages


These packages provide the implementation classes and interfaces for the client code for pvAccess.

org.epics.ca.client.impl.remote

This implements the client side of passing the various ChannelXXX requests over the network, where XXX is Get, Put, PutGet, etc. This code uses the code in the following two packages to send requests and receive responses.

org.epics.ca.client.impl.remote.handlers

This implements handlers for receiving responses from network requests.

org.epics.ca.client.impl.remote.requests

This implements code that sends a network request.

org.epics.ca.client.impl.remote.tcp

This interfaces the client code to package org.epics.ca.impl.remote.tcp.


Server Implementation Packages


These packages provide the implementation classes and interfaces for the server code for pvAccess.

org.epics.ca.server.impl.remote

This implements the server side of passing the various ChannelXXX requests over the network, where XXX is Get, Put, PutGet, etc. This code uses the code in the following two packages to send requests and receive responses. It also has the code which issues beacons.

org.epics.ca.server.impl.remote.handlers

This implements handlers for receiving requests from the client.

org.epics.ca.server.impl.remote.plugins

Currently has just code related to beacons.

org.epics.ca.server.impl.remote.requests

This implements code that sends responses to the client.

org.epics.ca.server.impl.remote.tcp

This interfaces the server code to package org.epics.ca.impl.remote.tcp.


Package org.epics.ca


Overview

This package provides:

Factories
Factories are available to start pvAccess channel access. This includes local channel access and the client and server for remote pvAccess.
CAConstants
A set of constants used by the pvAccess implementation.
CAException
A extension of Exception for pvAccess.
Version
Administrative class to keep track of the version number.

Factories

Each factory has a single public method:

    public static synchronized void start();

For example the pvAccess client can be started by calling:

    org.epics.ca.ClientFactory.start();

The following factories are available:

ClientFactory
This starts the client side of the network support for pvAccess. This is the only support that needs to be started by a stand-alone client.
LocalFactory
This is called for accessing a local PVDatabase. It is also required by the ServerFactory and must be started before the server factory. An application that wants to use channel access to access the local database must start this. For example the JavaIOC starts this.
ServerFactory
This must be started in order to allow pvAccess clients to access the local PVDatabase. For example the javaIOC can start this.

CAConstants

This defines a number of constants used by the implementation. It is not of interest to users. Look at the source for details.

CAException

This is a simple extension of the Java Exception class. It is defined so that channel access specific exceptions can be thrown.

Version

This is an administrative class to keep track of the version number. See the code for details.


Package org.epics.ca.client


Overview

This package defines the client interfaces for pvAccess, which is a version of channel access that fully supports structured data as defined by PVData. It is assumed that the reader understands PVData, which is implemented by the eclipse project "org.epics.pvData".

A Channel provides a communication path beween a client and a PVRecord. A channel access server, which must reside in the same process as the PVRecord, provides access to the record. The client and server can be part of the same process or can be in different processes on the same network node or on different network nodes. Channel Access provides the connection between the client and server.

A client creates a channel via a call to ChannelProvider.createChannel. A ChannelProvider is located via a call to ChannelAccess.getProvider. ChannelAccess is located via ChannelAccessFactory.

This overview discusses:

Many of the methods described below return or have a argument Status. This is defined in project pvData as follows:

interface Status extends Serializable {
    public enum StatusType {OK,WARNING,ERROR,FATAL}
    StatusType getType();
    String getMessage();
    String getStackDump();
    boolean isOK();
    boolean isSuccess();
}

Unless isSuccess is true the client must realize that the request failed. When a failure occurs, other arguments may be null.

Example

What the example does

This section shows an example of issuing a channel get request. the example is a java main program that can be executed as follows:

java org.epics.ca.client.example.ExampleChannelGet  channelName request

For example if the arguments are:

    scalarCounter value

The output is:

structure example
{
    value = 8
}

If the arguments are:

    scalarCounter value,alarm,timeStamp

The output is:

structure example
{
    value = 5
    alarm = structure
    {
        severity = structure
        {
            index = 0
            choices = [none,minor,major,invalid]
        }
        message = null
        ackTransient = false
        ackSeverity = structure
        {
            index = 0
            choices = [none,minor,major,invalid]
        }
    }
    timeStamp = structure
    {
        secondsPastEpoch = 1253549456
        nanoSeconds = 478000000
    }
}

If the request is not given then the entire record is shown.

Example Source

main
public class ExampleChannelGet {
    public static void main(String[] args) throws CAException {
        org.epics.ca.ClientFactory.start();
        int len = args.length;
        if(len<1 || len>2 || (len==1 && args[0].equals("?"))) {
            System.out.println("Usage: channelName request");
            return;
        }
        String channelName = args[0];
        String request = null;
        if(len==2) {
            request = args[1];
        }
       
        Client client = new Client(channelName,request);
        for(int i=0; i<10; i++) {
            if(client.isDone()) break;
            try {
                System.out.println("waiting");
                Thread.sleep(1000);
            } catch (Throwable th) {
                th.printStackTrace();
            }
        }
    }

    private static final String providerName = "pvAccess";
    private static final ChannelAccess channelAccess = ChannelAccessFactory.getChannelAccess();
    private static final PVDataCreate pvDataCreate = PVDataFactory.getPVDataCreate();

The main routine first checks for valid arguments, creates an instance of Client, which is shown below, and then waits for up to ten seconds until Client has obtained data.

Implementation of channel get client
    private static class Client implements ChannelRequester, ChannelGetRequester {

        Client(String channelName,String request) {
            if(request==null) {
                pvRequest = pvDataCreate.createPVStructure(null, "example", new Field[0]);
            } else {
                pvRequest = CreateRequestFactory.createRequest(request);
            }
            channelProvider = channelAccess.getProvider(providerName);
            channelProvider.createChannel(channelName, this, ChannelProvider.PRIORITY_DEFAULT);
        }

        private ChannelProvider channelProvider = null;
        private Channel channel = null;
        private ChannelGet channelGet = null;
        private PVStructure pvStructure = null;
        private BitSet bitSet = null;
        private PVStructure pvRequest = null;
        private boolean done = false;

        boolean isDone() {return done;}

The above is the constructor and private data. The constructor creates a channel. This will result in a call to channelCreated and, if succesful, a call to channelStateChange.

ChannelRequester methods.
        public void channelCreated(Status status, Channel channel) {
            if(!status.isSuccess()) {
                message("channelCreated " + status.getMessage(),MessageType.error);
                done = true;
                return;
            }
            this.channel = channel;
        }

        public void channelStateChange(Channel c,ConnectionState connectionState) {
            if(connectionState==ConnectionState.CONNECTED) {
                this.channel = c;
                channelGet = channel.createChannelGet(this, pvRequest);
            } else {
                message(connectionState.name(),MessageType.error);
                done = true;
            }
        }

channelCreated just checks status and saves the reference to the channel. channelStateChange calls createChannelGet when the channel connects. This will result in a call to channelGetConnect .

ChannelGetRequester methods:
        public void channelGetConnect(Status status, ChannelGet channelGet,PVStructure pvStructure, BitSet bitSet) {
            if(!status.isSuccess()) {
                message("channelGetConnect " + status.getMessage(),MessageType.error);
                done = true;
                return;
            }
            synchronized(this) {
                this.channelGet = channelGet;
                this.pvStructure = pvStructure;
                this.bitSet = bitSet;
            }
            channelGet.get(true);
        }

        public void getDone(Status status) {
            if(!status.isSuccess()) {
                message("getDone " + status.getMessage(),MessageType.error);
                done = true;
                return;
            }
            message(pvStructure.toString(),MessageType.info);
            done = true;
        }

channelGetConnect issues a get request, specifying that it is the last request. A client can issue multiple get requests for each ChannelGet but for a particular channelGet a new get request must not be issued until getDone is called. getDone is called as a result of a get request.

Requester methods:
        public String getRequesterName() {
            return "example";
        }

        public void message(String message, MessageType messageType) {
            if(messageType!=MessageType.info) {
                System.err.println(messageType.toString() + " " + message);
            } else {
                System.out.println(message);
            }
        }

    }
}

These two methods are defined by project pvData.

Starting Channel Access

Before using channel access, the appropriate support must be started. Each support is started by calling the start method of a factory that starts the support. For example the client side of network based channel access is started by calling:

    org.epics.ca.ClientFactory.start();

Package org.epics.ca provides the following factories:

ClientFactory
This starts the client side of the network support for pvAccess. This is the only support that needs to be started by a stand-alone client. The example shown in the previous section calls this.
LocalFactory
This is called for accessing a local PVDatabase. It is also required by the ServerFactory and must be started before the server factory. An application that wants to use channel access to access the local database must start this. For example the JavaIOC starts this.
ServerFactory
This must be started in order to allow pvAccess clients to access the local PVDatabase. For example the javaIOC can start this.

The javaIOC provides factories for starting the gateway code between caV3 and pvAccess. The factories are located in package org.epics.ioc.caV3 and are named:

ClientFactory
The code that allows a pvAccess client to commuinicate with an epiocs V3 IOC.
ServerFactory
The code that allows an epics V3 channel access client to access the local PVDatabase.

ChannelAccess, and ChannelProvider

In order to connect to a channel a client must:

  1. Call ChannelAccessFactory to get the ChannelAccess interface.
  2. Call ChannelAccess to get a ChannelProvider.
  3. Call channelProvider to create a Channel.

A client must know the channel name and the name of the channel provider. For PVData the channel name is just a record name. This project (CAJv4) implements the following channel providers: local and pvAccess. The javaIOC eclipse project provides support for version 3 channel access. See it for details.

ChannelAccessFactory

Class org.epics.ca.client.ChannelAccessFactory has the following public methods:

public class ChannelAccessFactory {
    public static ChannelAccess getChannelAccess();
    public static void registerChannelProvider(ChannelProvider channelProvider);
}

where

getChannelAccess
Gets the ChannelAccess interface described next.
registerChannelProvider
Registers a channel provider. Typical providers are local, pvAccess and caV3. This is called by channel providers not by user code.

ChannelAccess

interface ChannelAccess {
    ChannelProvider getProvider(String providerName);
    String[] getProviderNames();
}

where

getProvider
Get the provider with the specified name. A null is returned if no provider with that name has been registered.
getProviderNames
Get the names of all the registered providers.

ChannelProvider

interface ChannelProvider {
    static final public short PRIORITY_MIN = 0;
    static final public short PRIORITY_MAX = 99;
    static final public short PRIORITY_LINKS_DB = PRIORITY_MAX;
    static final public short PRIORITY_ARCHIVE = (PRIORITY_MAX + PRIORITY_MIN) / 2;
    static final public short PRIORITY_OPI = PRIORITY_MIN;

    void destroy();
    String getProviderName();
    ChannelFind channelFind(String channelName,ChannelFindRequester channelFindRequester);
    void createChannel(String channelName, channelRequester,short priority);
}

where

destroy
The channel provider will shutdown and remove all resources it is using.
getProviderName
Get the name of the provider.
channelFind
Find a channel. The details are described in this section.
createChannel
Create a channel. A Channel is described in the next section.

ChannelFind

A client can determine if a channel exists without creating a channel. The client must implement a requester interface and the implentation provides an interface that the client can use to cancel the request. The interfaces are:

interface ChannelFindRequester {
    void channelFindResult(Status status,ChannelFind channelFind,boolean wasFound);
}

interface ChannelFind {
     ChannelProvider getChannelProvider();
     void cancelChannelFind();
} 

where

channelFindResult
This is called by the implementation. It may or may not get called. For a remote call it is normally called only if the channel is found. A local provider will usually call it immediately and report if it has the requested channel. Thus this can be called before the channelFind method returns.
getChannelProvider
Get the channel provider.
cancelChannelFind
Cancel the find request.

Channel

The Channel interface provides access to the services a channel access provider implements for a channel. The principal services are: process, get, put, putGet,array, and monitor. Each of these and some other services are described in later sections of this package overview.

As described in the previous section a Channel is created via a call to the method:

    ChannelProvider.createChannel(String channelName,ChannelRequester channelRequester)

The caller must implement the interface:

interface ChannelRequester extends Requester {
    void channelCreated(Status status,Channel channel);
    void channelStateChange(Channel c,ConnectionState connectionState);
    void destroy(Channel c);
}

where

Requester
This is defined in package org.epics.pvdata.pv. It has two methods: getRequesterName and message.
channelCreated
This is called when a channel has been created. The argument provides the channel unless status was not success.
channelStateChange
A channel connection state change has occured. This called the first time when a channel has been created and connected to a server.
destroy
This is called if the channel is being terminated for some reason. The requester will no longer be able to make requests of the channel.

The Channel interface is:

interface Channel extends Requester{
    public enum ConnectionState {
         NEVER_CONNECTED, CONNECTED, DISCONNECTED, DESTROYED
    };

    ChannelProvider getProvider();
    String getRemoteAddress();
    ConnectionState getConnectionState();
    void destroy();
    String getChannelName();
    ChannelRequester getChannelRequester();
    boolean isConnected();
    AccessRights getAccessRights(PVField pvField);
    void getField(GetFieldRequester requester,String subField);
    ChannelProcess createChannelProcess(
        ChannelProcessRequester channelProcessRequester,
        PVStructure pvOption);
    ChannelGet createChannelGet(
        ChannelGetRequester channelGetRequester,
        PVStructure pvRequest);
    ChannelPut createChannelPut(
        ChannelPutRequester channelPutRequester,
        PVStructure pvRequest);
    ChannelPutGet createChannelPutGet(
        ChannelPutGetRequester channelPutGetRequester,
        PVStructure pvRequest);
    ChannelRPC createChannelRPC(
        ChannelRPCRequester channelRPCRequester,
        PVStructure pvRequest);
    ChannelArray createChannelArray(
        ChannelArrayRequester channelArrayRequester,
        PVStructure pvRequest);
    Monitor createMonitor(
        MonitorRequester MonitorRequester,
        PVStructure pvRequest);
}

where

getProvider
Get the provider.
getRemoteAddress
Get the network address of the server.
destroy
Destroy the channel and all resources used by the channel.
getChannelName
The name of the channel. For cav4 this is the name if the PVRecord.
getChannelRequester
Get the channel requester. This is normally called by the implementation rather than the client.
isConnected
Is the channel connected?
getAccessRights
Get the access rights for the channel.

The remaining methods are described in later sections of this package overview.

AccessRights

Access Rights are not currently implemented.

enum AccessRights {
    none,
    read,
    readWrite
}

GetField

MATEJ There is no way to cancel the request.

The method:

    Channel.getField(GetFieldRequester requester,String subField);

Gets the introspection interface for the specified sub field of the record it which the channel is connected. The subField can be null, which means get the introspection interface for the entire record, or is of the form "name.name..." . Thus it can be a request for any field within a record. The requester must implement the interface:

interface GetFieldRequester extends Requester {
    void getDone(Status status,Field field);
}

where

getDone
A getField request has finished. A null is returned if the request fails. If the request succeeds Field is the introspection interface.

ChannelRequest

Many of the interfaces described in later sections extend the following interface.

interface ChannelRequest extends Destroyable {}

where Destroyable has the single method:

destroy
Destroy whatever the extended interface implements. It will free all resources it uses.

Many of the interface described in the later sections are created via a create call that has as one of it's arguments:

       PVStructure pvRequest

A request structure is defined in package org.epics.ioc.pvCopy but, for convenience part is repeated here.

PVStructure pvRequest

This is a PVStructure that describes the fields and options in PVRecord that are to be accessed. The format is defined by org.epics.pvData.pvCopy. See the package overview for details.

CreateRequestFactory.createRequest

This package provides the following factory:

class CreateRequestFactory {
    public static PVStructure createRequest(String request,Requester requester);
}

This creates a request structure. See the package documentation for org.epics.iov.pvCopy/package.html for a detailed description.A few examples are repeaed here.

Examples

The following examples are for either a simple record or for a power supply record. These are records that have one of the following structures:

simpleRecord
    value
    alarm
    timeStamp
    display
    .. other fields like input, etc

powerSupply
    alarm
    timeStamp
    power
       value
       alarm
       .. other fields
    voltage
       value
       alarm
       .. other fields
    current
       value
       alarm
       .. other fields
    .. other fields
Simple example

The following creates a request for three fields: alarm, timeStamp, and power.value

    PVStructure pvRequest = CreateRequestFactory.createRequest("alarm,timeStamp,power.value");

The PVStructure holding data for the requester will have the structure:

 pvData
     alarm           // from record.alarm
     timeStamp       // from record.timeStamp
     value           // from record.value

Note that if the actual record does not have a requested field than that field will not be present in the structure returned to the client.

Power Supply Example

The following creates a request for alarm, timeStamp, power, current, and voltage. Power, current, and voltage will each be a structure with two fields: value and alarm.

    PVStructure pvRequest = CreateRequestFactory.createRequest(
       "alarm,timeStamp"
       + ",power{power.value,power.alarm}"
       + ",current{current.value,current.alarm}"
       + ",voltage{voltage.value,voltage.alarm}");

The resulting structure that appears to the client has the form:

pvData
   alarm          // from record.alarm
   timeStamp      // from record.timeStamp
   power          // appears because of pvRequest
      value       // from record.power.value
      alarm       // from record.power.alarm
   current        // appears because of pvRequest
      value       // from record.current.value
      alarm       // from record.current.alar.
   voltage        // appears because of pvRequest
      value       // from record.voltage.value
      alarm       // from record.voltage.alarm

ChannelProcess

A ChannelProcess is created via a call to:

interface Channel extends Requester{
   ChannelProcess createChannelProcess(
       ChannelProcessRequester channelProcessRequester);
}

The requester must implement the interface:

interface ChannelProcessRequester extends Requester {
    void channelProcessConnect(Status status,ChannelProcess channelProcess);
    void processDone(Status status);
}

where

channelProcessConnect
This returns the interface for requesting that a record be processed. Status is the result for the create request. channelProcess is null if status is not success.
processDone
This is called when a process request is done. Status is the result for the process request.

The following is the interface for requesting that a record be processed.

interface ChannelProcess extends ChannelRequest {
    void process(boolean lastRequest);
}

where

process
Process the record. If lastRequest is true than it is a one time request, i.e. it is the same as calling destroy after the process is complete. Another process request must not be issued until processDone is called.

ChannelGet

A ChannelGet is created via a call to:

interface Channel extends Requester{
    ChannelGet createChannelGet(ChannelGetRequester channelGetRequester,PVStructure pvRequest);
}

where

channelGetRequester
Described next.
pvRequest
This was described in a previous section. BUT for channelGet the request string for CreateRequestFactory.createRequest has the form: "record[options]field(fieldOptions)". An example of a record options is "process=true". The fieldOptions are as defined by pvCopy.

The requester must implement the interface.

interface ChannelGetRequester extends Requester {
    void channelGetConnect(Status status,ChannelGet channelGet,PVStructure pvStructure,BitSet bitSet);
    void getDone(Status status);
}

where

channelGetConnect
This is called if the createProcess fails or when the client request is connected to the server. Status provides the result of the createChannel request. If status is not success than the other arguments are null. channelGet is the interface for requesting gets. All data will be returned in pvStructure. bitSet shows which fields have new data. If a bit of bitSet is set for a structure field that means that all fields of the structure have new values. For example of bit 0 of bitSet is set then all fields of pvStructure have new data. Note that each PVField implements a method getFieldOffset(). this can be used with bitSet to determine which fields have new data values. See BitSet and PVField in org.epics.pvData for details.
getDone
The get request is done. status provides the result of the get request. If successful the pvStructure and bitSet returned by the call to channelGetConnect contain the data.

The following is the interface for requesting data from a record.

interface ChannelGet extends ChannelRequest {
    void get(boolean lastRequest);
}

where

get
Get data. If lastRequest is true than it is a one time request, i.e. it is the same as calling destroy after the get is complete. Another get request must not be issued until getDone is called.

ChannelPut

A ChannelPut is created via a call to:

interface Channel extends Requester{
    ChannelPut createChannelPut(ChannelPutRequester channelPutRequester,PVStructure pvRequest);
}

where

channelPutRequester
Described next.
pvRequest
This was described in a previous section. BUT for channelPut the request string for CreateRequestFactory.createRequest has the form: "record[options]field(fieldOptions)". An example of a record options is "process=true". The fieldOptions are as defined by pvCopy.

The requester must implement the interface.

interface ChannelPutRequester extends Requester {
    void channelPutConnect(Status status,ChannelPut channelPut,PVStructure pvStructure,BitSet bitSet);
    void putDone(Status status);
    void getDone(Status status);
}

where

channelPutConnect
This is called if the createChannelPut fails or when the client request is connected to the server. Status provides the result of the createChannelPut request. If status is not success than the other arguments are null. channelPut is the interface for requesting puts and gets. The caller puts data into pvStructure pvStructure and sets bits in bitSet to shows which fields have new data before making a put request. If a bit of bitSet is set for a structure field that means that all fields of the structure have new values. For example of bit 0 of bitSet is set then all fields of pvStructure have new data. Note that each PVField implements a method getFieldOffset(). this can be used with bitSet to determine which fields have new data values. See BitSet and PVField in org.epics.pvData for details.
putDone
The put request is done. status provides the result of the put request.
getDone
The get request is done. status provides the result of the put request.

The following is the interface for requesting data from a record.

interface ChannelPut extends ChannelRequest {
    void put(boolean lastRequest);
    void get();
}

where

put
Put data. If lastRequest is true than it is a one time request, i.e. it is the same as calling destroy after the put is complete.
get
Get the current data from the record. The record is never processed. The request just gets the current values which is put into the pvStructure returned in the call to channelPutConnect.
NOTE: Only one of put and get can be outstanding at the same time. Another get or put must not be issued until getDone or putDone is called.

ChannelPutGet

A channelPutGet request puts data into a record, optionally processes the record, and gets data from the record.

A channel putGet is created via a call to:

ChannelPutGet createChannelPutGet(ChannelPutGetRequester channelPutGetRequester,PVStructure pvRequest);
}

where

channelPutGetRequester
Described next.
pvPutRequest
This was described in a previous section. BUT for channelPutGet the request string for CreateRequestFactory.createRequest has the form: "record[process=true]putField(fieldOptions)getField(fieldOptions)". An example of a record options is "process=true". The fieldOptions are as defined by pvCopy.

The requester must implement the interface.

interface ChannelPutGetRequester extends Requester {
    void channelPutGetConnect(Status status,ChannelPutGet channelPutGet,
            PVStructure pvPutStructure,PVStructure pvGetStructure);
    void putGetDone(Status status);
    void getPutDone(Status status);
    void getGetDone(Status status);
}

where

channelPutGetConnect
This is called if the createChannelPutGet fails or when the client request is connected to the server. Status provides the result of the createChannelPutGet request. If status is not success than the other arguments are null. channelPutGet is the interface for requesting putGet, getPut and getGet. pvPutStructure holds the put data and pvGetStructure holds the get data.
putGetDone
The putGet request is done.
getPutDone
The getPut request is done.
getGetDone
The getGet request is done.

The following is the interface for requesting data from a record.

interface ChannelPutGet extends ChannelRequest {
    void putGet(boolean lastRequest);
    void getPut();
    void getGet();
}

where

putGet
First put the pvPutStructure data into the record. Then if process is true process the record. Finally get data from the record and put it into pvGetStructure. If lastRequest is true than it is a one time request, i.e. it is the same as calling destroy after the putGet is complete.
getPut
Get current data from the record and put it into pvPutStructure. The record is never processed. The request just gets the current values which is put into the pvPutStructure returned in the call to channelPutGetConnect.
getGet
Get current data from the record and put it into pvGetStructure. The record is never processed. The request just gets the current values which is put into the pvGetStructure returned in the call to channelPutGetConnect.

NOTE: Only one of putGet, getPut, or getGet can be outstanding at the same time. Another request must not be issued until the appropriate xxxDone is called.

ChannelRPC

A ChannelRPC is like a putProcessGet except that a completly different PVStructure can be returned for each request. It is created via a call to:

interface Channel extends Requester{
    ChannelRPC createChannelRPC(ChannelRPCRequester channelRPCRequester,PVStructure pvRequest);
}

where

channelRPCRequester
Described next.
pvRequest
This was described in a previous section. BUT for channelRPC the request string for CreateRequest.createRequest has the form: "record[options]field(fieldOptions)". Normally no record options are entered. The fieldOptions are as defined by pvCopy.

The requester must implement the interface.

interface ChannelRPCRequester extends Requester {
    void channelRPCConnect(Status status,ChannelRPC channelRPC);
    void requestDone(Status status,PVStructure pvResponse);
}

where

channelRPCConnect
Status provides the result of the createChannelRPC request. If status is not success than the other argument is null.
requestDone
The request is done. status provides the result of the request. If successful a pvResponse is returned.

The following is the interface for requesting data from a record.

interface ChannelRPC extends ChannelRequest {
    void request(PVStructure pvArgument,boolean lastRequest);
}

where

request
pvArgument is the structure that is sent to the server. If lastRequest is true than it is a one time request, i.e. Send it is the same as calling destroy after the request is complete.

Only one request at a time can outstanding.

ChannelArray

ChannelArray provides the ability to read or write a sub-array of an array field in a record. Note that all the other transfer methods can also read or write arrays but always transfer entire arrays. ChannelArray provides the ability to transfer a subarray. A ChannelArray is created via a call to:

interface Channel extends Requester{
    ChannelArray createChannelArray(
        ChannelArrayRequester channelArrayRequester,
        PVStructure pvRequest);
}

where

channelArrayRequester
Described next.
pvRequest
This must be a PVStructure created as follows:
PVStructure pvRequest = pvDataCreate.createPVStructure(null, "", new Field[0]);
PVString pvFieldName = (PVString)pvDataCreate.createPVScalar(pvRequest, "field", ScalarType.pvString);
pvFieldName.put(subField);
pvRequest.appendPVField(pvFieldName);

The requester must implement the interface.

interface ChannelArrayRequester extends Requester {
    void channelArrayConnect(Status status,ChannelArray channelArray,PVArray pvArray);
    void putArrayDone(Status status);
    void getArrayDone(Status status);
}

where

channelArrayConnect
This is called if the createChannelArray fails or when the client request is connected to the server. Status provides the result of the createChannelArray request. If status is not success than the other arguments are null. channelArray is the interface for requesting puts and gets. pvArray holds the data to put or get.
putArrayDone
The put request is done.
getArrayDone
The get request is done.

The following is the interface for getting or putting array data from a record.

interface ChannelArray extends ChannelRequest{
    void putArray(boolean lastRequest, int offset, int count);
    void getArray(boolean lastRequest, int offset, int count);
}

where

putArray
Put array data. The offset is the offset in the server and the count is the total number of elements to write. If lastRequest is true than it is a one time request, i.e. it is the same as calling destroy after the put is complete.
getArray
Get array data. The offset is the offset in the server and the count is the total number of elements to read. If lastRequest is true than it is a one time request, i.e. it is the same as calling destroy after the get is complete.

Monitor

Monitor provides the abiliy to set monitors on data in a PVRecord. What triggers a monitor depends on the monitor support in the server. The standard server provides support for the following: onPut, onChange, onAbsoluteChange, and onPercentChange.

A Monitor is created via a call to:

    void createMonitor(
        MonitorRequester monitorRequester,
        PVStructure pvRequest);
}

where

monitorRequester
Described next.
pvRequest
This is defined by pvCopy and pvMonitor. See their package overviews for details (org.epics.pvData.pvCopy and org.epics.pvData.pvMonitor). The format of the request for CreateRequest.createRequest has the form "record[options]field(fieldOptions)". Note that you can specify monitor options for individual fields. See the package overview for pvMonitor for details.

The requester must implement the interface.

interface MonitorRequester extends Requester{
    void monitorConnect(Monitor monitor);
    void monitorEvent((Monitor monitor);
    void unlisten();
}

where

monitorConnect
This is called if the createMonitor fails or when the client request is connected to the server. Status provides the result of the createMonitor request. If status is not success than the other arguments are null. monitor is the interface for the Monitor
monitorEvent
monitorEvent is called when a monitor occurs. The client must call monitor.poll to get data for the monitor. See below.
unlisten
The server has issued an unlisten request.

The following is the Monitor interface which is defined in project pvData

interface Monitor extends Destroyable {
    void start();
    void stop();
    MonitorElement poll();
    void release(MonitorElement monitorElement);
}

where

start
Start monitoring
stop
Stop monitoring
poll
Poll for monitor event. Null is returned when no more events are available. The client must call this method in order to get monitor data.
release
When the client has processed the monitor event returned by poll the client must call release before again calling poll.

A monitorElement is defined as:

interface MonitorElement {
    PVStructure getPVStructure();
    BitSet getChangedBitSet();
    BitSet getOverrunBitSet();
}

where

getPVStructure
The data structure.
getChangedBitSet
A bitset which has a bit set for each field of the data structure which has changed since the last monitor.
getOverrunBitSet
A bitset which has a bit set for each field of the data structure which has changed more than once since the last monitor.

Package org.epics.ca.server


Overview

This package defines the server interfaces for pvAccess, which is the version of channel access that fully supports structured data as defined by PVData. This package describes:

Channel Processor
An application that uses the pvAccess server to make a local PVDatabase available to the network can implement support for processing records, i.e. implement support for the process option of the various Channel.createChannelXXX methods. For example the javaIOC imnplements this by interfacing pvAccess to the RecordProcess facility implemented by the javaIOC.
Channel Server
The ChannelServer interface is described.
Server Context
The ServerContext implemented by pvAccess is described.

Channel Processor

Three interfaces are involved with support for a client asking that a record be processed. ChannelProcessor and ChannelProcessorProvider are implemented by the application, e. g. the javaIOC. ChannelProcessorRequester is implemented bu pvAccess.

ChannelProcessor, which is attached to a specific PVRecord, is defined as:

interface ChannelProcessor {
    void detach();
    void requestProcess();
    void process(boolean leaveActive,TimeStamp timeStamp);
    void setInactive();
}

where

detach
End of being a channel processor.
requestProcess
Request to process. ChannelProcessorRequester.becomeProcessor is called when the requester can call setActive and/or process.
setActive
Set the record active. This is called if the requester wants to put to the record before the record starts processing. If this is successful than the requester must call process after the put is complete.
process

Process the record. A value of false means that the request failed. If leaveActive is true the record is left active after process is complete. This allows the caller to read data from the record before the record is released.The caller must call setInactive after the caller is done reading data.

setInactive
Called if leaveActive was true.

ChannelProcessorPrivider is defined as:

interface ChannelProcessorProvider {
    ChannelProcessor requestChannelProcessor(PVRecord pvRecord,
         ChannelProcessorRequester channelProcessorRequester);
}

where

requestChannelProcessor
Request to become record processor. A null is returned if the caller could not become the record processor.

ChannelProcessorRequester is defined as:

interface ChannelProcessorRequester extends Requester{
    void becomeProcessor();
    void canNotProcess(String reason);
    void recordProcessResult(Status status);
    void recordProcessComplete();
    void lostRightToProcess();
}

where

becomeProcessor
Called as a result of a call to requestProcess.
canNotProcess
A request was made to become processor but record can not be processed.
recordProcessResult
Called to report result of record processing. This is called before the record is unlocked.
recordProcessComplete
Called when all processing is complete and record is unlocked.
lostRightToProcess
The process requester has lost the right to request processing.

Channel Server

This is an interface implemented by local server:

interface ChannelServer extends ChannelProvider{
    void registerMonitor(MonitorCreate monitorCreate);
    boolean registerChannelProcessProvider(
        ChannelProcessorProvider channelProcessProvider);
}

where

registerMonitor
register a monitor algorithm.
registerChannelProcessProvider
Register the ChannelProcessProvider.

Server Context

This is an interface implemented by pvAccess server:

interface ServerContext {
    Version getVersion();
    void initialize(ChannelAccess channelAccess) throws CAException, IllegalStateException;
    void run(int seconds) throws CAException, IllegalStateException;
    void shutdown() throws CAException, IllegalStateException;
    void destroy() throws CAException, IllegalStateException;
    void printInfo();
    void printInfo(PrintStream out);
    void dispose();
    void setBeaconServerStatusProvider(BeaconServerStatusProvider beaconServerStatusProvider);
}

where

getVersion
x
initialize
x
run
x
shutdown
x
destroy
x
printInfo
x
dispose
x
setBeaconServerStatusProvider
x