EPICS pvAccessJava

EPICS v4 Working Group, Working Draft, 05-Sep-2012

This version:
pvAccessJava_20120905.html
Latest version:
pvAccessJava_20120905.html
Editors:
Marty Kraimer, BNL
Matej Sekoranja, CosyLab

Abstract

pvAccessJava is the Java implementation of pvAccess, which is one of a related set of products:

pvData
pvData (Process Variable Data) defines and implements an efficent way to store, access, and transmit memory resident structured data
pvAccess
pvAccess is network support for transmitting pvData.
pvIOC
A pvIOC is a network accessable smart real time database. The database consists of memory resident records. Each record has a name that is unique within the local area network and contains a top level pvData structure. Each field of a record can optionally have support code attached to it. The support is called when a request is made to process the record. The support code is what makes the record "smart". A pvAccess server is provided so that the records can be accesed via the network.
pvService
A middle layer for implementing services.

Each of the products has a Java and a C++ implementation.

The products are all part of the V4 implementation of Experimental Physics and Industrial Control System.

Status of this Document

This is the 05-Sep-2012 version of the Java implementation of pvAccess. It is a complete implementation of pvAccess as currently defined.

TODO

The following is a list of unresolved issues for pvAccessJava:

(none)
(none)

Table of 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.pvaccess.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.pvaccess.client

This project provides the client and server networking spport for the interfaces defined in org.epics.pvaccess.client. The pvIOCJava provides a local implementation of pvAccess API, which registers itself with the server support provided by this project. Other implementations 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.pvaccess.LocalFactory.start(), and calling org.epics.pvaccess.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.pvaccess.server.ChannelServer.
  3. A gateway between pvAccess and other systems can be implemented. For example projects pvAccessJava and pvIOCJava provide gateway code between caV3 and pvAccess. pvAccessJava (see package org.epics.caV3) allows pvAccess client to talk to a caV3 server, pvIOCJava (see package org.epics.pvioc.caV3) allows caV3 client to talk to a pvAccess server.

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 pvAccess API or any of its related interfaces because they are described in the package overview for org.epics.pvaccess.client.

org.epics.pvaccess

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 pvAccess data source. For example the pvIOCJava (PVDatabase) can start this.

org.epics.pvaccess.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();

    // get wanted channel provider 
    ChannelProvider channelProvider = channelAccess.getProvider("pvAccess");

    // connect to a channel with given name
    Channel channel = channelProvider.createChannel(
                                         "someChannel",
                                         channelRequester,
                                         ChannelProvider.PRIORITY_DEFAULT);

This package defines the interfaces a client uses to comnmunicate with a pvAccess server. This project fully implements 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 pvIOCJava does not support ChannelPutGet because an EPICS V3 IOC does not provide an equivalent facility.

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

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

where

getChannelAccess
This gets the single instance of ChannelAccess
registerChannelProvider
This registers a ChannelProvider. Usually user code does not call this, e.g. it is called via the factories in org.epics.pvaccess
unregisterChannelProvider
This unregisters a ChannelProvider. Usually user code does not call this, e.g. it is called via the factories in org.epics.pvaccess

ChannelAccess is defined as:

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

where

getProvider
Get the channel provider.
getProviderNames
Get the names of all regsitered providers.

ChannelProvider has a method (among others):

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.

Problems and Future Plans

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.

Helper Packages

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

org.epics.pvaccess

This has the following:

ClientFactory
Starts the client side of remote pvAccess.
ServerFactory
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.
PVFactory
Factory proxy for all the standard pvData factories used by pvAccess.

org.epics.pvaccess.util.logging

A logging facility based on java.util.logging. This has the following:

LoggerProvider
Defines an interface that provides a logger.
LoggingUtils
Contains various logging helper methods, e.g. mapping from pvData MessageType to Java Logging API Level.
ConsoleLogFormatter
Java API formatter that produces single line log reports meant to go to the console.
ConsoleLogHandler
Java API log handler output logs to the System.out. By default it uses ConsoleLogFormatter.

To setup a simple logging in you console application, use the following code:

        ConsoleLogHandler.defaultConsoleLogging(Level.INFO);
        Logger logger = Logger.getLogger(MyApplicationClass.class.getName());

        ...
        logger.info("Hello world.");

Implementation Packages

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

org.epics.pvaccess.util

This has the following:

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.
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.
Mailbox
Optimized usage of concurrent linked list queue.
ShortHashMap
A short hash map. This is used instead of java.util.HashMap so that Short objects do not have to be allocated.

org.epics.pvaccess.util.sync

This package contains thread synchronization utility classes, e.g. named lock pattern implementation (lock guarding a named instance).

org.epics.pvaccess.util.configuration

This package defines interfaces for configuration framework used by pvAccess.

org.epics.pvaccess.util.configuration.impl

This package implements default configuration method for pvAccess.

org.epics.pvaccess.impl.remote

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

org.epics.pvaccess.impl.remote.codec

This package implement pvAccess protocol (codec) in a way that can be plugged into the blocking or non-blocking IO system.

org.epics.pvaccess.impl.remote.codec.impl

This package partly implements codec to be used by blocking or non-blocking IO system.

org.epics.pvaccess.impl.remote.io

This package currently provides interfaces of a non-blocking IO system.

org.epics.pvaccess.impl.remote.io.impl

This package contains an implementation of non-blocking IO system using Selector.

org.epics.pvaccess.impl.remote.request

This pakcage contains interfaces pvAccess uses to handle requests.

org.epics.pvaccess.impl.remote.tcp

This package contains the code that implements pvAccess codec over TCP transport.

org.epics.pvaccess.impl.remote.udp

his package contains the code that implements pvAccess codec over UDP transport.

org.epics.pvaccess.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.pvaccess.client.impl.remote

This implements the client side pvAccess API 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.pvaccess.client.impl.remote.handlers

This implements handlers for receiving responses from network requests.

org.epics.pvaccess.client.impl.remote.requests

This implements code that sends a network request.

org.epics.pvaccess.client.impl.remote.search

This implement pvAccess discovery mechanism over UDP.

org.epics.pvaccess.client.impl.remote.tcp

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

Server Implementation Packages

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

org.epics.pvaccess.server.impl.remote

This implements the server side pvAccess API 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.pvaccess.server.impl.remote.handlers

This implements handlers for receiving requests from the client.

org.epics.pvaccess.server.impl.remote.plugins

Currently has just code related to beacons. User can attach its own data to the beacon messages (e.g. to report IOC status).

org.epics.pvaccess.server.impl.remote.tcp

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

org.epics.pvaccess.server.impl.rpc

This package contains interfaces to implement a service based on pvAccess RPC mechanism.

org.epics.pvaccess.server.impl.rpc.impl

This package is the implementation of the org.epics.pvaccess.server.impl.rpc package.

Package org.epics.pvaccess

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.pvaccess.ClientFactory.start();

The following factories are available:

ClientFactory
This starts the client side pvAccess API of the network support for pvAccess. This is the only support that needs to be started by a stand-alone client.
ServerFactory
This starts the server side pvAccess API of the network support for pvAccess. For example the pvIOCJava 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.pvaccess.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.pvaccess.client.example.ExampleChannelGet <channelName> <request>

For example if the arguments are:

    counter field(value)

The output is:

2012-09-11T12:48:44.831 Channel 'counter' created with status: StatusImpl [type=OK]. 
2012-09-11T12:48:45.631 Channel 'counter' CONNECTED. 
2012-09-11T12:48:45.708 ChannelGet for 'counter' connected with status: StatusImpl [type=OK]. 
2012-09-11T12:48:45.710 getDone for 'counter' called with status: StatusImpl [type=OK]. 
structure 
    int value 1
2012-09-11T12:48:45.735 Channel 'counter' DISCONNECTED. 
2012-09-11T12:48:45.736 Channel 'counter' DESTROYED. 

If the arguments are:

    counter field(value,timeStamp,alarm)

The output is:

2012-09-11T12:51:12.113 Channel 'counter' created with status: StatusImpl [type=OK]. 
2012-09-11T12:51:12.156 Channel 'counter' CONNECTED. 
2012-09-11T12:51:12.163 ChannelGet for 'counter' connected with status: StatusImpl [type=OK]. 
2012-09-11T12:51:12.164 getDone for 'counter' called with status: StatusImpl [type=OK]. 
structure 
    int value 4
    timeStamp_t timeStamp
        long secondsPastEpoch 1347360671
        int nanoSeconds 660000000
        int userTag 0
    alarm_t alarm
        int severity 0
        int status 0
        string message 
2012-09-11T12:51:12.167 Channel 'counter' DISCONNECTED. 
2012-09-11T12:51:12.168 Channel 'counter' DESTROYED.

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 Throwable {
        
    int len = args.length;
        if (len == 0 || len > 2)
        {
            System.out.println("Usage: <channelName> <pvRequest>");
            return;
        }
        
        final String channelName = args[0];
        final String pvRequestString = args[1];
        
        // initialize console logging
        ConsoleLogHandler.defaultConsoleLogging(Level.INFO);
        Logger logger = Logger.getLogger(ExampleChannelGet.class.getName());
        logger.setLevel(Level.ALL);

        // setup pvAccess client
        org.epics.pvaccess.ClientFactory.start();

        // get pvAccess client provider
        ChannelProvider channelProvider = ChannelAccessFactory.getChannelAccess().getProvider(org.epics.pvaccess.ClientFactory.PROVIDER_NAME);
        
        //
        // create channel and channelGet
        //
        CountDownLatch doneSignal = new CountDownLatch(1);

        ChannelRequesterImpl channelRequester = new ChannelRequesterImpl(logger);
        Channel channel = channelProvider.createChannel(channelName, channelRequester, ChannelProvider.PRIORITY_DEFAULT);
        
        ChannelGetRequester channelGetRequester = new ChannelGetRequesterImpl(logger, channel, doneSignal);
        channel.createChannelGet(
channelGetRequester,
CreateRequestFactory.createRequest(pvRequestString, channelGetRequester)
);

        // wait up-to 3 seconds for completion
        if (!doneSignal.await(3, TimeUnit.SECONDS))
            logger.info("Failed to get value (timeout condition).");
        
        // stop pvAccess client
        org.epics.pvaccess.ClientFactory.stop();
    }

The main routine first checks for valid arguments, initializes console logging, creates a channel and channel get and then waits for up to 3 seconds for response.

Implementation of ChannelRequester:
    static class ChannelRequesterImpl implements ChannelRequester
    {
        private final Logger logger;
        public ChannelRequesterImpl(Logger logger)
        {
            this.logger = logger;
        }

        @Override
        public String getRequesterName() {
            return getClass().getName();
        }

        @Override
        public void message(String message, MessageType messageType) {
            logger.log(LoggingUtils.toLevel(messageType), message);
        }

        @Override
        public void channelCreated(Status status, Channel channel) {
            logger.info("Channel '" + channel.getChannelName() + "' created with status: " + status + ".");
        }

        @Override
        public void channelStateChange(Channel channel, ConnectionState connectionState) {
            logger.info("Channel '" + channel.getChannelName() + "' " + connectionState + ".");
        }
    
    }

ChannelRequester.channelCreated method gets called when channel instance is created. ChannelRequester.channelStateChange gets called on very channel state change. The implementation above just logs all the information.

Implementation of ChannelGetRequester:
    
    static class ChannelGetRequesterImpl implements ChannelGetRequester
    {
        private final Logger logger;
        private final Channel channel;
        private final CountDownLatch doneSignaler;
    
        private volatile PVStructure pvStructure = null;
   
        public ChannelGetRequesterImpl(Logger logger, Channel channel, CountDownLatch doneSignaler)
        {
            this.logger = logger;
            this.channel = channel;
            this.doneSignaler = doneSignaler;
        }

        @Override
        public String getRequesterName() {
            return getClass().getName();
        }

        @Override
        public void message(String message, MessageType messageType) {
            logger.log(LoggingUtils.toLevel(messageType), message);
        }

        @Override
        public void channelGetConnect(Status status, ChannelGet channelGet,
                                          PVStructure pvStructure, BitSet bitSet) {
            logger.info("ChannelGet for '" + channel.getChannelName() + "' connected with status: " + status + ".");
            if (status.isSuccess())
            {
                this.pvStructure = pvStructure;
                channelGet.get(true);
            }
            else
                doneSignaler.countDown();
        }

        @Override
        public void getDone(Status status) {
            logger.info("getDone for '" + channel.getChannelName() + "' called with status: " + status + ".");

            if (status.isSuccess())
            {
                // NOTE: no need to call channelGet.lock()/unlock() since we read pvStructure in the same thread (i.e. in the callback)
                System.out.println(pvStructure.toString());
            }

            doneSignaler.countDown();
        }
    }

ChannelGetRequester.channelGetConnect gets called when ChannelGet request is created on server side. Client must always check status for errors. In case of success, pvStructure is not null and it holds a reference to the data structure (container) where values will be stored on actual get request. The implementation above issues actual get request on success by calling "channelGet.get(true)". The "true" parameter indicates to self-destroy this request after get is done. If more than one get operation needs to be done, a programmer should call "channel.get(false)" as many time as needed and so reuse resources related to a get request (moreover this allows pvAccess to optimize network utilization and transfer only values that has changed since the last get request). User can always destroy a request by calling "channelGet.destroy()".
ChannelGetRequester.getDone gets called on get operation completion. On success indicated by status parameter, pvStructure holds the latest data.

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.pvaccess.ClientFactory.start();

Package org.epics.pvaccess provides the following factories:

ClientFactory
This starts the client side pvAccess API 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 starts the server side pvAccess API of the network support for pvAccess. For example the pvIOCJava can start this.

ChannelAccess, and ChannelProvider

In order to connect to a channel a client must:

  1. Call ChannelAccessFactory.getChannelAccess() to get the ChannelAccess interface.
  2. Call ChannelAccess.getProvider(String providerName) to get a ChannelProvider.
  3. Call ChannelProvider.createChannel(String channelName, ...) to create a Channel.

A client must know the channel name and the name of the channel provider.

ChannelAccessFactory

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

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

where

getChannelAccess
This gets the single instance of ChannelAccess
registerChannelProvider
This registers a ChannelProvider. Usually user code does not call this, e.g. it is called via the factories in org.epics.pvaccess
unregisterChannelProvider
This unregisters a ChannelProvider. Usually user code does not call this, e.g. it is called via the factories in org.epics.pvaccess

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);
    Channel createChannel(String channelName, ChannelRequester, short priority);
    Channel createChannel(String channelName, ChannelRequester channelRequester, short priority, String address);
}

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

This method is to be used to by local pvAccess implementations (e.g. pvAccess server queries pvIOCJava). 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, RPC, 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 channel, ConnectionState connectionState);
}

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 is called the first time when a channel has been created and connected to a server or destroyed.

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, e.g. 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

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 and status contains a reason of a failure. 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("field(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(
       "field(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:

interface Channel extends Requester {
    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 (this will be allowed in a future).

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.pvaccess.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.

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
Get server implementation version.
initialize
Force to initialize server immediately (user does not need to call this).
run
Run the server for specified amount of time (seconds), 0 stands for forever.
shutdown
Shutdown the server.
destroy
Destroy server instance.
printInfo
Print server info to the System.out.
dispose
Silently destory the server instance.
setBeaconServerStatusProvider
Set BeaconServerStatusProvider instance to be used by the server (optional).

To start pvAccess server you can simply use the following code:

org.epics.pvaccess.ServerFactory.start();