EPICS pvAccessJava
Release 4.0.2, 10-Nov-2014
- Editors:
- Marty Kraimer, BNL
Matej Sekoranja, CosyLab
Abstract
pvAccessJava is the Java implementation of pvAccess, which is one of a
related set of products:
relatedDocumentsV4.html
Status of this Document
This is the 10-Nov-2014 version of the Java implementation of pvAccess. It is a complete implementation of pvAccess as currently defined.
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.
This project also implements client code that uses the Channel Access network protocol to communicate with servers. It converts between the DBR ChannelAccess data and pvData so that the client only sees pvData.
If your only interest is to write client code then look at the example in the next section and then go directly to Pachkage org.epics.pvaccess.client in this document.
This project provides the client and server network support 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:
- 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().
- 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.
- A gateway between pvAccess and other systems can be implemented.
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 = ChannelProviderRegistryFactory.getChannelProviderRegistry() .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); CreateRequest createRequest = CreateRequest.create(); PVStructure pvRequest = createRequest.createRequest(pvRequestString); if(pvRequest==null) { String message = "createRequest failed " + createRequest.getMessage(); logger.info(message); } else { channel.createChannelGet(channelGetRequester,pvRequest); // 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; } public String getRequesterName() { return getClass().getName(); } public void message(String message, MessageType messageType) { logger.log(LoggingUtils.toLevel(messageType), message); } public void channelCreated(Status status, Channel channel) { logger.info("Channel '" + channel.getChannelName() + "' created with status: " + status + "."); } 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; } public String getRequesterName() { return getClass().getName(); } public void message(String message, MessageType messageType) { logger.log(LoggingUtils.toLevel(messageType), message); } public void channelGetConnect(Status status, ChannelGet channelGet,Structure structure { logger.info("ChannelGet for '" + channel.getChannelName() + "' connected with status: " + status + "."); if (status.isSuccess()) { this.pvStructure = pvStructure; channelGet.get(true); } else doneSignaler.countDown(); } public void getDone(Status status, PVStructure pvStructure, BitSet changedBitSet)s { logger.info("getDone for '" + channel.getChannelName() + "' called with status: " + status + "."); if (status.isSuccess()) { 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.
The implementation above issues actual get request on success by calling
"channelGet.get()".
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.
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 client and server that use the pvAccess network protocol to communicate between client and server.
- 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.
A client normally only needs to start the channelProvider as follows:
org.epics.pvaccess.ClientFactory.start();
This starts the channelProvider that uses the pvAccess network protocol. The name of the provider is pva.
For starting servers see package overview below for details.
org.epics.ca
This provides an implementation of ChannelProvider that uses the Channel Access network protocol instead of the pvAccess network protocol. It converts between DBR data and pvData. It has a ClientFactory that has methods start and stop.
A client starts the channelProvider as follows:
org.epics.ca.ClientFactory.start();
The name of the provider is ca.
The channelProvider implements ChannelGet, ChannelPut, ChannelArray, and Monitor. It does not implement ChannelProcess, ChannelPutGet, or ChannelRPC.
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.
To connect to a channel a client does the following:
// get wanted channel provider ChannelProvider channelProvider = ChannelProviderRegistryFactory.getChannelProviderRegistry().getProvider("pva"); // 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 communicate 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.
Except for ChannelAccessFactory and CreateRequest, this package contains only Java interface and enum definition.
Package org.epics.pvaccess
Overview
This package provides:
- Factories
- ClientFactory and ServerFactory
- PVAConstants
- A set of constants used by the pvAccess implementation.
- PVAException
- A extension of Exception for pvAccess.
- PVFactory
- A convenience class for accessing pvData facilities.
- Version
- Administrative class to keep track of the version number.
Factories
Each factory has a 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.
The ClientFactory has a public method:
org.epics.pvaccess.ClientFactory.stop();
PVAConstants
This defines a number of constants used by the implementation. It is not of interest to users. Look at the source for details.
PVAException
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 package "org.epics.pvdata".
A Channel provides a communication path between 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.
This overview discusses:
- How to connect to a channel provider.
- An overview of all the client interfaces.
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.
ChannelProviderRegistry, and ChannelProvider
In order to connect to a channel a client must:
- Call ChannelProviderRegistryFactory.getChannelProviderRegistry().getProvider(String providerName) to get a ChannelProvider.
- Call ChannelProvider.createChannel(String channelName, ...) to create a Channel.
A client must know the channel name and the name of the channel provider.
ChannelProviderRegistry
Class org.epics.pvaccess.client.ChannelAccessFactory has the following public methods:
interface ChannelProviderRegistry { ChannelProvider getProvider(String providerName); ChannelProvider createProvider(String providerName); String[] getProviderNames(); }
where
- getProvider
- This gets the requested provider.Two providers are registered automatically: pva, which uses the pvAccess network protocol, and ca, which uses the Channel Access network protocol.
- createProvider
- This registers a ChannelProvider. Usually user code does not call this, e.g. it is called via code that implements the ChannelProvider interface.
- getProviderNames
- Returns the names of the providers that have been created.
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); ChannelFind channelList( ChannelListRequester channelListRequester); 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 implementation 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 occurred. 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 pvRequest); 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.
Many of the interface described in the later sections are created via a create call that has as one of it's arguments:
PVStructure pvRequestSee pvDataJava for a description of pvRequest.
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 Lockable, Destroyable { Channel getChannel(); void cancel(); void lastRequest();
where
- destroy
- Destroy whatever the extended interface implements. It will free all resources it uses.
- getChannel
- Get the channel instance to which this request belongs.
- cancel
- Cancel the current request.
- lastRequest
- The next request will be the last request.
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, ChannelProcess channelProcess); }
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(); }
where
- process
- Process the record. 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 createRequest.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, Structure structure); void getDone( Status status, ChannelGet channelGet, PVStructure pvStructure, BitSet bitSet); }
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. structure is the introspection interface for data that is returned to getDone.
- getDone
- The get request is done. status provides the result of the get request. If successful the pvStructure and bitSet contain the data returned as a result of a get request. 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.
The following is the interface for requesting data from a record.
interface ChannelGet extends ChannelRequest { void get(); }
where
- get
- Get data. 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 createRequest.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, Structure structure); void putDone( Status status, ChannelPut channelPut); void getDone( Status status, ChannelPut channelPut, PVStructure pvStructure, BitSet bitSet); }
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. Structure is the introspection interface that must be used for data that is put to the server or that is returned by a get request.
- 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. pvStructure has the data returned from the server. 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.
The following is the interface for requesting data from a record.
interface ChannelPut extends ChannelRequest { void put(PVStructure pvPutStructure, BitSet bitSet); void get(); }
where
- put
- Put data. pvPutStructure is the data to send to the server, bitSet determines which fields are sent.
- 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.
- pvRequest
- This was described in a previous section. BUT for channelPutGet the request string for createRequest.createRequest has the form: "record[...]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, Structure putStructure, Structure getStructure); void putGetDone( Status status, ChannelPutGet channelPutGet, PVStructure getPVStructure, BitSet getBitSet); void getPutDone( Status status, ChannelPutGet channelPutGet, PVStructure putPVStructure, BitSet putBitSet); void getGetDone( Status status, ChannelPutGet channelPutGet, PVStructure getPVStructure, BitSet getBitSet); }
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. putStructure is the introspection interface that is used for data sent by the client and getStructure the introspection interface for data received by the client.
- putGetDone
- The putGet request is done. If status is not success then the other arguments may be null. getPVStructure is the data returned to the client and getBitSet shows which fields have changed value since the last putGet request.
- getPutDone
- The getPut request is done. If status is not success then the other arguments may be null. putPVStructure is the data returned to the client and putBitSet shows which fields have changed value since the last getPut request.
- getGetDone
- The getGet request is done. If status is not success then the other arguments may be null. getPVStructure is the data returned to the client and getBitSet shows which fields have changed value since the last getGet request.
The following is the interface for requesting data from a record.
interface ChannelPutGet extends ChannelRequest { void putGet(PVStructure pvPutStructure, BitSet putBitSet); 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.
- getPut
- Get current put data from the record and put it into pvPutStructure. The record is never processed.
- getGet
- Get current data from the record and put it into pvGetStructure. The record is never processed.
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 completely 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, ChannelRPC channelRPC, 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); }
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:
CreateRequest createRequest = CreateRequest.create(); PVStructure pvRequest = createRequest.createRequest("subField"); if(pvRequest==null) { String message = createRequest.getMessage(); // take drastic action }
subField is the full path name to the desired field. For example "value" selects a top level field named value.
The requester must implement the interface.
interface ChannelArrayRequester extends Requester { void channelArrayConnect( Status status, ChannelArray channelArray, Array array); void putArrayDone( Status status, ChannelArray channelArray); void getArrayDone( Status status, ChannelArray channelArray, PVArray pvArray); void getLengthDone( Status status, ChannelArray channelArray, int length, int capacity); void setLengthDone( Status status, ChannelArray channelArray); }
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. array is the interface for the data that transfered between client and server.
- putArrayDone
- The put request is done.
- getArrayDone
- The get request is done. pvArray holds the data.
- getLengthDone
- The getLength request is done. length and capacity hold the result.
- setLengthDone
- The setLength request is done.
The following is the interface for getting or putting array data from a record.
interface ChannelArray extends ChannelRequest{ void putArray( PVArray putArray, int offset, int count, int stride); void getArray( int offset, int count, int stride); void getLength(); void setLength( int length); }
where
- putArray
- Put array data. The offset and stride are the offset and stride in the server and the count is the total number of elements to write.
- getArray
- Get array data. The offset and stride are the offset and stride in the server and the count is the total number of elements to read.
- getLength
- Get the current length and capacity of the array in the server.
- setLength
- Set the length and capacity of the array in the server.
Monitor
Monitor provides the ability 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(Status status, Monitor monitor, Structure structure)); 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
- The result of the createMonitor request. If status is not success than the other arguments are null.
- monitor
- The interface for the Monitor.
- structure
- The introspection interface for the data that will be returned for each monitor event.
- 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 { Status start(); Status 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.
Problems and Future Plans
Access Security
Something like how CA implements access security is required. A complication is that for CA a client attaches to a single scalar or array field. For pvAccess a client attaches to an arbitrary 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.
- PVAConstants
- A set of constants for pvAccess
- PVAException
- 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.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(ChannelProviderRegistry channelAccess) throws PVAException; void initialize(ChannelAccess channelAccess) throws PVAException, IllegalStateException; void run(int seconds) throws PVAException, IllegalStateException; void shutdown() throws PVAException, IllegalStateException; void destroy() throws PVAException, 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 destroy 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();