Package org.epics.ioc.ca

EPICS JavaIOC: channel Access
package: org.epics.ioc.ca
2008.02.12

See:
          Description

Interface Summary
CD CD (ChannelData).
CDArray Interface for an array field.
CDArrayArray CDNonScalarArray - A CRRecord array field that contains non-scalar elements.
CDField CDField - Data for a field of a CDRecord (Channel Data Record)
CDGet Channel put using a CD (Channel Data) to hold the data..
CDGetRequester The methods implemented by the requester for a CDPut.
CDMonitor Interface for monitoring channel data.
CDMonitorRequester  
CDPut Channel put using a CD (Channel Data) to hold the data..
CDPutRequester The methods implemented by the requester for a CDPut.
CDQueue A queue of CD (ChannelData).
CDRecord CDRecord - A record that holds a PVRecord.
CDStructure CDStructure - A CDRecord field that holds a PVStructure.
CDStructureArray CDNonScalarArray - A CRRecord array field that contains non-scalar elements.
Channel Interface for accessing a channel.
ChannelAccess Interface returned by ChannelAccessFactory.
ChannelField Interface for a field of a channel.
ChannelFieldGroup Interface for getting data from a group of fields.
ChannelFieldGroupListener Listener for field group changes.
ChannelGet Request to get data from a channel.
ChannelGetRequester Requester for a Get.get request.
ChannelListener Listener for connect state changes.
ChannelMonitor Monitor data from a channel.
ChannelMonitorNotify  
ChannelMonitorNotifyRequester Requester that monitors a channel without requesting data.
ChannelMonitorRequester Interface
ChannelProcess ChannelProcess - request that a channel be processed..
ChannelProcessRequester Callback for a channel process request.
ChannelProvider Interface for creating and destroying a channel.
ChannelPut Interface for a channel access put request.
ChannelPutGet Channel access put/get request.
ChannelPutGetRequester Requester for a putGet request.
ChannelPutRequester Requester for ChannelPut requests.
 

Class Summary
AbstractChannel Abstract class for code that implements Channel.
AbstractChannelField Abstract class for implementing ChannelField.
BaseCD Base class for CD.
BaseCDArray  
BaseCDArrayArray Base class for a CD (Channel Data) Array of Arrays.
BaseCDField Implementation of CDField.
BaseCDGet Base class for CD.
BaseCDPut Base class for CD.
BaseCDQueue Base class for a CDQueue.
BaseCDRecord Base class for a CDRecord (Channel Data Record).
BaseCDStructure Base class for a CDStructure (Channel Data Structure).
BaseCDStructureArray Base class for a CD (Channel Data) Array of Structures.
BaseChannelFieldGroup  
CDFactory A factory for creating CD and CDQueue.
CDMonitorFactory Factory that implements CDMonitor.
ChannelAccessFactory  
ChannelMonitorNotifyFactory  
ChannelProviderLocalFactory Factory and implementation of local channel access, i.e.
 

Enum Summary
AccessRights Access Rights.
 

Package org.epics.ioc.ca Description

EPICS JavaIOC: channel Access
package: org.epics.ioc.ca
2008.02.12

CONTENTS

Overview


This package contains Java definitions for Channel Access clients

A channel is an interface for acessing data. A channel is implemented by a channelProvider. An arbitrary number of channelProviders are allowed. Each channelProvider has a name and must register itself to ChannelFactory. The underlying data is presented as PVData via a ChannelField. The client can access multiple ChannelFields via a ChannelFieldGroup.

CD (ChannelData) is a facility that, given a ChannelFieldGroup, creates a PVRecord that contains a PVData for each ChannelField as well as a reference to the ChannelField.

A channelProvider must implement the following: Channel, ChannelProvider, ChannelGet, ChannelPut, ChannelPutGet, and ChannelMonitor. All other interfaces, i.e. ChannelMonitorNotify and all the CD interfaces are generic, i.e. implemented by factories provided by the package.


Channel Definitions


This section defines the interface and factory classes for connecting to a channel and creating interfaces for accessing a channel. The interfaces for accessing a channel are defined in later sections.

A channel is created via a call to ChannelFactory.create(pvName,...). The pvName can optionally consist of three components: 1) A channelName, 2) A fieldName, and 3) options. The details are provider dependent but if possible a provider should support the following syntax:

    channelName.fieldName{options}

The channelName is any set of characters not including '.'. The fieldName is all characters after the first '.' up to the optional '{'. If the '{' is present than all characters between the braces are the options. These conventions are supported by the ChannelProviderLocalFactory, which provides access to the local DB database. Other providers may optionally support the same conventions.

For a javaIOC a channelName is a recordName. This is also true for EPICS databases.

Definitions

    interface ChannelListener extends Requester {
        void channelStateChange(Channel c,boolean isConnected);
         void destroy(Channel c);
    }
    interface Channel  extends Requester {
        void connect();
        void disconnect();
        void destroy();
        String getChannelName();
        PVRecord getPVRecord();
        ChannelListener getChannelListener();
        boolean isConnected();
        String getPropertyName();
        String getFieldName();
        String getOptions();
        ChannelField createChannelField(String name);
        ChannelFieldGroup createFieldGroup(ChannelFieldGroupListener listener);
        ChannelProcess createChannelProcess(
            ChannelProcessRequester channelProcessRequester);
        ChannelGet createChannelGet(ChannelFieldGroup channelFieldGroup,
            ChannelGetRequester channelGetRequester,
            boolean process);
        ChannelPut createChannelPut(ChannelFieldGroup channelFieldGroup,
            ChannelPutRequester channelPutRequester,
            boolean process);
        ChannelPutGet createChannelPutGet(
            channelFieldGroup putFieldGroup,ChannelFieldGroup getFieldGroup,
            ChannelPutGetRequester channelPutGetRequester,
            boolean process);
        ChannelMonitor createChannelMonitor(
            ChannelMonitorRequester channelMonitorRequester);
        boolean add(ChannelProcess channelProcess);
        boolean add(ChannelGet channelGet);
        boolean add(ChannelPut channelPut);
        boolean add(ChannelPutGet channelPutGet);
        boolean add(ChannelMonitor channelMonitor);
        boolean remove(ChannelProcess channelProcess);
        boolean remove(ChannelGet channelGet);
        boolean remove(ChannelPut channelPut);
        boolean remove(ChannelPutGet channelPutGet);
        boolean remove(ChannelMonitor channelMonitor);
    }

    enum AccessRights {
        none,
        read,
        readWrite
    }

    interface ChannelField {
        Field getField();
        PVField getPVField();
        void postPut();
        ChannelField findProperty(String propertyName);
        ChannelField createChannelField(String fieldName);
        String[] getPropertyNames();
        PVEnumerated getEnumerated();
        AccessRights getAccessRights();
    }

    interface ChannelFieldGroupListener {
        void accessRightsChange(Channel channel,ChannelField channelField);
    }

    interface ChannelFieldGroup {
        void addChannelField(ChannelField channelField);
        void removeChannelField(ChannelField channelField);
        List<ChannelField> getList();
        ChannelField[] getArray();
    }

    interface ChannelMonitorRequester extends Requester{
        void beginPut();
        void endPut();
        void dataPut(PVField modifiedPVField);
        void dataPut(PVField requestedPVField,PVField modifiedPVField);
    }
    
    interface ChannelMonitor {
        void setFieldGroup(ChannelFieldGroup channelFieldGroup);
        void getData(CD cd);
        void start();
        void stop();
        void destroy();
    }

    interface ChannelAccess {
        Channel createChannel(String pvName,String[] propertys,
            String providerName, ChannelListener listener);
        void registerChannelProvider(ChannelProvider channelProvider);
        ChannelProvider getChannelProvider(String providerName);
        ChannelProvider[] getChannelProviders();
        boolean isChannelProvider(String channelName,String providerName);
    }

    public class ChannelAccessFactory {
         static ChannelAccess getChannelAccess();
    }

    interface ChannelProvider {
        Channel createChannel(String pvName,ChannelListener listener);
        String getProviderName();
        boolean isProvider(String channelName);
        void destroy();
    }

Channel

A channel provides access to an arbitrary number of fields in the record. The methods are:

connect
Connect to the data source.
disconnect
Disconnect from the data source.
destroy
Destroy the channel. Any active requests will still occur but no new requests will be accepted for the channel.
getChannelName
Get the channelName.
getPVRecord
Get the PVRecord this channel holds.
getChannelListener
Get the ChannelListener.
message
Channel Access code calls this to report errors and/or diagnostic information.
isConnected
Is the channel connected?
getPropertyName
Get the propertyName for this channel. This name can be passed to channel.getPVRecord.findProperty().
getFieldName
Get the fieldName. This name can be passed to channel.getPVRecord.getField().
getOptions
Get the options. The details are channelProvider dependent.
createChannelField
Create a ChannelField if the field is found and return the interface. If not found null is returned.
createFieldGroup
get, put, putGet, and monitor all use fieldGroup to specify the data to get/put from/to a channel.
createChannelProcess
Create a process request. This is used to ask a channel to process.
createChannelGet
Create a get request.
createChannelPut
Create a put request.
createChannelPutGet
Create a putGet request.
createChannelMonitor
Create a channel monitor. This is used to create monitors for the channel.
add remove
add and remove are called by channelProcess, ..., channelMonitor.

ChannelListener

ChannelListener is an interface that must be implemented by code that creates a channel. It has the methods:

channelStateChange
The connection state changed. The listener can call channel.isConnected to find the connection state.
disconnect
The channel is going away. The channel will not accept any further requests.

AccessRights

AccessRights is an enum specifying access rights to fields of a channel. Note that access rights are not currently implemented.

none
The channel can neither read or write the field.
read
The channel can read but not modify the channel.
write
The channel can both read and modify the channel

ChannelField

ChannelField describes a specific field in a channel.

getField
Returns the Field that describes the field. See package org.epics.ioc.pv for details.
getPVField
Gets the PVField that holds the data.
postPut
When a client does a put to the PVField, this muset be called.
findProperty
Find a ChannelField for the specified propertyName.
getPropertyNames
Get all the names of all the properties associated with this field..
getEnumerated
If the associated PVField is an enumerated structure return the Enumerated interface. Returns null if the PVField is not an enumerated structure.
getAccessRights
Get the access rights for the field.

ChannelFieldGroupListener

ChannelFieldGroupListener provides a method that is called whenever the access rights change. The method is:

accessRightsChange
The listener can call channelField.getAccessRights to get the current rights.

ChannelFieldGroup

ChannelFieldGroup has the methods:

addChannelField
Add a channelField to the group. Note that channel.findField returns a channelField.
removeChannelField
Remove a channelField from the group.
getList
Get the list of channelFields in the group.
getArray
Get the array of ChannelField

ChannelMonitorRequester

ChannelMonitorRequester has the methods:

beginPut
This is called when a new set of monitored data is available. Between beginPut and endPut a set of dataPut calls are made.
endPut
This is called when at the end of a new set of monitored data.
dataPut(PVField modifiedPVField);
A put to the modifiedPVField has occured.
dataPut(PVField requestedPVField,PVField modifiedPVField);
A put to the modifiedPVField has occured. The requestedPVField is the PVField in an associated ChannelField.

ChannelMonitor

ChannelMonitor has the methods:

setFieldGroup
Set the fieldGroup to monitor.
getData
Get the current data and put it into the CD.
start
Start monitoring.
stop
Stop monitoring.

ChannelAccess

A channelFactory creates a channel. A channel is either local, i.e. code running in an IOC is accessing a field in the local IOC database, or remote, code is accessing a channel that is available over the network. Channelfactory also has methods called by support for local access and by support for remote access.

The methods implemented by ChannelAccess are:

createChannel
A client calls this to create a channel. A Channel is created and returned only if the channelProvider is registered and if the channelProvider can locate the channelName. If a channel is created connection managment is started. A null is returned if the request fails.
registerChannelProvider
This is the registration call for a channel access provider.
getChannelProvider
Return the ChannelProvider or null if the providerName is not registered.
getChannelProviders
Get an array of all of the channelProviders.
isChannelProvider
Does providerName provide a channel for channelName

ChannelAccessFactory

ChannelAccessFactory provides the single method:

getChannelAccess
Get the single instance of ChannelAccess.

ChannelProvider

This is an interface that must be implemented by code that implements channel access. It is called by ChannelFactory. It has only one method

createChannel
ChannelFactory calls this first for local channel access and if the channel is not found then for remote channel access.
getProviderName
Get the provider name.
isProvider
Can the provider access channelName?
destroy
Destroy the channelProvider.

Channel Process, Get, Put, PutGet, and Monitor


Definitions

    interface ChannelProcess {
        boolean process();
        void destroy();
    }

    interface ChannelProcessRequester extends Requester {
            void processDone(RequestResult requestResult);
    }

    interface ChannelGet {
        boolean get();
        void getDelayed(PVField pvField);
        void destroy();
    }

    interface ChannelGetRequester extends Requester {
        boolean nextGetField(ChannelField field,PVField pvField);
        boolean nextDelayedGetField(PVField pvField);
        void getDone(RequestResult requestResult);
    }

    interface ChannelPut {
        boolean put();
        void putDelayed(PVField pvField);
        void destroy();
    }

    interface ChannelPutRequester extends Requester {
        boolean nextPutField(ChannelField field,PVField pvField);
        boolean nextDelayedPutField(PVField pvField);
        void putDone(RequestResult requestResult);
    }


    interface ChannelPutGet {
        boolean putGet();
        void putDelayed(PVField pvField);
        void getDelayed(PVField pvField);
        void destroy();
    }

    interface ChannelPutGetRequester extends
        ChannelPutRequester,ChannelGetRequester {}

ChannelProcess

ChannelProcess has the methods:

process
Process the channel. If the channel is a database record, process the record. process returns (false, true) if the request (can not, can) be done. Normally true is returned. A false value probably means that the channel is not connected or channelProcess is not the requester.
destroy
Destroy any state. This is called automatically when channel.destroy() id called.

ChannelProcessRequester has the methods:

getRequesterName
Determined by the requester.
message
Called for error or informational messages.
processDone
Called when the record associated with the channel completes processing.

A ChannelProcess is created via a call:

    ChannelProcess channelProcess = channel.createChannelProcess(this).

The requester must implement interface ChannelProcessRequester. null is returned if the requester is not allowed to process the channel. For example the channel is connected to a record that already has an assigned record processor.

If createChannelProcess or process itself fails, channelProcessRequester.message is called. If process returns true, then channelProcessRequester.requestDone is called when the channel completes processing.

ChannelGet

ChannelGet has the methods:

get
Get all data for the fieldGroup. The data is returned via calls to channelGetRequester.
getDelayed
If channelGetRequester.nextGetField returns true, meaning the requester is not done retrieving the data, then the requester calls getDelayed to retrieve the data.
destroy
Destroy any state. This is called automatically when channel.destroy() id called.

ChannelGetRequester has the methods:

nextGetField
The next pvField in the fieldGroup. The requester returns false if it is done with the data and true otherwise. If true is returned the the requester calls channelGet.getDelayed when it is ready.
nextDelayedGetField
When the requester calls channelGet.getDelayed the data is returned via a call to nextDelayedGetField
getDone
The request is done.

Delayed gets are provided for channel access servers that need to block while handling data. Consider a server that needs to send an array over the network. If it is a very large array, the server has to send the array in multuple network buffers. In order not to lock a database record while the array is being sent it can use the delayed methods. It implements something like:

    PVArray pvArray;
    int size,offset;

    boolean nextGetField(Channel channel,ChannelField field,PVField pvField) {
        // recognize that data is actually an array
        pvArray = (PVArray)pvField;
        size = pvArray.getLength();
        offset = 0;
        return true;
    }
    ...
    while(moreToDo) {
       // get networkBuffer. This may block while waiting
       channelGet.getDelayed(pvArray();
       // send buffer. This might block
       if(offset>=size) break; // all done
    }
    ...
    boolean nextDelayedGetField(PVField pvField) {
        // transfer data to network buffer
        // update offset
        if(offset<size) return true // getDelayed will again be called
        return false // all done
    }

ChannelPut

ChannelPut has the methods:

put
Put all data for the fieldGroup. The data is fetched via calls to channelPutRequester.
putDelayed
If channelPutRequester.nextPutField returns true, meaning the requester has not put the data, then the requester calls putDelayed when it is ready to put the data.
destroy
Destroy any state. This is called automatically when channel.destroy() id called.

ChannelPutRequester has the methods:

nextPutField
The next pvField in the fieldGroup. The requester returns false if it is done with that data and true if it is not ready to put the data. If true is returned the the requester calls channelPut.putDelayed when it is ready.
nextDelayedPutField
When the requester calls channelPut.putDelayed the data is put via a call to nextDelayedPutField
putDone
The put request is complete.

Like delayed gets delayed puts are used by servers that need to block. For example servers that transfer data from the network to an IOC database.

ChannelPutGet

This is a combination of ChannelPut and ChannelGet. A typical example is a client request to:


Abstract and Base Classes


    public abstract class AbstractChannel implements Channel{
        protected AbstractChannel(ChannelListener channelListener, String options);
        protected synchronized void setPVRecord(PVRecord pvRecord,String fieldName);
        public synchronized PVRecord getPVRecord();
        public synchronized boolean add(ChannelProcess channelProcess);
        public synchronized boolean add(ChannelGet channelGet);
        public synchronized boolean add(ChannelPut channelPut);
        public synchronized boolean add(ChannelPutGet channelPutGet);
        public synchronized boolean add(ChannelMonitor channelMonitor);
        public synchronized boolean remove(ChannelProcess channelProcess);
        public synchronized boolean remove(ChannelGet channelGet);
        public synchronized boolean remove(ChannelPut channelPut);
        public synchronized boolean remove(ChannelPutGet channelPutGet);
        public synchronized boolean remove(ChannelMonitor channelMonitor);
        public synchronized String getChannelName();
        public String getRequesterName();
        public void message(String message, MessageType messageType);
        public void connect();
        public void disconnect();
        public synchronized boolean isConnected();
        public void destroy();
        public ChannelListener getChannelListener();
        public synchronized boolean isConnected();
        public synchronized String getFieldName();
        public synchronized String getOptions();
        public synchronized String getPropertyName();
        public synchronized ChannelFieldGroup createFieldGroup(
           ChannelFieldGroupListener listener);
    }

    public class BaseChannelField implements ChannelField { ... }
    public class BaseChannelFieldGroup implements ChannelFieldGroup { ... }

AbstractChannel is for use by Channel Providers. The public methods are sufficent for most providers and do not need to be overriden. The provider must call the add and remove methods whenever the corresponding interface is implemented or destroyed. When destroy is called AbstractChannel calls the destroy method of each of the process/get/put/putGet/monitor interfaces.

BaseChannelField implements all ChannelField methods. However the provider must provide a PVField interface to the constructor and often needs to override some of the methods.

BaseChannelFieldGroup implements all ChannelFieldGroup methods. A provider normally can use BaseChannelFieldGroup without overriding any of the methods.


ChannelMonitorNotify


ChannelMonitorNotify

This is support for being notified when a put is issued to a field of an IOC database. The notification does not include data.

    public interface ChannelMonitorNotify extends ChannelMonitor{}
    
    interface ChannelMonitorNotifyRequester extends Requester{
        void monitorEvent();
    }
    
    class ChannelMonitorNotifyFactory {
        ChannelMonitorNotify create(Channel channel,
            ChannelMonitorNotifyRequester monitorNotifyRequestor);
    } 

Local Channel Provider


An implementation of a channel access client for accessing records in the IOC database is provided. It has the name "local" This is created automatically by ChannelProviderLocalFactory . The factory creates a single instance of an implementation of a channel access client for accessing local records. ChannelProviderLocalFactory has only one public method.

    public class ChannelProviderLocalFactory  {
        static public void register();
    }

This method is called by ChannelFactory when it is called before a local Channel Access is registered.


CD - Channel Data


CD (ChannelData) is a facility that holds a copy of the data contained in a fieldGroup. CD helps solve two problems:

  1. Blocking with a record locked.
    An example is a channel access server. Instead of pre allocating network buffers for a fieldGroup it can create a CD, transfer data from a record to the CD, and then transfer the CD to a network buffer. In the case of a large array multiple network buffers will be required.
  2. Data repository for database monitoring.
    For database monitoring a queue of CDs can be created. When a monitored record changes, a CD can be taken from the queue, and the data values stored in the CD. This can be done without blocking. When the server is ready it can empty the queue and send the CDs over the network.

A CD is associated with a channel and channelFieldGroup. When a CD is created via a call to CDFactory.createCD it automatically creates a CDRecord and associated subfields, which are described in the next section.

CD Definitions

    interface CD {
        void destroy();
        Channel getChannel();
        ChannelFieldGroup getChannelFieldGroup();
        CDRecord getCDRecord();
        void clearNumPuts();
        boolean get(PVField pvField);
        boolean put(PVField pvField);
        boolean put(PVField pvField,PVField pvSubField);
        CDGet createCDGet(
            CDGetRequester channelCDGetRequester,
            boolean process);
        void destroy(CDGet channelCDGet);
        CDPut createCDPut(
            CDPutRequester cdPutRequester,
            boolean process);
        void destroy(CDPut cdPut);
    }


    interface CDQueue {
        int getNumberFree();
        int capacity();
        CD getFree(boolean forceFree);
        void setInUse(CD cd);
        CD getNext();
        int getNumberMissed();
        void releaseNext(CD cd);
    }

    class CDFactory {
         static CD createCD(
             Channel channel,ChannelFieldGroup channelFieldGroup);
         static CDQueue createQueue(
             int queueSize,Channel channel,ChannelFieldGroup channelFieldGroup);
    }

    class BaseCD { ... }
    class BaseCDQueue { ... }
    class BaseCDPut { ... }
    class BaseCDGet { ... }

CD

CD has the following methods:

delete
Delete the CD. Thias automatically call delete for each CDGet, CVPut, and CDModify.
getChannel
Get the channel to which this channelFieldGroup belongs.
getChannelFieldGroup
Get the ChannelFieldGroup for this CD.
getCDRecord
Get the CDRecord that holds the data.
getMaxPutsToField
Get the maxNumPuts to any field.
clearNumPuts
Clear the internal list of items that have been added.
get
Get data from the CD and put it into pvField. It returns (false,true) if data (was not, was) put into the CDField.
put
The PVField has been modified. Two versions are provided. One is if a ChannelField is connected to the PVField itself and the other if the PVField is a subfield of the PVStructure to which the ChannelField is connected. NOTE that the pvFields are from the ChannelField NOT the pvField from the CD. Each returns (false,true) if data (was not, was) put into a ChannelField.
createCDGet
Create a CDGet.
destroy(CDGet channelCDGet)
Delete a CDGet.
createCDPut
Create a CDPut.
destroy(CDPut channelCDPut)
Delete a CDPut.

A CD is allocated as follows:

    CD cd = CDFactory.createData(
        channel,channelFieldGroup);

This creates storage for each element of the field group. It can create storage for all pvTypes. For Array types, the initial size and capacity is 0. The arrays will grow as data is placed in them but will not be released.

CDQueue

CDQueue has the following methods:

getNumberFree
Get the number of unused cd elements in the queue.
capacity
Get the number of cd elements in the queue.
getFree
Get a cd element from the queue. If there are no more free elements numberMissed is incremented. If forceFree is true the oldest used element is reused. If no free element is available then null is returned.
setInUse
Sets the CD in use. This must be called for each cd returned by getFree. The caller can make changes to the CD before it is set in use.
getNext
Get the next cd element that has new data in it. Return null if there are no more elements.
getNumberMissed
Get the number of times getGree has been called since the last call to releaseNext.
releaseNext
Release the element returned by getNext.

A CDQueue is created as follows:

    CDQueue cdQueue = CDFactory.createQueue(
         queueSize,channel,channelFieldGroup);

This creates queueSize channelFieldGroups and a queue to manage them. As an example of how a queue is used consider a channel access server monitoring a fieldGroup of an IOC database record.

CDFactory

CDFactory has the following methods:

createData
Create a CD.
createQueue
Create a CDQueue.

CDField - Channel Data Fields


Each cd provides a set of interfaces for accessing the data values. The data is stored in PVField objects. The complete set of PVFields form a PVRecord, Each CD interface provides access to it's corresponding PV interface. The CD interfaces provide additional methods that allow the client to determine how often each PVField was written.

CDField Definitions

    interface CDField {
        CDField getParent();
        CDRecord getCDRecord();
        ChannelField getChannelField();
        PVField getPVField();
        int getNumPuts();
        void incrementNumPuts();
        int getMaxNumPuts();
        void setMaxNumPuts(int numPuts);
        void clearNumPuts();
        void get(PVField pvField,boolean postPut);
        void put(PVField pvField);
        void put(PVField pvField,PVField pvSubField);
        String toString();
        String toString(int indentLevel);
    }

    interface CDRecord {
        CDField findCDField(PVField pvField);
        CDField findSourceCDField(PVField sourcePVField);
        PVRecord getPVRecord();
        CDStructure getCDStructure();
        PVDataCreate getPVDataCreate();
    }
    
    interface CDStructure extends CDField {
        CDField findCDField(PVField pvField);
        CDField findSourceCDField(PVField sourcePVField);
        CDField[] getCDFields();
        PVStructure getPVStructure();
    }

    interface CDArray extends CDField{
        PVArray getPVArray();
    }
    
    interface CDArrayArray extends CDArray {
        CDField findCDField(PVField pvField);
        CDField findSourceCDField(PVField sourcePVField);
        CDArray[] getElementCDArrays();
    }

    interface CDStructureArray extends CDArray {
        CDField findCDField(PVField pvField);
        CDField findSourceCDField(PVField sourcePVField);
        CDStructure[] getElementCDStructures();
    }

    class BaseCDRecord { ... }
    class BaseCDField { ... }
    class BaseCDArray { ... }
    class BaseCDStructure { ... }
    class BaseCDStructureArray { ... }
    class BaseCDArrayArray { ... }

CDField

Each field in the PVRecord associated with CDRecord has an associated CDField or an extension. CDField has the methods:

getParent
Get the parent of this field. If CDField is the CDStructure for the fieldGroup than the parent is null.
getCDRecord
Get the CDRecord to which this CDField belongs.
getChannelField
Get the ChannelField for this CDField.
getPVField
Get the PVField associated with this CDField.
getNumPuts
Get the number of dataPuts to this field.
incrementNumPuts
Increment the number of dataPuts to this field. This is called by extensions to CDField.
getMaxNumPuts
Get the maximum number of puts since the last clearNumPuts. This is the maximum number of puts to any particular element of the associated PVField. If PVField is a scalar or an array of scalars then this is the number of calls to dataPut.
setMaxNumPuts
Set the maximum number of puts. This is called by derived classes.
clearNumPuts
Set all number of puts to 0.
get
Get data from the CDField and put it into pvField. If postPut is true channelField.postPut is called if the data is written.
get
Put the CDField PVField with data from pvField or pvSubField.

CDRecord

CDRecord is for the ChannelFieldGroup. It has the methods:

findCDField
Given a pvField find the ChannelField that holds the pvField.
findSourceCDField
Given a pvField find the ChannelField that references the source pvField.
getPVRecord
Get the PVRecord interface. This PVRecord will have a recordName which is the channelName, which is he name of the record to which the channel is connected.
getCDStructure
Get the CDStructure for the CDRecord itself. The CDStructure will have a subfield for each member of the channelFieldGroup that the cd describes. Each subfield describes the data for it's ChannelField.
getPVDataCreate
This is used by the code that creates CD interfaces. It returns a factory to create PVDat objects.

CDStructure

CDStructure is associated with a PVStructure. It has the methods:

findCDField
Given a pvField find the ChannelField that holds the pvField.
findSourceCDField
Given a pvField find the ChannelField that references the source pvField.
getCDFields
Get the CDField array for the fields of the structure.
getPVStructure
Get the PVStructure.

CDArray

CDArray is associated with a PVArray. It has the method:

getPVArray
Get the PVArray for this array.

CDArray is associated with a PVArray. It has the method:

CDStructureArray

CDStructureArray is associated with a PVArray with structure elements.

findCDField
Given a pvField find the ChannelField that holds the pvField.
findSourceCDField
Given a pvField find the ChannelField that references the source pvField.
getElementCDStructures
Get the CDStructure array.

CDArrayArray

CDArrayArray is associated with a PVArray with array elements.

findCDField
Given a pvField find the ChannelField that holds the pvField.
findSourceCDField
Given a pvField find the ChannelField that references the source pvField.
getElementCDArrays
Get the CDArray array.

Base CD Classes

The BaseCD classes provide implementations of the CD interraces. These provide complete imnplementations and should rarely need to be extended.


CDGet, CDPUT, CDMonitor


CDGet

    public interface CDGet {
        void destroy();
        void get(CD cd);
    }
    
    public interface CDGetRequester extends Requester{
        void getDone(RequestResult requestResult);
    }

CDGet has the methods:

destroy
Destroy the CDGet.
get
Get data and put it into the CD.

CDGetRequester has the methods:

getDone
The get has finished. If successful the data is in the CD.

CDPut

    interface CDPut {
        void destroy();
        void get(CD cd);
        void put(CD cd);
    }
    
    public interface CDPutRequester extends Requester{
        void getDone();
        void putDone(RequestResult requestResult);
    }

This is a put that uses a CD to hold the data. The caller puts data into the CD before calling CDPut.put().

CDPut has the methods:

destroy
Destroy the CDGet.
get
Get the latest target data and put it into cd. The target record is not processed.
put
Put the data currently residing in cd and put it to the target. If process is requested than the record is set active before the data is put.

CDPutRequester has the methods:

getDone
The get request is done and the data is in cd.
putDone
The put request is finished. The result of record processing, if specified, is returned.

CDMonitor

This is support for being notified when a put is issued to a field of an IOC database. The notification includes data.

    interface CDMonitor {
        void lookForPut(ChannelField channelField, boolean causeMonitor);
        void lookForChange(ChannelField channelField, boolean causeMonitor);
        void lookForAbsoluteChange(ChannelField channelField,double value);
        void lookForPercentageChange(ChannelField channelField,double value);
        void start(int queueSize,IOCExecutor iocExecutor);
        void stop();
    }
    
    interface CDMonitorRequester extends Requester{
        void monitorCD(CD cD);
        void dataOverrun(int number);
    }
    
    class CDMonitorFactory {
        public static CDMonitor create(Channel channel,
            CDMonitorRequester cdMonitorRequester)
    }

CDMonitor has the methods:

lookForPut
Look for a put. If the ChannelField is a structure then look for a put to any subfield of the structure.
lookForChange
Look for a change in a data value. This is only valid for a primitive field.
lookForAbsoluteChange
Look for an absolute change in the data. The argument value is the deadband. This is only valid if ChannelField is a numeric scalar.
lookForPercentageChange
Look for a percentage change in the data. The argument value is the deadband. This is only valid if ChannelField is a numeric scalar.
start - MonitorNotify
Notify when a change occurs but do not send data. The caller can issue a get request to retrieve the data.
start - Monitor
When data changes send it the the requester.
stop
Stop monitoring.

CDMonitorRequester has the methods:

monitorCD
The modified data.
dataOverrun
The number of missed monitors.

CDMonitorRequester has the method:

create
Create a CDMonitor

Example For CD


Discussion

This example creates a CD for a fieldGroup that has the following:

The definition is:

    static class ValueData implements ChannelFieldGroupListener{
        ValueData(Channel channel);
        ChannelFieldGroup init();
        void clear();
        boolean nextGetField(Channel channel, ChannelField field, PVField pvField);
        void printResults();
    }
where
ValueData
The constructor
init
creates everthing it needs. Returns null if anything fails.
clear
Prepares to accept a new set of data for the fieldGroup
nextGetField
Adds the data to the cd list.
printResults
Prints all data received since last clear.

What it provides for later examples is the ability to dump everthing an example gets from a record after the record is no longer locked.

Implementation

    class ValueData implements ChannelFieldGroupListener{
        private Channel channel;
        private String fieldName;
        private ChannelFieldGroup channelFieldGroup;
        private ChannelField valueField;
        private ChannelField alarmField = null;
        private ChannelField timeStampField = null;

        ValueData(Channel channel,String fieldName) {
            this.channel = channel;
            this.fieldName = fieldName;
        }

       
        public void accessRightsChange(Channel channel, ChannelField channelField) {
            // TODO Auto-generated method stub

        }

        private ChannelFieldGroup init() {
            channelFieldGroup = channel.createFieldGroup(this);
            valueField = channel.createChannelField(fieldName);
            if(valueField==null) {
                System.out.printf("findField returned %s%n", result.toString());
                return null;
            }
            channelFieldGroup.addChannelField(valueField);
            alarmField =  valueField.findProperty("alarm");
            if(alarmField!=null) channelFieldGroup.addChannelField(alarmField);
            timeStampField = valueField.findProperty("timeStamp");
            if(timeStampField!=null) channelFieldGroup.addChannelField(timeStampField);
            return channelFieldGroup;
        }


       private String printResults(CD cd) {
            StringBuilder builder = new StringBuilder();
            ChannelFieldGroup channelFieldGroup = cd.getChannelFieldGroup();
            List<ChannelField> channelFieldList = channelFieldGroup.getList();
            CDStructure cdStructure = cd.getCDRecord().getCDStructure();
            CDField[] cdbDatas = cdStructure.getCDFields();
            int maxNumPuts = cd.getMaxPutsToField();
            if(maxNumPuts!=1) {
                builder.append(String.format(
                    " maxNumPuts %d ",maxNumPuts));
            }
            for(int i=0;i<cdbDatas.length; i++) {
                CDField cdField = cdbDatas[i];
                maxNumPuts = cdField.getMaxNumPuts();
                if(maxNumPuts<=0) continue;
                if(maxNumPuts!=1) {
                    builder.append(String.format(
                        " maxNumPuts %d ",maxNumPuts));
                }
                PVField pvField = cdField.getPVField();
                ChannelField channelField = channelFieldList.get(i);
                if(channelField==valueField) {
                    builder.append(String.format(
                        "value %s ",
                        pvField.toString(2)));
                } else if(channelField==alarmField) {
                    builder.append(String.format(" alarm %s",
                        pvField.toString()));
                } else if(channelField==timeStampField) {
                    PVTimeStamp pvTimeStamp = PVTimeStamp.create(pvField);
                    TimeStamp timeStamp = new TimeStamp();
                    pvTimeStamp.get(timeStamp);
                    long seconds = timeStamp.secondsPastEpoch;
                    int nano = timeStamp.nanoSeconds;
                    long now = nano/1000000 + seconds*1000;
                    Date date = new Date(now);
                    builder.append(String.format(" time %s",
                        date.toLocaleString()));
                }
                if(cdField.getNumSupportNamePuts()>0) {
                    builder.append(String.format("supportName %s numSupportNamePuts %d%n",
                        pvField.getSupportName(),cdField.getNumSupportNamePuts()));
                }
            }
            return builder.toString();
        }
    }

Process Example


Discussion

This example shows how to implement a process request.

Implementation

    static class Process implements ChannelProcessRequester,ChannelListener
    {
        private Lock lock = new ReentrantLock();
        private Condition waitDone = lock.newCondition();
        private boolean allDone = false;
        private String pvname = null;
        private Channel channel;
        private ChannelProcess channelProcess;

        Process(String pvname) {
            this.pvname = pvname;
            channel = ChannelFactory.createChannel(pvname, this);
            channelProcess = channel.createChannelProcess(this);
           // SHOULD CHECK FOR NULL
        }
        void destroy() {
            channel.destroy();
        }
        void process() {
            allDone = false;
            channelProcess.process();
            lock.lock();
            try {
                if(!allDone) {
                    waitDone.await();
                }
            } catch (InterruptedException e) {
                return;
            } finally {
                lock.unlock();
            }
        }

        public String getRequesterName() {
            return "Put:" + pvname;
        }

        public void message(String message, MessageType messageType) {
            message(channel,message,messageType);
        }

        public void message(Channel channel, String message, MessageType messageType) {
            System.out.printf("putGet.massage %s%n", message);
        }

        public void requestDone(Channel channel, RequestResult requestResult) {
            lock.lock();
            try {
                allDone = true;
                    waitDone.signal();
            } finally {
                lock.unlock();
            }
        }

        public void channelStateChange(Channel c, boolean isConnected) { }

        public void disconnect(Channel c) { }

        public void accessRightsChange(Channel channel, ChannelField channelField) { }
    }

Get Example


Discussion

This example shows how to implement a get request.

Implementation

    static class Get implements
    ChannelGetRequester,
    ChannelListener, ChannelFieldGroupListener
    {
        private Lock lock = new ReentrantLock();
        private Condition waitDone = lock.newCondition();
        private boolean allDone = false;
        private String pvname = null;
        private Channel channel;
        private ChannelGet channelGet;
        private ValueData valueData;
        private ChannelFieldGroup getFieldGroup;

        Get(String pvname,boolean process) {
            this.pvname = pvname;
            channel = ChannelFactory.createChannel(pvname, this);
            channelGet = channel.createChannelGet(this, process);
        }
        void destroy() {
            channel.destroy();
        }
        boolean connect() {

            valueData = new ValueData(channel);
            getFieldGroup = valueData.init();
            if(getFieldGroup==null) return false;
            return true;
        }

        void get() {
            allDone = false;
            valueData.clear();
            channelGet.get(getFieldGroup);
            lock.lock();
            try {
                if(!allDone) {
                    waitDone.await();
                }
            } catch (InterruptedException ie) {
                return;
            } finally {
                lock.unlock();
            }
            valueData.printResults();
        }

        public boolean nextDelayedGetField(PVField pvField) {
            //nothing to do
        }

        public String getRequesterName() {
            return "PutGet:" + pvname;
        }

        public void message(String message, MessageType messageType) {
            message(channel,message,messageType);
        }

        public boolean nextGetField(Channel channel, ChannelField field, PVField pvField) {
            valueData.nextGetField(channel, field, pvField);
            return false;
        }

        public void message(Channel channel, String message, MessageType messageType) {
            System.out.printf("putGet.massage %s%n", message);
        }

        public void requestDone(Channel channel, RequestResult requestResult) {
            lock.lock();
            try {
                allDone = true;
                    waitDone.signal();
            } finally {
                lock.unlock();
            }
        }

        public void channelStateChange(Channel c, boolean isConnected) { }

        public void disconnect(Channel c) { }

        public void accessRightsChange(Channel channel, ChannelField channelField) { }
    }

Put Example


Discussion

This example shows how to implement a put request.

Implementation

    static class Put implements
    ChannelPutRequester,
    ChannelListener, ChannelFieldGroupListener
    {
        private Lock lock = new ReentrantLock();
        private Condition waitDone = lock.newCondition();
        private boolean allDone = false;
        private String pvname = null;
        private Channel channel;
        private ChannelPut channelPut;
        private ChannelFieldGroup putFieldGroup;
        private ChannelField valueField;
        private double value;

        Put(String pvname, boolean process) {
            this.pvname = pvname;
            channel = ChannelFactory.createChannel(pvname, this);

            channelPut = channel.createChannelPut(this, process);
        }

        public boolean nextDelayedPutField(PVField pvField) {
            // nothing to do
            return false;
        }
        void destroy() {
            channel.destroy();
        }
        boolean connect() {
            putFieldGroup = channel.createFieldGroup(this);
            valueField = channel.findField("value");
            if(valueField==null) {
                System.out.println("PutGet:set value not found");
                return false;
            }
            putFieldGroup.addChannelField(valueField);
            return true;
        }

        void put(double value) {
            this.value = value;
            allDone = false;
            channelPut.put(putFieldGroup);
            lock.lock();
            try {
                if(!allDone) {
                    waitDone.await();
                }
            } catch (InterruptedException ie) {
                return;
            } finally {
                lock.unlock();
            }
        }

        public String getRequesterName() {
            return "Put:" + pvname;
        }

        public void message(String message, MessageType messageType) {
            message(channel,message,messageType);
        }

        public boolean nextPutField(Channel channel, ChannelField field, PVField pvField) {
            PVDouble pvDouble = (PVDouble)pvField;
            pvDouble.put(value);
            return false;
        }

        public void message(Channel channel, String message, MessageType messageType) {
            System.out.printf("putGet.massage %s%n", message);
        }

        public void requestDone(Channel channel, RequestResult requestResult) {
            lock.lock();
            try {
                allDone = true;
                    waitDone.signal();
            } finally {
                lock.unlock();
            }
        }

        public void channelStateChange(Channel c, boolean isConnected) { }

        public void disconnect(Channel c) { }

        public void accessRightsChange(Channel channel, ChannelField channelField) { }
    }

PutGet Example


Discussion

This example shows how to implement a putGet request. When the put method is called, it puts a double value to a field named value, optionally processes the record, and retrieves the value, status, severity, and timeStamp.

Implementation

    static class PutGet implements
    ChannelPutGetRequester,
    ChannelListener, ChannelFieldGroupListener
    {
        private Lock lock = new ReentrantLock();
        private Condition waitDone = lock.newCondition();
        private boolean allDone = false;
        private String pvname = null;
        private Channel channel;
        private ChannelPutGet channelPutGet;
        private ChannelFieldGroup putFieldGroup;
        private ValueData valueData;
        private ChannelFieldGroup getFieldGroup;
        private ChannelField valueField;
        private double value;

        PutGet(String pvname,boolean process) {
            this.pvname = pvname;
            channel = ChannelFactory.createChannel(pvname, this);
            channelPutGet = channel.createChannelPutGet(this, process);
        }

        public boolean nextDelayedPutField(PVField pvField) {
            // Nothing to do
            return false;
        }

        public boolean nextDelayedGetField(PVField pvField) {
            // Nothing to do
            return false;
        }

        boolean connect() {
            putFieldGroup = channel.createFieldGroup(this);
            valueField = channel.findField("value");
            if(valueField==null) {
                System.out.println("PutGet:set value not found");
                return false;
            }
            putFieldGroup.addChannelField(valueField);
            valueData = new ValueData(channel);
            getFieldGroup = valueData.init();
            if(getFieldGroup==null) return false;
            return true;
        }

        void destroy() {
            channel.destroy();
        }

        void putGet(double value) {
            this.value = value;
            allDone = false;
            valueData.clear();
            channelPutGet.putGet(putFieldGroup, getFieldGroup);
            lock.lock();
            try {
                if(!allDone) {
                    waitDone.await();
                }
            } catch (InterruptedException ie) {
                return;
            } finally {
                lock.unlock();
            }
            valueData.printResults();
        }

        public String getRequesterName() {
            return "PutGet:" + pvname;
        }

        public void message(String message, MessageType messageType) {
            message(channel,message,messageType);
        }

        public boolean nextGetField(Channel channel, ChannelField field, PVField pvField) {
            valueData.nextGetField(channel, field, pvField);
            return false;
        }

        public boolean nextPutField(Channel channel, ChannelField field, PVField pvField) {
            PVDouble pvDouble = (PVDouble)pvField;
            pvDouble.put(value);
            return false;
        }

        public void message(Channel channel, String message, MessageType messageType) {
            System.out.printf("putGet.massage %s%n", message);
        }

        public void requestDone(Channel channel, RequestResult requestResult) {
            lock.lock();
            try {
                allDone = true;
                    waitDone.signal();
            } finally {
                lock.unlock();
            }
        }

        public void channelStateChange(Channel c, boolean isConnected) { }

        public void disconnect(Channel c) { }

        public void accessRightsChange(Channel channel, ChannelField channelField) { }
    }