EPICS pvDataJava

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

Latest version:
pvDataJava.html
This version:
pvDataJava_20120903.html
Previous version:
pvDataJava_20120808.html
Editors:
Marty Kraimer, BNL

Abstract

pvDataJava is a computer software package for the efficient storage, access, and communication, of structured data. It is specifically the Java implementation of pvData, which is one part of the set of related products in the EPICS V4 control system programming environment:

pvData
pvData (Process Variable Data) defines and implements an efficent way to store, access, and communicate memory resident structured data
pvAccess
pvAccess is a software library for high speed controls network communications, optimized for pvData
pvIOC
pvIOC is a software framework for building network accessable "smart" real time databases, suitable for interfacing devices in a distributed control system, that can exchange pvData over pvAccess.
pvService
A middle layer for implementing efficient data services.

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

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

Status of this Document

This is the 03-Sep-2012 version of the Java implementation of pvData. This version is a general edit and regularizes the header boilerplate.

The text describes software which is a complete implementation of pvData as currently planned by the EPICS V4 Working Group.

The following is a list of unresolved issues for pvDataJava:

  1. org.epics.pvdata.util: Have to certify if this package is in use. If being used this document should talk about it. If not being used it should be deleted.

Table of Contents

Introduction

pvData is one of a set of related packages in the EPICS V4 core sofware. It describes and implements the data management system to which the the other projects interface.

pvData (Process Variable Data) defines and implements an efficent way to store, access, and communicate memory resident data structures.

definition
Package org.epics.pvdata.pv has Java interface definitions that define pvData. Although defined with Java syntax they also document what is required for implementation in other languages such as C++.
implementation
The set of packages provided by this project provide a complete Java implementation of pvData. Project pvAccess is the network support for pvData, i.e. it provides a channel access client and server that fully support pvData. Project pvIOCJava provides an IOC (Input Output Controller) that supports pvData and provides record processing..
efficient
Small memory footprint, low cpu overhead, and concise code base.
data storage
pvData defines separate introspection and data interfaces. The introspection interfaces provide access to immutable objects, which allows introspection instances to be freely shared. The introspection interface for a process variable can be accessed without requiring access to the data.
data access
Client code can access pvData via the introspection and data interfaces. For "well known" data, e.g. image data, specialized interfaces can be provided without requiring any changes to the core software.
data transfer
The separation of introspection and data interfaces allows for efficient network data transfer. At connection time introspection information can be passed from server to client. Each side can create a data instance. The data is transferred between these instances. The data in the network buffers does not have to be self describing since each side has the introspection information.
memory resident
pvData only defines memory resident data.
structured data
pvData has four types: scalar, scalarArray, structure, and structureArray. A scalar has one of the following scalarTypes : pvBoolean, pvByte, pvShort, pvInt, pvLong, pvUByte, pvUShort, pvUInt, pvULong, pvFloat, pvDouble, and pvString. A scalarArray is a one dimensional array with the element type being any of the scalarTypes. A structure is an ordered set of fields where each field has a name and type. are supported.A structureArray is an array of structures where each element has the same intrspection interface. Since a field can have type structure complex structures can be created that simulate types.

The pvIOCJava implements a Process Variable (PV) Database, which is a memory resident database holding pvData, has the following features:

pvData was initially created to support the javaIOC and was part of the javaIOC project. The original javaIOC project has been broken up into many projects, e. g. pvDataJava, pvAccessJava, pvIOCJava, pvServiceJava. In addition there are C++ implementation of each of these projects. pvData is intended for use by 1) channel access clients, 2) Interface between client and network, 3) Interface between network and channel access server, 4) Interface between server and IOC database. Since it is an interface to data, it could also be used by other systems, e.g. TANGO, TINE, etc. A high level Physics application can hold data as pvData. By starting a channel access server, the data can made available to network clients.

pvData contains everything required to support Channel Access and Channel Access clients and servers.

PVData Meta Language

This section describes a meta language for describing pvData. Currently there are no plans for a parser for the meta language. It is used for documentation. The meta language is used to describe both introspection interfaces and data interfaces.

The toString introspection and data methods described below present data in a format similar to the metadata syntax.

Definition

PVData supports structured data. All data appears via top level structures. A structure has an ordered set of fields where each field has a fieldDef defined as follows:

type fieldName value // comment

where value is present for data objects and // indicates the the rest of the line is a comment.

type is one of the following:

scalar
A scalar field can be any of the following:
boolean
Has the valuetrue or false
byte
An 8 bit signed integer.
short
An 16 bit signed integer.
int
An 32 bit signed integer.
long
An 64 bit signed integer.
ubyte
An 8 bit unsigned integer.
ushort
An 16 bit unsigned integer.
uint
An 32 bit unsigned integer.
ulong
An 64 bit unsigned integer.
float
A IEEE float.
double
A IEEE double.
string
An immutable string.
scalarArray
A scalarArray field is an array of any of the scalar types.
boolean[]
byte[]
short[]
int[]
long[]
ubyte[]
ushort[]
uint[]
ulong[]
float[]
double[]
string[]
structure
A structure field has the definition:
     structure fieldName
         fieldDef
         ...
      
or
     xxx_t fieldName
         // if data object then following appear
         fieldDef
         ...
      
For structure fieldName each fieldDef must have a unique fieldName within the structure For "xxx_t fieldName" xxx_t must be a previously structure definition of the form:
    structure xxx_t
        ...
structureArray
A structureArray field has the definition:
     structure[] fieldName
          structureDef
          ...
          

or

    xxx_t[] fieldName
      

Thus a structure array is an array where each element is a structure but all elements have the same introspection interface. For introspection the structureDef appears once without any data valuies.

The above is used to describe introspection objects. Data objects are describe in a similar way but each scalar field and each array field has data values. The definition of the data values depends on the type. For scalars the data value is whatever is valid for the type.

boolean
The value must be true or false
byte,...ulong
Any valid integer or hex value, e.g. 3 and 0x0ff are valid values
float,double
Any valid integer or real e.g. 3, 3.0, and 3e0 are valid values
string
The value can be an alphanumeric value or any set of characters enclosed in "" Within quotes a quote is expressed as \" Examples are aValue "a value" "a\" xxx" are valid values.

For scalar arrays the syntax is:

      = [value,...,value]

where each value is a valid scalar data value depending on the type. Thus it is a comma separated set of values enclosed in [] White space is permitted surrounding each comma.

Examples

Define the following top level structure:

structure timeStamp_t
    long secondsPastEpoch
    int nanoSeconds 

Then the following introspection objects can be defined:

structure scalarDoubleExample // introspection object
    double value
    timeStamp_t timeStamp
or
structure scalarDoubleExample // introspection object
    double value
    structure timeStamp
        long secondsPastEpoch
        int  nanoSeconds

The following data objects can be defined:

structure scalarDoubleExample // data object
    double value 1.0
    timeStamp_t timeStamp
         long secondsPastEpoch 0
         int  nanoSeconds 0
or
scalar arrayDoubleExample
    double[] value  [1.0,2.0]
    structure timeStamp
         long secondsPastEpoch 0
         int  nanoSeconds 0

If the following interface is defined:

structure point_t
    double x
    double y

Then the following introspection objects can be defined:

structure lineExample
    point_t begin
    point_t end

structure pointArrayExample
    point_t[] points
    
or
structure lineExample
    structure begin
        double x
        double y
    structure end
        double x
        double y

structure pointArrayExample
    structure[] points
        structure point
            double x
            double y

And the following data objects can be defined:

structure lineExample
    point_t begin
        double x 0.0
        double y 0.0
    point_t end
        double x 10
        double y 10

structure pointArrayExample
    point_t[] value
        structure point
            double x 0.0
            double y 0.0
        structure point
            double x 10.0
            double y 10.0

or

structure lineExample
    structure begin
        double x 0
        double y 0
    structure end
        double x 10
        double y 10

structure pointArrayExample
    structure[] value
        structure point
            double x 0.0
            double y 0.0
        structure point
            double x 10.0
            double y 10.0

Interface Definitions

This section gives a brief description of the pvData intospection and data interfaces. In this section the methods are shown but not described. See org.epics.pvdata.pv below for a description of each method.

Types

The following are the type definitions:

enum Type {
    scalar,
    scalarArray,
    structure,
    structureArray;
}

where

scalar
A field that has data with one of the scalarTypes.
scalarArray
A field that is an array where each element is the same scalarType.
structure
A field which has named subfields.
structureArray
A field that is an array of structures where each element has the same introspection interface, i.e. each element has the same structure.
enum ScalarType {
    pvBoolean,
    pvByte,pvShort,pvInt,pvLong,
    pvUByte,pvUShort,pvUInt,pvULong,
    pvFloat,pvDouble,
    pvString;
    // The following are convenience methods
    public boolean isInteger();
    public boolean isUInteger();
    public boolean isNumeric();
    public boolean isPrimitive();
    public static ScalarType getScalarType(String type);
    public String toString();
}

where

boolean
true or false
byte
An 8 bit signed byte
short
16 bit signed integer
int
32 bit signed integer
long
64 bit signed integer
ubyte
An 8 bit unsigned byte
ushort
16 bit unsigned integer
uint
32 bit unsigned integer
ulong
64 bit unsigned integer
float
32 bit IEEE float
double
64 bit IEEE float
string
An immutable string. The Java implementation is String. For other implementations the network representation must be the same as for Java. Note that a string is treated like it is a scaler.

NOTE: Java does not support unsigned integers so the Java implementation of each unsigned type is implemented as the corresponding signed type. The only exception is the Convert facility. When it performs a widening operation, e.g. from ubyte to short, it performs the correct conversion.

Introspection Interfaces

Field is the base introspection interface. It has only an id and a type.

interface Field extends Serializable {
    String getId();
    Type getType();
    void toString(StringBuilder buf);
    void toString(StringBuilder buf,int indentLevel);
    String toString();
}

interface Scalar extends Field {
    ScalarType getScalarType();
}

interface ScalarArray extends Field {
    ScalarType getElementType();
}

interface Structure extends Field {
    Field getField(String fieldName);
    int getFieldIndex(String fieldName);
    Field[] getFields();
    Field getField(int fieldIndex);
    String[] getFieldNames();
    String getFieldName(int fieldIndex)
}

interface StructureArray extends Field {
    Structure getStructure();
}

The introspection interfaces provide access to immutable objects. This allows introspection interfaces to be freely shared between data objects. For example the introspection interface for a timeStamp, which is a structure containing two fields, can be shared by every record that has a time stamp.

Data Interfaces

PVField is the base interface for a data field:

interface PVField extends Requester, Serializable {
    String getFieldName();
    void setRequester(Requester requester);
    int getFieldOffset();
    int getNextFieldOffset();
    int getNumberFields();
    PVAuxInfo getPVAuxInfo();
    boolean isImmutable();
    void setImmutable();
    Field getField();
    PVStructure getParent();
    void renameField(String newName);
    void postPut(); // calls PVRecordField.postPut if this is a field of a record
    void setPostHandler(PostHandler postHandler);
    void toString(StringBuilder buf);
    void toString(StringBuilder buf,int indentLevel);
    String toString();
}

Each scalar type has an associated data interface: PVBoolean, PVByte, PVShort, PVInt, PVLong, PVUByte, PVUShort, PVUInt, PVULong, PVFloat, PVDouble, and PVString. Each has a get and a put method. For example:

interface PVDouble extends PVScalar{
    double get();
    void put(double value);
}

PVArray is the base class for arrays.

interface PVArray extends PVField, SerializableArray {
    int getLength();
    void setLength(int length);
    int getCapacity();
    void setCapacity(int length);
    boolean isCapacityMutable();
    void setCapacityMutable(boolean isMutable);
}

PVScalarArray is the base class for scalar arrays.

interface PVScalarArray extends PVArray {
    ScalarArray getScalarArray();
}

For each scalar type an associated array data interface is defined. Each has a get and put method. For example:

public class DoubleArrayData {
    public double[] data;
    public int offset;
}

interface PVDoubleArray extends PVArray {
    int get(int offset, int len, DoubleArrayData data);
    int put(int offset,int len, double[] from, int fromOffset);
    void shareData(double[] from);
}

PVStructureArray is the interface for an array of structures where each element has the same iontrospection interface.

public class StructureArrayData {
    public PVStructure[] data;
    public int offset;
}

interface PVStructureArray extends PVArray{
    StructureArray getStructureArray();
    int get(int offset, int length, StructureArrayData data);
    int put(int offset,int length, PVStructure[] from, int fromOffset);
    void shareData(PVStructure[] from);
}

PVStructure is the data interface for a structure.

interface PVStructure extends PVField , BitSetSerializable{
    Structure getStructure();
    PVField[] getPVFields();
    PVField getSubField(String fieldName);
    PVField getSubField(int fieldOffset);
    void appendPVField(String fieldName,PVField pvField);
    void appendPVFields(String[] fieldNames,PVField[] pvFields);
    void removePVField(String fieldName);
    void replacePVField(PVField oldPVField,PVField newPVField);
    // The following are convenience methods
    PVBoolean getBooleanField(String fieldName);
    PVByte getByteField(String fieldName);
    PVShort getShortField(String fieldName);
    PVInt getIntField(String fieldName);
    PVLong getLongField(String fieldName);
    PVFloat getFloatField(String fieldName);
    PVDouble getDoubleField(String fieldName);
    PVString getStringField(String fieldName);
    PVScalarArray getScalarArrayField(String fieldName);
    PVStructureArray getStructureArrayField(String fieldName);
    PVStructure getStructureField(String fieldName);
    PVArray getArrayField(String fieldName,ScalarType elementType);
    String getExtendsStructureName();
    boolean putExtendsStructureName(String extendsStructureName);
    public boolean checkValid();
}

Introspection and Data creation

The following interface creates introspection instances:

public interface FieldCreate {
    Scalar createScalar(ScalarType scalarType);
    ScalarArray createScalarArray(ScalarType elementType);
    StructureArray createStructureArray(Structure elementStructure);
    Structure createStructure(String[] fieldNames, Field[] field);
    Structure createStructure(String id,String[] fieldNames, Field[] field);
    Structure appendField(Structure structure,String fieldName, Field field);
    Structure appendFields(Structure structure,String[] fieldNames, Field[] fields);
    Structure createStructure(Structure structToClone);
    Field deserialize(ByteBuffer buffer, DeserializableControl control);
}

The following interface creates data instances:

public interface PVDataCreate {
    PVField createPVField(Field field);
    PVField createPVField(PVField fieldToClone);
    PVScalar createPVScalar(Scalar scalar);
    PVScalar createPVScalar(ScalarType fieldType);
    PVScalar createPVScalar(PVScalar scalarToClone);
    PVScalarArray createPVScalarArray(ScalarArray array);
    PVScalarArray createPVScalarArray(ScalarType elementType);
    PVScalarArray createPVScalarArray(PVScalarArray arrayToClone;
    PVStructureArray createPVStructureArray(StructureArray structureArray);
    PVStructure createPVStructure(Structure structure);
    PVStructure createPVStructure(String[] fieldNames,Field[] fields);
    PVStructure createPVStructure(PVStructure structToClone);
    PVField[] flattenPVStructure(PVStructure pvStructure);
}

pvData Conversion

An interface named Convert provides all reasonable conversions to/from pvData. The convert utility is also used to implement the toString methods of PVField. See org.epics.pvdata.pv.Convert for details.

Package Summary

This document describes everything via Java definitions. The initial implementation is in Java but the functionality is also implemented in C++ (See pvDataCPP for details).

pvData is distributed as a sourceforge mercurial project named pvDataJava. It consists of the following java packages:

org.epics.pvdata.pv

The Java enum, interface, and class definitions that define pvData. This section provides a complete definition of what pvData is.

org.epics.pvdata.factory

Provides everything required for creating pvData. It provides the following factories:

FieldFactory
Creates introspection interfaces.
PVDataFactory
Creates data interfaces for all of the supported data types.
ConvertFactory
Converts between support data types.
StatusFactory
Status is a class for communication status between code modules.
StandardFieldFactory
Creates introspection objects for "well known" data.
StandardPVFieldFactory
Creates data objects for "well known" data.

Although pvDataFactory can provide the implementation for all supported data types, often it is desirable to provide other implementations. To make it easy to create alternate implementations a set of abstract and base classes are supplied.

org.epics.pvdata.property

Provides a way to associated properties with a field.

The basic idea is to associate properties with any field named "value". All the fields in the structure that contains the value field are considered properties of value with the field name being the property name. See that package overview for details.

This package also provides support for "well known" field definitions like timeStamp, alarm, display,etc. Code that uses pvData can be simplified by using this support.

org.epics.pvdata.misc

This package provides support that is used by pvData factories and might also be useful to software that uses pvData.

org.epics.pvdata.monitor

Provides the ability to monitor changes to an arbitrary subset of the fields in a record.

Package org.epics.pvdata.pv

Overview

This package has the complete set of enum, interface, and class definitions that describe PVData. The implementation is provided in package org.epics.pvdata.factory.

A PVStructure is a field that contains an array of subfields. Each field has code for accessing the field. The interface for each field is PVField or an interface that extends PVField. Each field also has an introspection interface, which is Field or an extension of Field. This package overview describes the complete set of data and introspection interfaces for pvData.

This package also describes an interface Convert, which provides a rich set of methods for converting and copying data between field.

The interface FieldCreate creates the introspection interfaces. The interface PVDataCreate creates the PVField interfaces. Between them they provide the ability to create every type of Field and PVField, i.e. they provide a complete implemenation of pvData. It is also possible for other code to provide implementations.

The interface StandardField provides introspection objects for standard fields. The interface StandardPVField provides data objects for standard fields.

The interface StatusCreate and class Status provide status object to pass between source modules.

Process Variable Reflection

Given the introspection object it is possible to introspect a field without requiring access to data. The reflection and data interfaces are separate because the data may not be available. For example when a PVAccess client connects to a PV, the client library can obtain the reflection information without obtaining any data. Only when a client issues an I/O request will data be available. This separation is especially important for arrays and structures so that a client can discover the type without requiring that a large array or structure be transported over the network.

Type

The types are defined by the Java definitions:

enum Type {
    scalar,
    scalarArray,
    structure,
    structureArray;
}

enum ScalarType {
    pvBoolean,
    pvByte, pvShort, pvInt, pvLong,
    pvUByte, pvUShort, pvUInt, pvULong,
    pvFloat,pvDouble,
    pvString;

    //Convenience methods
    public boolean isInteger();   // pvByte,...,pvULong
    public boolean isUInteger();   // pvUByte,...,pvULong
    public boolean isNumeric();    // pvByte,...pvDouble
    public boolean isPrimitive();  // pvBoolean,...pvDouble
    public static ScalarType getScalarType(String type);
    public String toString();
}

Serializable

The following interfaces are called by pvAccess for transporting data over the network. The abstract and base classes ensure that these methods are properly implemented.

interface Serializable {
    void serialize(ByteBuffer buffer,SerializableControl flusher);
    void deserialize(ByteBuffer buffer,DeserializableControl control);
}
where
serialize
Serialize into buffer. flusher is called when buffer is full.
deserialize
deserialize from byte buffer. control is called when more data is required.
interface SerializableControl {
    void flushSerializeBuffer();
    void ensureBuffer(int size);
    void alignBuffer(int alignment);
    void cachedSerialize(Field field, ByteBuffer buffer)
}
where
flushSerializeBuffer
Code that called serialize must empty the buffer. The call can block until the buffer is flushed.
ensureBuffer
Helper method. Ensures specified size of bytes, flushes if necessary.
alignBuffer
Align buffer.Note that this takes care only current buffer alignment. If streaming protocol is used, care must be taken that entire stream is aligned.
cachedSerialize
Serialize Field instance via cache.
interface DeserializableControl {
    void ensureData(int size);
    void alignData(int alignment);
    Field cachedDeserialize(ByteBuffer buffer)
}
where
ensureData
Helper method. Ensures specified size of bytes, provides it if necessary.
`
alignData
Align buffer.Note that this takes care only current buffer alignment. If streaming protocol is used, care must be taken that entire stream is aligned.
cachedDeserialize
Deserialize Field instance via cache.
interface SerializableArray extends Serializable {
    void serialize(ByteBuffer buffer, SerializableControl flusher, int offset, int count);
}       
where
serialize
Serialize field into given buffer.
interface BitSetSerializable {
   void serialize(ByteBuffer buffer, SerializableControl flusher, BitSet bitSet);
   void deserialize(ByteBuffer buffer, DeserializableControl control, BitSet bitSet);
}
where
serialize
Serialize field into given buffer. The BitSet shows the fields to serialize.
deserialize
Deserialize field into given buffer. The BitSet shows the fields to serialize.

Reflection

This section defines the complete set of Java PV reflection interfaces. Reflection consists of the following:

Field
A field has an ID and a type. It can be converted to a string. The format is the metadata format described in the overview.
Scalar
A scalar has a scalarType
ScalarArray
The element type is a scalarType
StructureArray
The field holds PVStructure[]. Each element has the same Structure interspection interface. A client can only get/put entire PVStructure elements NOT subfields of array elements.
Structure
Has fields that can be any of the supported types. In addition it has a name for each field.
FieldCreate
This is an interface that provides methods to create introspection interfaces. A factory is provides to create FieldCreate.
Field
    
interface Field extends Serializable {
    String getID();
    Type getType();
    void toString(StringBuilder buf));
    void toString(StringBuilder buf,int indentLevel);
    String toString();
} 
where
getID
Get the identification string. It can be empty. For scalar fields the ID is the metadata type, i.e. boolean, byte, etc. For scalarArray fields the ID is the metadata type, i.e. boolean[], byte[], etc. For structure fields the ID is determined by the argument specified when fieldCreate.createStructure is called. For structureArray fields the ID is XX[] where XX is the ID of the element structure.
getType
Get the field type.
toString
Create a String that shows the type. The format is the metadata syntax defined in the overview.
Scalar
interface Scalar extends Field {
    ScalarType getScalarType();
}
where
getScalarType
Return the ScalarType.
ScalarArray
interface ScalarArray extends Field{
    ScalarType getElementType();
}
where
getElementType
Return the ScalarType for each array element.
Structure
interface Structure extends Field{
    Field getField(String fieldName);
    int getFieldIndex(String fieldName);
    Field[] getFields();
    Field getField(int fieldIndex);
    String[] getFieldNames();
    String getFieldName(int fieldIndex);
}
where
getField
Return a field of the structure. The field can be requested by name or by index.
getFieldIndex
Return the index of the field with the specified fieldName.
getFields
Return the array of sub fields.
getFieldNames
Return the fieldNames for the fields.
getFieldName
Return the Field for the index.
StructureArray
interface StructureArray extends Field{
    Structure getStructure();
}
where
getStructure
Return the introspection interface for the array elements.
FieldCreate

Syntax for fieldName and id.

A fieldName must begin with a letter and must be a sequence of letters and digits. A letter is defined as 'A'-'Z', 'a'-'z','_', or any Unicode character that denotes a letter in a language. Similarly digits are '0'-'9' and any Unicode character that denotes a digit in a language. Note that this is the same as the Java syntax for variable names.

The syntax for id is the same except the '.' is also allowed after the initial letter.

interface FieldCreate {
    Scalar createScalar(ScalarType scalarType);
    ScalarArray createScalarArray(ScalarType elementType);
    StructureArray createStructureArray(Structure elementStructure);
    Structure createStructure(String[] fieldNames, Field[] fields);
    Structure createStructure(String id,String[] fieldNames, Field[] fields);
    Structure appendField(Structure structure,String fieldName, Field field);
    Structure appendFields(Structure structure,String[] fieldNames, Field[] fields);
    Structure createStructure(Structure structToClone);
    Field deserialize(ByteBuffer buffer, DeserializableControl control);
}
where
createScalar
Return the Scalar with the specified scalarType. Note that the implementation creates a single instance for each scalarType.
createScalarArray
Return the ScalarArray with the specified elementType. Note that the implementation creates a single instance for each elementType.
createStructureArray
Return a StructureArray with the specified introspection interface for each array element.
createStructure
Return a Structure. There are two methods. The first creates a structure with an empty ID.
appendField
Append a field to a structure.
appendFields
Append an array of fields to a structure.
deserialize
Deserialize a field from the the buffer.

status

Status provides a way to pass status back to client code. It is new and not currently used by pvData but may be in the future. It is used by code that uses pvData.

Status

interface Status extends Serializable  {
    public enum StatusType {OK,WARNING,ERROR,FATAL};
    StatusType getType();
    String getMessage();
    String getStackDump();
    boolean isOK();
    boolean isSuccess();
}
where
StatusType
An enum for the status type.
getType
Get the statusType.
getMessage
Get a message explaining the error.
getStackDump
Get a stack dump.
isOK
Is the status the singleton object for StatusType.OK?
isSuccess
Is the StatusType either OK or WARNING?

StatusCreate

interface StatusCreate {
    Status getStatusOK(); 
    Status createStatus(StatusType type, String message, Throwable cause);
    Status deserializeStatus(ByteBuffer buffer, DeserializableControl control);
}
where
getStatusOK
Get a singleton that returns StatusType.OK and a null message and stackDump.
createStatus
Create a new Status.
deserializeStatus
Use this method instead of Status.deserialize(), since this allows OK status optimization.

PVField - Data Interfaces

This section defines the Java Interfaces for accessing the data within a top level PVStructure.

PVField

PVField is the base interface for accessing data. Every field of a top level PVStructure has a PVField associated with it. This includes the top level structure itself.

interface PVField extends Serializable, Requester {
    String getFieldName();
    void setRequester(Requester requester);
    int getFieldOffset();
    int getNextFieldOffset();
    int getNumberFields();
    PVAuxInfo getPVAuxInfo();
    boolean isImmutable();
    void setImmutable();
    Field getField();
    PVStructure getParent();
    void renameField(String newName);
    void postPut();
    void setPostHandler(PostHandler postHandler);
    String toString();
    void toString(StringBuilder buf);
    void toString(StringBuilder buf,int indentLevel);
}

where

getFieldName
Get the field name for this field. This will be a empty string for the top level structure.
setRequester
Set a requester to receive messages sent to this field. A field can only have a single requester. An IllegalStateException is thrown if a requester is already attached.
getFieldOffset
Get offset of the PVField field within top level structure. Every field within the PVStructure has a unique offset. The top level structure has an offset of 0. The first field within the structure has offset equal to 1. The other offsets are determined by recursively traversing each structure of the tree.
getNextFieldOffset
Get the next offset. If the field is a scalar or array field then this is just offset + 1. If the field is a structure it is the offset of the next field after this structure. Thus (nextOffset - offset) is always equal to the total number of fields within the field.
getNumberFields
Get the total number of fields in this field. This is nextFieldOffset - fieldOffset.
getPVAuxInfo
Get the PVAuxInfo for this field. PVAuxInfo is described below.
isImmutable
Is the field immutable?
setImmutable
Make the field immutable. Once a field is immutable it can never be changed since there is no method to again make it mutable. This is an important design decision because it allows immutable array fields to share the internal primitive data array.
getField
Get the reflection interface.
getParent
Get the interface for the parent or null if this is the top level PVStructure.
renameField
Rename the field name.
postPut
If this field is a field of a record pvRecordField.postPut() is called. If not a field of a record nothing happens.
setPostHandler
Set the handler for postPut. At most one handler can be set.
toString
Converts the field data to a string. This is mostly for debugging purposes. The format is the meta data format described in the pvData project overview. Note: The actual conversion is done by the Convert facility.

Requester

A PVField extends Requester. Requester is present so that when database errors are found there is someplace to send a message.

In the pvIOCJava, PVRecord provides methods to register message requesters. Also a PVDatabase provides an identical method. Thus when a message is generated for a field it is propagated up to the record with the full field name attached and then propagated to the PVDatabase which sends the messages to the registered requesters.

enum MessageType {info,warning,error,fatalError}

interface Requester {
    String getRequesterName();
    void message(String message, MessageType messageType);
}

where

MessageType
Type of message.
Requester
The default implementation is:
  • getRequesterName
    This is the full field name concatenated to the record name.
  • message
    For the default implementation, PVField prepends the full field name to the message and calls PVRecord.message. The default implementation for PVRecord either displays the message on stdout or stderr or gives the message to message requsters.

PVAuxInfo

AuxInfo (Auxillary Information) is information about a field that is application specific. It will not be available outside the application that implements the database. In particular it will not be made available to Channel Access. It is used by the database itself to override the default implementation of fields. The JavaIOC uses it for attaching support code. Database Configuration and other tools can use it for configuration information. Each Field and each PVField can have have an arbitrary number of auxInfos. An auxInfo is a (key,PVScalar) pair where key is a string.

public interface PVAuxInfo {
    PVField getPVField();
    PVScalar createInfo(String key,ScalarType scalarType);
    Map<String,PVScalar> getInfos();
    PVScalar getInfo(String key);
    void toString(StringBuilder buf);
    void toString(StringBuilder buf,int indentLevel);
}

where

getPVField
Get the PVField to which this PVAuxInfo is attached.
createInfo
Create a new PVScalar of type scalarType.
getInfos
Get a map of all the auxInfos.
getInfo
Get the PVScalar with the specified key.
toString
Print all the auxInfo data in metadata format.

PVScalar and extensions

interface PVScalar extends PVField {
    Scalar getScalar();
}
Primitive PVField types

The interfaces for primitive data types are:

interface PVBoolean extends PVScalar {
    boolean get();
    void put(boolean value);
}

interface PVByte extends PVScalar {
    byte get();
    void put(byte value);
}

interface PVShort extends PVScalar {
    short get();
    void put(short value);
}

interface PVInt extends PVScalar {
    int get();
    void put(int value);
}

interface PVLong extends PVScalar {
    long get();
    void put(long value);
}

interface PVUByte extends PVScalar {
    byte get();
    void put(byte value);
}

interface PVUShort extends PVScalar {
    short get();
    void put(short value);
}

interface PVUInt extends PVScalar {
    int get();
    void put(int value);
}

interface PVULong extends PVScalar {
    long get();
    void put(long value);
}

interface PVFloat extends PVScalar {
    float get();
    void put(float value);
}

interface PVDouble extends PVScalar {
    double get();
    void put(double value);
}

NOTE: The implementation for each unsigned integer is the same as for the same signed type. This is because Java does not implement unsigned primitive types.

PVString

The interface for string is:

interface PVString extends PVScalar, SerializableArray {
    String get();
    void put(String value);
}

PVArray and Extensions

PVArray is the base interface for all the other PV Array interfaces. It extends PVField and provides the additional methods:

interface PVArray extends PVField, SerializableArray {
    int getLength();
    void setLength(int len);
    int getCapacity();
    void setCapacity(int len);
    boolean isCapacityMutable();
    void setCapacityMutable(boolean isMutable);
}
getLength
Get the current length. This is less that or equal to the capacity.
setLength
Set the length. If the PVField is not mutable then an exception is thrown. If this is greater than the capacity setCapacity is called.
getCapacity
Get the capacity, i.e. this is the sized of the underlying data array.
setCapacity
Set the capacity. The semantics are implementation dependent but typical semantics are as follows: If the capacity is not mutable an exception is thrown. A new data array is created and data is copied from the old array to the new array.
isCapacityMutable
Is the capacity mutable
setCapacityMutable
Specify if the capacity can be changed.
PVArray Extensions

The interface for each array type has get and put methods which have the same arguments except for the data type. For example PVDoubleArray is:

public class DoubleArrayData {
    public double[] data;
    public int offset;
}
interface PVDoubleArray extends PVScalarArray {
    int get(int offset, int len, DoubleArrayData data);
    int put(int offset, int len, double[]from, int fromOffset);
    void shareData(double[] from);
}i

Get "exposes" it's internal array by setting data.data and data.offset. The caller is responsible for copying the array elements. This violates the principle that objects should not expose their internal data but is done for efficency. For example it makes it possible to copy between arrays with identical element types via a call to System.arraycopy without requiring an intermediate array.

Both get and put return the number of elements actually transfered. The arguments are:

offset
The offset in the PV array.
len
The maximum number of elements to transfer. The number actually transfered will be less than or equal to this value.
data
Get sets data.data to it's internal array and data.offset to the offset into the array. The caller is responsible for the actual data transfer.
from
The array from which the data is taken. This array is supplied by the caller
fromOffset
The offset in from

The caller must be prepared to make multiple calls to retrieve or put an entire array. A caller should accept or put partial arrays. For example the following reads an entire array:

double[] getArray(PVDoubleArray pv)
{
    int len = pv.getLength();
    double[] storage = new double[len];
    DoubleArrayData data = new DoubleArrayData();
    int offset = 0;
    while(offset < len) {
        int num = pv.get(offset,(len-offset),data);
        System.arraycopy(data.data,data.offset,storage,offset,num);
        offset += num;
    }
    return storage;
}

shareData results in the PVArray using the primitive array that is passed to this method. This is most useful for immutable arrays. In this case the caller must set the PVArray to be immutable. If the PVArray is not immutable then the application is responsibility for coordinating access to the array. This violates the principle that objects should not expose their internal data but is important for immutable arrays. For example pvData and the javaIOC define many enumerated structures where an enumerated structure has twofields: index and choices. Choices is a PVStringArray that holds the enumerated choices. Index is a PVInt that is the index of the currently selected choice. The choices can be immutable. Allowing the choices internal String[] to be shared between all the instances of an enumerated structure saves on storage. Another reason for allowing shared data is so that an application which processes an array can be separated into multiple modules that directly access the internal data array of a PVArray. This can be required for minimizing CPU overhead. In this case it is the applications responsibility to coordinate access to the array.

Complete set of PVArray Extensions
interface PVScalarArray extends PVArray {
    ScalarArray getScalarArray();
}

public class BooleanArrayData {
    public boolean[] data;
    public int offset;
}
interface PVBooleanArray extends PVScalarArray {
    int get(int offset, int len, BooleanArrayData data);
    int put(int offset, int len, boolean[]from, int fromOffset);
    void shareData(boolean[] from);
}

public class ByteArrayData {
    public byte[] data;
    public int offset;
}
interface PVByteArray extends PVScalarArray {
    int get(int offset, int len, ByteArrayData data);
    int put(int offset, int len, byte[]from, int fromOffset);
    void shareData(byte[] from);
}
interface PVUByteArray extends PVScalarArray {
    int get(int offset, int len, ByteArrayData data);
    int put(int offset, int len, byte[]from, int fromOffset);
    void shareData(byte[] from);
}

public class ShortArrayData {
    public short[] data;
    public int offset;
}
interface PVShortArray extends PVScalarArray {
    int get(int offset, int len, ShortArrayData data);
    int put(int offset, int len, short[]from, int fromOffset);
    void shareData(short[] from);
}
interface PVUShortArray extends PVScalarArray {
    int get(int offset, int len, ShortArrayData data);
    int put(int offset, int len, short[]from, int fromOffset);
    void shareData(short[] from);
}

public class IntArrayData {
    public int[] data;
    public int offset;
}
interface PVIntArray extends PVScalarArray {
    int get(int offset, int len, IntArrayData data);
    int put(int offset, int len, int[]from, int fromOffset);
    void shareData(int[] from);
}
interface PVUIntArray extends PVScalarArray {
    int get(int offset, int len, IntArrayData data);
    int put(int offset, int len, int[]from, int fromOffset);
    void shareData(int[] from);
}

public class LongArrayData {
    public long[] data;
    public int offset;
}
interface PVLongArray extends PVScalarArray {
    int get(int offset, int len, LongArrayData data);
    int put(int offset, int len, long[]from, int fromOffset);
    void shareData(long[] from);
}
interface PVULongArray extends PVScalarArray {
    int get(int offset, int len, LongArrayData data);
    int put(int offset, int len, long[]from, int fromOffset);
    void shareData(long[] from);
}

public class FloatArrayData {
    public float[] data;
    public int offset;
}
interface PVFloatArray extends PVScalarArray {
    int get(int offset, int len, FloatArrayData data);
    int put(int offset, int len, float[]from, int fromOffset);
    void shareData(float[] from);
}

public class DoubleArrayData {
    public double[] data;
    public int offset;
}
interface PVDoubleArray extends PVScalarArray {
    int get(int offset, int len, DoubleArrayData data);
    int put(int offset, int len, double[]from, int fromOffset);
    void shareData(double[] from);
}

public class StringArrayData {
    public String[] data;
    public int offset;
}
interface PVStringArray extends PVScalarArray {
    int get(int offset, int len, StringArrayData data);
    int put(int offset, int len, String[]from, int fromOffset);
    void shareData(String[] from);
}

public class StructureArrayData {
    public PVStructure[] data;
    public int offset;
}

interface PVStructureArray extends PVArray {
    StructureArray getStructureArray();
    int get(int offset, int length, StructureArrayData data);
    int put(int offset,int length, PVStructure[] from, int fromOffset);
    void shareData(PVStructure[] from);
}

NOTES:

Unsigned types
The implementation for each unsigned integer is the same as for the same signed type. This is because Java does not implement unsigned primitive types.
PVStructureArray
A client can only access the data in the elements of the array via the get and put methods, i.e. it is not possible to access subfields indirectly. PVStructureArray.getNumberFields() returns 1, i.e. the field looks like a leaf field.

PVStructure

The interface for a structure is:

interface PVStructure extends PVField, BitSetSerializable {
    Structure getStructure();
    PVField[] getPVFields();
    PVField getSubField(String fieldName);
    PVField getSubField(int fieldOffset);
    void appendPVField(PVField pvField);
    void appendPVFields(PVField[] pvFields);
    void removePVField(String fieldName);
    void replacePVField(PVField oldPVField,PVField newPVField);
    // the following are convenience methods
    PVBoolean getBooleanField(String fieldName);
    PVByte getByteField(String fieldName);
    PVShort getShortField(String fieldName);
    PVInt getIntField(String fieldName);
    PVLong getLongField(String fieldName);
    PVFloat getFloatField(String fieldName);
    PVDouble getDoubleField(String fieldName);
    PVString getStringField(String fieldName);
    PVStructure getStructureField(String fieldName);
    PVScalarArray getScalarArrayField(String fieldName,ScalarType elementType);
    PVStructureArray getStructureArrayField(String fieldName);
    String getExtendsStructureName();
    boolean putExtendsStructureName(String extendsStructureName);
}

where

getStructure
Get the introspection interface for the structure.
getPVFields
Returns the array of subfields. The set of subfields must all have different field names.
getSubField(String fieldName)
Get a subField of a field. For a PVStructure a non-null result is returned if fieldName is a field of the PVStructure. The fieldName can be of the form name.name...
getSubField(int fieldOffset)
Get the field located a fieldOffset, where fieldOffset is relative to the top level structure. This returns null if the specified field is not located within this PVStructure.
appendPVField
Append pvField to the end of this PVStructure. This should NOT be called if any code is attached to any of the fields in the top level structure.
appendPVFields
Append an array of pvFields to the end of this structure. Note that if the original number of fields is 0 than pvFields replaces the original. Thus the caller must NOT reuse pvFields after calling this method. This should NOT be called if any code is attached to any of the fields in the top level structure
removePVField
Remove the specified field from this structure. This should NOT be called if any code is attached to any of the fields in the top level structure.
replacePVField
Replace a field with a new field.
getBooleanField
Look for fieldName. If found and it has the correct type return the interface. This and the following methods are convenience methods that allow a user to get the interface to a subfield without requiring introspection. fieldName can be of the form name.name...
getByteField
Look for fieldName. If found and it has the correct type return the interface.
getShortField
Look for fieldName. If found and it has the correct type return the interface.
getIntField
Look for fieldName. If found and it has the correct type return the interface.
getLongField
Look for fieldName. If found and it has the correct type return the interface.
getFloatField
Look for fieldName. If found and it has the correct type return the interface.
getDoubleField
Look for fieldName. If found and it has the correct type return the interface.
getStringField
Look for fieldName. If found and it has the correct type return the interface.
getScalarArrayField
Look for fieldName. If found and it has the correct type return the interface.
getStructureArrayField
Look for fieldName. If found and it has the correct type return the interface.
getExtendsStructureName
Get the name of structure that this structure extends.
putExtendsStructureName
Specify the structure that this structure extends.

PVDataCreate

PVDataCreate is an interface that provides methods that create PVField interfaces. A factory is provided that creates PVDataCreate.

interface PVDataCreate {
    PVField createPVField(Field field);
    PVField createPVField(PVField fieldToClone);
    PVScalar createPVScalar(Scalar scalar);
    PVScalar createPVScalar(ScalarType fieldType);
    PVScalar createPVScalar(PVScalar scalarToClone);
    PVScalarArray createPVScalarArray(ScalarArray array);
    PVScalarArray createPVScalarArray(ScalarType elementType);
    PVScalarArray createPVScalarArray(PVScalarArray arrayToClone);
    PVStructureArray createPVStructureArray(StructureArray structureArray);
    PVStructure createPVStructure(Structure structure);
    PVStructure createPVStructure(String[] fieldNames,PVField[] pvFields);
    PVStructure createPVStructure(PVStructure structToClone);
    PVField[] flattenPVStructure(PVStructure pvStructure);
}
where
createPVField
The PVField is created reusing the Field interface. Two methods are provided. Each calls the corresponding createPVScalar, createPVArray, or createPVStructure depending in the type of the argument.
createPVScalar
Creates an instance of a PVScalar. Three versions are supplied. The first is passed an introspection interface. The second provides the field name and the scalarType. The last provides a field name and a PVScalar to clone. The newly created PVScalar will have the same auxInfos as the original.
createPVScalarArray
Create an instance of a PVArray. Three versions are supplied. The first is passed an introspection interface. The second provides the field name and the elementType. The last provides a field name and a PVArray to clone. The newly created PVArray will have the same auxInfos as the original.
createPVStructureArray
Create a PVStructureArray. It must be passed a structureToClone. This will become the Structure interface for ALL elements of the PVStructureArray. It MUST be used to create any new array elements.
createPVStructure
Create an instance of a PVStructure. Three methods are provided. The first method uses a previously created structure introspection interface. The second uses a PVField[]. The third initializes the subfields by cloning the fields contained in structToClone. The newly created sub-fields will have the same values and auxInfos as the original. If structToClone is null then the new structure is initialized to have 0 sub-fields.
flattenPVStructure
Create an array of PVFields for the fields in the PVStructure. The order is according to fieldOffset.

Convert

NOTE: copying immutable array fields. If an entire immutable array field is copied to another array that has the same elementType, both offsets are 0, and the length is the length of the source array, then the shareData method of the target array is called and the target array is set immutable. Thus the source and target share the same primitive array.

This section describes the supported conversions between data types.

interface Convert {
    void getFullFieldName(StringBuilder builder,PVField pvField)
    void getString(StringBuilder buf,PVField pv, int indentLevel);
    void getString(StringBuilder buf,PVField pv);
    void fromString(PVScalar pv,String from);
    void fromString(PVScalarArray pv,String from);
    int fromStringArray(PVScalarArray pv,
         int offset, int len, String[]from, int fromOffset);
    int toStringArray(PVScalarArray pv,
         int offset, int len, String[]to, int toOffset);
    boolean isCopyCompatible(Field from, Field to);
    void copy(PVField from,PVField to);
    boolean isCopyScalarCompatible(Field from, Field to);
    void copyScalar(PVField from, PVField to);
    boolean isCopyScalarArrayCompatible(ScalarArray from, ScalarArray to);
    int copyScalarArray(PVScalarArray from, int offset,
         PVScalarArray to, int toOffset, int len);
    boolean isCopyStructureCompatible(Structure from, Structure to);
    void copyStructure(PVStructure from, PVStructure to);
    boolean isCopyStructureArrayCompatible(StructureArray from, StructureArray to);
    void copyStructureArray(PVStructureArray from, PVStructureArray to);
    // For the following the pv Type must be PVByte, ...., PVDouble
    byte toByte(PVField pv);
    short toShort(PVField pv);
    int   toInt(PVField pv);
    long  toLong(PVField pv);
    float toFloat(PVField pv);
    double toDouble(PVField pv);
    String toString(PVScalar pv);
    void  fromByte(PVField pv, byte from);
    void  fromShort(PVField pv, short from);
    void  fromInt(PVField pv, int from);
    void  fromLong(PVField pv, long from);
    void  fromUByte(PVField pv, byte from);
    void  fromUShort(PVField pv, short from);
    void  fromUInt(PVField pv, int from);
    void  fromULong(PVField pv, long from);
    void  fromFloat(PVField pv, float from);
    void  fromDouble(PVField pv, double from);
// For the following the element type must be pvByte, ...., pvDouble
    int toByteArray(PVScalarArray pv,
        int offset, int len, byte[]to, int toOffset);
    int toShortArray(PVScalarArray pv,
        int offset, int len, short[]to, int toOffset);
    int toIntArray(PVScalarArray pv,
        int offset, int len, int[]to, int toOffset);
    int toLongArray(PVScalarArray pv,
        int offset, int len, long[]to, int toOffset);
    int toFloatArray(PVScalarArray pv,
        int offset, int len, float[]to, int toOffset);
    int toDoubleArray(PVScalarArray pv,
        int offset, int len, double[]to, int toOffset);
    int fromByteArray(PVScalarArray pv,
        int offset, int len, byte[]from, fromOffset);
    int fromShortArray(PVScalarArray pv,
        int offset, int len, short[]from, fromOffset);
    int fromIntArray(PVScalarArray pv,
        int offset, int len, int[]from, fromOffset);
    int fromLongArray(PVScalarArray pv,
        int offset, int len, long[]from, fromOffset);
    int fromUByteArray(PVScalarArray pv,
        int offset, int len, byte[]from, fromOffset);
    int fromUShortArray(PVScalarArray pv,
        int offset, int len, short[]from, fromOffset);
    int fromUIntArray(PVScalarArray pv,
        int offset, int len, int[]from, fromOffset);
    int fromULongArray(PVScalarArray pv,
        int offset, int len, long[]from, fromOffset);
    int fromFloatArray(PVScalarArray pv,
        int offset, int len, float[]from, fromOffset);
    int fromDoubleArray(PVScalarArray pv,
        int offset, int len, double[]from, fromOffset);
    void newLine(StringBuilder builder, int indentLevel);
}

The array methods all return the number of elements copied or converted. This can be less than len if the PVField array contains less than len elements.

newLine is a convenience method for code that implements toString It generates a newline and inserts blanks at the beginning of the newline.

The getString methods dump the data in the metadata syntax described in the pvData project overview. Note that the toString methods of PVField are implemented by calling these convert methods.

StandardField and StandardPVField

Warning: The concept of Standard Field is closely related to property which is described below. The section on property provides details about alarm, timeStamp, display, control, and enumerated. That section should be read in conjuction with this section.

A standard field is a field that tools know how to use. pvData defines and provides support for the following standard fields.

enumerated
This is a structure that has two subfields: index, and choices
value
This is any field with the name "value". It can be any type. The other standard fields can provide "properties" for the value field.
timeStamp
Encodes a time stamp. It can be a standalone field or be a property if a value field, in which case it should be a sub field of the same structure as the value field.
alarm
Encodes an alarm. It is normally a property if a value field, in which case it should be a sub field of the same structure as the value field.
display
Encodes a set of information for displaying a scalar or scalarArray value. It is normally a property if a value field, in which case it should be a sub field of the same structure as the value field.
control
Encodes a set of information for limits for a scalar or scalarArray value. It is normally a property if a value field, in which case it should be a sub field of the same structure as the value field.
valueAlarm
Defines a set of values for setting alarm values for a scalar value. It has separate definitions for booleanAlarm, byteAlarm, shortAlarm, intAlarm, longAlarm, floatAlarm, and doubleAlarm. There is also an enumeratedAlarm for an enumerated value field.

StandardField

interface StandardField {
    Structure scalar(ScalarType scalarType,String properties);
    Structure scalarArray(ScalarType elementType, String properties);
    Structure structureArray(Structure structure,String properties);
    Structure enumerated();
    Structure enumerated(String properties);
    Structure alarm();
    Structure timeStamp();
    Structure display();
    Structure control();
    Structure booleanAlarm();
    Structure byteAlarm();
    Structure shortAlarm();
    Structure intAlarm();
    Structure longAlarm();
    Structure floatAlarm();
    Structure doubleAlarm();
    Structure enumeratedAlarm();
}
where
scalar
Create a Structure that has a scalar field named value and with the specfied scalarType. The structure can have aditional fields that are properties of the value field. properties is some combination of alarm, timeStamp, display, control, and valueAlarm.
scalarArray
Create a Structure that has a scalarArray field named value and with the specfied elementType,. The structure can have aditional fields that are properties of the value field. properties is some combination of alarm, timeStamp, display, and control.
structureArray
Create a Structure that has a structureArray field named value and with the specfied structure as the introspection interface for each array element,. The structure can have aditional fields that are properties of the value field. properties is some combination of alarm and timeStamp.
enumerated()
Create an enumerated Structure
enumerated(String properties)
Create a Structure that has an enumerated structure field named value. The structure can have aditional fields that are properties of the value field. properties is some combination of alarm, timeStamp, and enumeratedAlarm.
alarm
Create an alarm Structure.
timeStamp
Create a timeStamp Structure.
display
Create an display Structure.
control
Create a control Structure.
booleanAlarm
Create a booleanAlarm Structure.
byteAlarm
Create a byteAlarm Structure.
shortAlarm
Create a shortAlarm Structure.
intAlarm
Create a intAlarm Structure.
longAlarm
Create a longAlarm Structure.
floatAlarm
Create a floatAlarm Structure.
doubleAlarm
Create a doubleAlarm Structure.
enumeratedAlarm
Create a enumearatedAlarm Structure.

StandardPVField

interface StandardPVField {
    PVStructure scalar(ScalarType type,String properties);
    PVStructure scalarArray(ScalarType elementType, String properties);
    PVStructure structureArray(Structure structure,String properties);
    PVStructure enumerated(String[] choices);
    PVStructure enumerated(String[] choices,String properties);
}
where
scalar
Create a PVStructure that has a scalar field named value and with the specfied scalarType. The structure can have aditional fields that are properties of the value field. properties is some combination of alarm, timeStamp, display, control, and valueAlarm.
scalarArray
Create a PVStructure that has a scalarArray field named value and with the specfied elementType,. The structure can have aditional fields that are properties of the value field. properties is some combination of alarm, timeStamp, display, and control.
structureArray
Create a PVStructure that has a structureArray field named value and with the specfied structure as the introspection interface for each array element,. The structure can have aditional fields that are properties of the value field. properties is some combination of alarm and timeStamp.
enumerated(String[] choices)
Create an enumerated PVStructure. The choices field is initialized with choices and set immutable.
enumerated(String[] choices,String properties)
Create a PVStructure that has an enumerated structure field named value. The choices field of value is initialized with choices and set immutable. The structure can have aditional fields that are properties of the value field. properties is some combination of alarm, timeStamp, and enumeratedAlarm.

Examples

Accessing PVData

Assume that code wants to access two fields from a PVStructure:

value
Must be a PVDouble.
timeStamp
Just look for field with this name.

The following code uses introspection to get the desired information.

String getValueAndTimeStamp(PVStructure pvStructure) {
   PVField valuePV = pvStructure.getSubField("value");
   if(valuePV==null) {
       return "value field not found";
   }
   if(valuePV.getField.getType!=Type.scalar) {
       return "value field is not a scalar";
   }
   Scalar scalar = (Scalar)valuePV.getField();
   if(scalar.getScalarType!=ScalarType.pvDouble) {
       return "value field is not a double";
   }
   PVDouble pvDouble = (PVDouble)valuePV;
   PVField timeStampPV = pvStructure.getSubField("timeStamp");
   if(timeStampPV==null) {
       return "timeStamp field not found";
   }
   double value = valuePV.get();
   return value + " timeStamp " + timeStampPV.toString();
}

Creating PVData

Example of creating a scalar field.

PVDataCreate pvDataCreate = PVDataFactory.getPVDataCreate();
PVDouble pvValue = pvDataCreate.createPVScalar(ScalarType.pvDouble);

Create a structure.

    
FieldCreate fieldCreate = FieldFactory.getFieldCreate();
PVDataCreate pvDataCreate = PVDataFactory.getPVDataCreate();

PVStructure create() {
    Field[] fields = new Field[2];
    String[] fieldNames = new String[2];
    fields[0] = fieldCreate.createScalar(ScalarType.pvLong);
    fields[1] = fieldeCreate.createScalar(ScalarType.pvInt);
    fieldNames[0] = "a";
    fieldNames[1] = "b";
    PVStructure pvStructure = pvDataCreate.createPVStructure(
        fieldNames,fields);
    return(pvStructure);
}

StandardPVField provides and easy way to create fields. For example:

StandardPVField standardPVField = StandardPVFieldFactory.getStandardPVField();
PVStructure pvStructure = standardPVField.scalar(
    ScalarType.pvDouble,
    "alarm,timeStamp.display,control,valueAlarm");

Package org.epics.pvdata.factory

Overview

This package provides factories and classes to implement everything defined in package org.epics.pvdata.pv

Factory

FieldFactory

public final class FieldFactory {
    public static FieldCreate getFieldCreate();
}

FieldFactory automatically creates a single instance of FieldCreate and provides a method to get the interface.

PVDataFactory

public class PVDataFactory {
    public static PVDataCreate getPVDataCreate();
}

PVDataFactory automatically creates a single instance of PVDataCreate and provides a method to get the interface.

ConvertFactory

public final class ConvertFactory {
    public static Convert getConvert();
}

ConvertFactory automatically creates a single instance of Convert and provides a method to get the interface.

StatusFactory

public final class StatusFactory {
    public static StatusCreate getStatusCreate();
}

This provides a singleton that implements StatusCreate.

StandardFieldFactory

public final class StandardFieldFactory {
    public static StandardField getStandardField();
}

This provides a singleton that implements StandardField.

StandardPVFieldFactory

public final class StandardPVFieldFactory {
    public static StandardPVField getStandardPVField();
}

This provides a singleton that implements StandardPVField.

Base Introspection Classes

This section describes base classes for implementing Field instances , i.e. introspection instances. For many applications they provide a complete introspection implementation but they could be extended if necessary.

BaseField

    
    public class BaseField implements Field {
        public BaseField(String fieldName, Type type);
        // all Field methods
    }

BaseScalar

    public class BaseScalar extends BaseField implements Scalar {
        public BaseScalar(String fieldName,ScalarType scalarType);
        // all Scalar methods
    }

BaseStructure

    public class BaseStructure extends BaseField implements Structure {
        public BaseStructure(String fieldName,Field[] field);
        // all Structure methods
    }

BaseScalarArray

    public class BaseScalarArray extends BaseField implements ScalarArray {
        public BaseScalarArray(String fieldName,ScalarType elementType);
        // all ScalarArray methods  
    }

BaseStructureArray

    public class BaseStructureArray extends BaseArray implements StructureArray {
        public BaseStructureArray(String fieldName,Field[] fields);
        // all StructureArray methods
    }
}

Abstract and Base Classes for PVField

BasePVAuxInfo

This is a complete implementation of PVAuxInfo.

public class BasePVAuxInfo implements PVAuxInfo {
    public BasePVAuxInfo(PVField pvField);
    // All PVAuxInfo methods
}

AbstractPVField

This is an abstract base class for implementing PVField interfaces. It MUST be the base class for any class that extends PVField.

public abstract class AbstractPVField implements PVField{
    protected static Convert convert = ConvertFactory.getConvert();
    protected AbstractPVField(Field field);
    // All public methods of PVField
}

The public methods are described in package org.epics.pvdata.pv. The protected methods are:

convert
A convenience for derived classes since implementations often need access to the conversion facility.
AbstractPVField
The constructor which must be called by any derived class.

Classes For PVStructure

BasePVStructure

The following is a base class for any code that implements PVStructure. Any code that implements PVStructure MUST extend this class.

public class BasePVStructure extends AbstractPVField implements PVStructure
    public BasePVStructure(Structure structure);
    // all public methods of PVStructure
}

Classes For PVScalar

AbstractPVScalar

The following is an abstract base class for implementing PVScalar. It MUST be the base class for any code that implements an extension of PVScalar.

public class AbstractPVScalar extends AbstractPVField implements PVScalar {
    protected AbstractPVScalar(Scalar scalar);
    public Scalar getScalar();
}

BasePVBoolean

public class BasePVBoolean extends AbstractPVScalar implements PVBoolean
{
    protected boolean value = false;
    public BasePVBoolean(Scalar scalar);
    // public methods of PVBoolean
}

BasePVByte

public class BasePVByte extends AbstractPVScalar implements PVByte
{
    protected byte value;
    public BasePVByte(Scalar scalar);
    // public methods of PVByte
}

BasePVShort

public class BasePVShort extends AbstractPVScalar implements PVShort
{
    protected short value;
    public BasePVShort(Scalar scalar);
    // public methods of PVShort
}

BasePVInt

public class BasePVInt extends AbstractPVScalar implements PVInt
{
    protected int value;
    public BasePVInt(Scalar scalar);
    // public methods of PVInt
}

BasePVLong

public class BasePVLong extends AbstractPVScalar implements PVLong
{
    protected long value;
    public BasePVLong(Scalar scalar);
    // public methods of PVLong
}

BasePVBUyte

public class BasePVUyte extends AbstractPVScalar implements PVUyte
{
    protected byte value;
    public BasePVUyte(Scalar scalar);
    // public methods of PVUyte
}

BasePVUShort

public class BasePVUhort extends AbstractPVScalar implements PVUhort
{
    protected short value;
    public BasePVUhort(Scalar scalar);
    // public methods of PVUhort
}

BasePVUInt

public class BasePVUnt extends AbstractPVScalar implements PVUnt
{
    protected int value;
    public BasePVUnt(Scalar scalar);
    // public methods of PVUnt
}

BasePVULong

public class BasePVUong extends AbstractPVScalar implements PVUong
{
    protected long value;
    public BasePVUong(Scalar scalar);
    // public methods of PVUong
}

BasePVFloat

public class BasePVFloat extends AbstractPVScalar implements PVFloat
{
    protected float value;
    public BasePVFloat(Scalar scalar);
    // public methods of PVFloat
}

BasePVDouble

public class BasePVDouble extends AbstractPVScalar implements PVDouble
{
    protected double value;
    public BasePVDouble(Scalar scalar);
    // public methods of PVDouble
}

BasePVString

public class BasePVString extends AbstractPVScalar implements PVString
{
    protected String value;
    public BasePVString(Scalar scalar);
    // public methods of PVString
}

Classes for PVArray

AbstractPVArray

The following is a abstract class for creating array fields. Any code that implements any extension of PVArray must extend this class.

public abstract class AbstractPVArray extends AbstractPVField implements PVArray{
    protected int length = 0;
    protected int capacity;
    protected boolean capacityMutable = true;
    
    protected AbstractPVArray(Array array);
    abstract public void setCapacity(int capacity);
    // public methods of PVArray
}

AbstractPVScalarArray

The following is an abstract class for creating scalar arrays. All implementations of scalar arrays should extend this class.

public abstract class AbstractPVScalarArray
   extends AbstractPVArray implements PVScalarArray
{
    protected AbstractPVScalarArray(ScalarArray array);
    public ScalarArray getScalarArray();
}

For each ScalarType there is a base class for implementing the corresponding array type. For most uses it is not necessary to extend these classes.

BasePVBooleanArray

public class BasePVBooleanArray extends AbstractPVArray implements PVBooleanArray
{
    protected boolean[] value;
    // implements all PVBooleanArray methods
}

BasePVByteArray

public class BasePVByteArray extends AbstractPVArray implements PVByteArray
{
    protected byte[] value;
    // implements all PVByteArray methods
}

BasePVShortArray

public class BasePVShortArray extends AbstractPVArray implements PVShortArray
{
    protected short[] value;
    // implements all PVShortArray methods
}

BasePVIntArray

public class BasePVIntArray extends AbstractPVArray implements PVIntArray
{
    protected int[] value;
    // implements all PVIntArray methods
}

BasePVLongArray

public class BasePVLongArray extends AbstractPVArray implements PVLongArray
{
    protected long[] value;
    // implements all PVLongArray methods
}

BasePVUByteArray

public class BasePVUByteArray extends AbstractPVArray implements PVUByteArray
{
    protected byte[] value;
    // implements all PVUByteArray methods
}

BasePVUShortArray

public class BasePVUShortArray extends AbstractPVArray implements PVUShortArray
{
    protected short[] value;
    // implements all PVUShortArray methods
}

BasePVUIntArray

public class BasePVUIntArray extends AbstractPVArray implements PVUIntArray
{
    protected int[] value;
    // implements all PVUIntArray methods
}

BasePVULongArray

public class BasePVULongArray extends AbstractPVArray implements PVULongArray
{
    protected long[] value;
    // implements all PVULongArray methods
}

BasePVFloatArray

public class BasePVFloatArray extends AbstractPVArray implements PVFloatArray
{
    protected float[] value;
    // implements all PVFloatArray methods
}

BasePVDoubleArray

public class BasePVDoubleArray extends AbstractPVArray implements PVDoubleArray
{
    protected double[] value;
    // implements all PVDoubleArray methods
}

BasePVStringArray

public class BasePVStringArray extends AbstractPVArray implements PVStringArray
{
    protected String[] value;
    // implements all PVStringArray methods
}

BasePVStructureArray

public class BasePVStructureArray  extends AbstractPVArray implements PVStructureArray
{
   // implements all PVStructureArray methods
}

Package org.epics.pvdata.property

Definition of Property

Only fields named "value" have properties. A record can have multiple value fields, which can appear in the top level structure of a record or in a substructure. All other fields in the structure containing a value field are considered properties of the value field. The fieldname is also the property name. The value field can have any type, i.e. scalar, scalarArray, or structure. Typical property fields are timeStamp, alarm, display, control, and history. The timeStamp is a special case. If it appears anywhere in the structure hieraracy above a value field it is a property of the value field.

For example the following top level structure has a single value field. The value field has properties alarm, timeStamp, and display.

structure counterOutput
    double value
    alarm_t
        int severity 0
        int status 0
        string message
    double value
    display_t
        double limitLow 0.0
        double limitHigh 10.0
        string description "Sample Description"
        string format "%f"
        string units volts

The following example has three value fields each with properties alarm and timeStamp. Voltage, Current, and Power each have a different alarms but all share the timeStamp.

structure powerSupplyValue
    double value
    alarm_t
        int severity 0
        int status 0
        string message

structure powerSupplySimple
    alarm_t
        int severity 0
        int status 0
        string message
    timeStamp_t
        long secondsPastEpoch
        int nanoSeconds
        int userTag
    powerSupplyValue_t voltage
        double value
        alarm_t
            int severity 0
            int status 0
            string message
    powerSupplyValue_t power
        double value
        alarm_t
            int severity 0
            int status 0
            string message
    powerSupplyValue_t current
        double value
        alarm_t
            int severity 0
            int status 0
            string message

Standard Properties

The following field names have special meaning, i.e. support properties for general purpose clients.

value
This is normally defined since most general purpose clients access this field. All other fields in the structure support or describe the value field. The type can any supported type but is usually one of the following:
scalar
Any of the scalar types.
scalarArray
An array with the elementType being a scalar type
enumerated structure
A structure that includes fields named index and choices. index is an int that selects a choice. choices is an array of strings that defines the complete set of choices.
other
Other structure or array types can also be defined if clients and support code agree on the meaning. Some examples are: 1) A structure defining a 2D matrix, 2) A structure defining an image, 3) A structure that simulates a remote method, ...
timeStamp
The timeStamp. The type MUST be a timeStamp structure. Also if the PVData structure does not have a timeStamp then a search up the parent tree is made to find a timeStamp.
alarm
The alarm. The type MUST be an alarm structure.
display
A display structure as described below. It provides display characteristics for the value field.
control
A control structure as described below. It provides control characteristics for the value field.
history
Provides a history buffer for the value field. Note that currently PVData does not define history suppoprt.
other
Other standard properties can be defined.

In addition a structure can have additional fields that support the value field but are not recognized by most general purpose client tools. Typical examples are:

input
A field with support that changes the value field. This can be anything. It can be a channel access link. It can obtain a value from hardware. Etc.
valueAlarm
A field with support that looks for alarm conditions based on the value.
output
A field with support that reads the current value and sends it somewhere else. This can be anything. It can be a channel access link. It can write a value to hardware. Etc.

The model allows for device records. A device record has structure fields that that support the PVData data model. For example a powerSupport record can have fields power, voltage, current that each support the PVData data model.

PVProperty Interfaces and Classes

PVProperty

Interface and factory for finding a field within a structure.

interface PVProperty {
    PVField findProperty(PVField pvField,String fieldName);
    PVField findPropertyViaParent(PVField pvField,String propertyName);
    String[] getPropertyNames(PVField pvField);
}
where
findProperty
Find a field that is a subfield or property of this PVField. The fieldName is of the form name.name... The pvField must be named value or it does not have properties.
findPropertyViaParent
Find a property by searching up the parent tree. The property name is expected to match the name of a field. The return value is the interface to the first field found that is not a null structure or null if not found.
getPropertyNames
Get a String array that holds the names of the properties for this field.

PVPropertyFactory

public class PVPropertyFactory {
     public static PVProperty getPVProperty();
}

Standard Properties

This section has structure definitions that support standard properties. These definitions are defined in project javaIOC.

timeStamp

A timeStamp is represented by the following structure

structure timeStamp
    long secondsPartEpoch
    int nanoSeconds
    int userTag

The Epoch is the POSIX epoch, i.e. Jan 1, 1970 00:00:00 UTC. Both the seconds and nanoSeconds are signed integers and thus can be negative. Since the seconds is kept as a 64 bit integer, it allows for a time much greater than the present age of the universe. Since the nanoSeconds portion is kept as a 32 bit integer it is subject to overflow if a value that corresponds to a value that is greater than a little more than 2 seconds of less that about -2 seconds. The support code always adjust seconds so that the nanoSecconds part is normalized, i. e. it has is 0<=nanoSeconds<nanoSecPerSec..

TimeStamp

The Java definition of a timeStamp is:

interface TimeStamp {
    static final long milliSecPerSec = 1000;
    static final long microSecPerSec = milliSecPerSec*milliSecPerSec;
    static final long nanoSecPerSec = milliSecPerSec*microSecPerSec;
    static final long  posixEpochAtEpicsEpoch = 631152000;
    void normalize();
    long getSecondsPastEpoch();
    long getEpicsSecondsPastEpoch();
    int getNanoSeconds();
    int getUserTag();
    void setUserTag(int userTag);
    void put(long secondsPastEpoch,int nanoSeconds);
    long getMilliSeconds();
    void put(long milliSeconds);
    void getCurrentTime();
    boolean equals(TimeStamp other);
    boolean lt(TimeStamp other);
    boolean le(TimeStamp other);
    void add(long seconds);
    void add(double seconds);
    double diff(TimeStamp a,TimeStamp b);
}

where:

normalize
Adjust secondsPastEpoch and nanoSeconds so that 0<=nanoSeconds< nanoSecPerSec.
getSecondsPastEpoch
Get the seconds part of timeStamp
getEpicsSecondsPastEpoch
Get seconds relative to the EPICS epoch. The epics epoch starts on Jan 1 1990 00:00:00 UTC.
getNanoSeconds
Get the nanoSeconds part of timeStamp.
getUserTag
Get the userTag
setUserTag
Set the userTag
put(long secondsPastEpoch,int nanoSeconds)
Put a value into the timeStamp.
getMilliSeconds
Get bthe number of milliseconds since the epoch.
put(long milliSeconds);
Put a value into the timeStamp given the number of milliSeconds since the epoch.
getCurrentTime
Get the curent time.
equals
Is this time equal other?
lt
Is this time less than other.
le
Is this time less that or equal to other.
add(long seconds)
Add the specified number of seconds.
add(double seconds)
Add the specified number of seconds.
diff
Compute a-b. The result is in seconds.

The TimeStamp class provides arithmetic and comparison methods for time stamps. The result is always kept in normalized form, which means that the nano second portion is 0≤=nano<nanoSecPerSec. Note that it is OK to have timeStamps for times previous to the epoch.

TimeStampFactory
class TimeStampFactory implements TimeStamp {
    public static TimeStamp create();
}
PVTimeStamp
interface PVTimeStamp {
    boolean attach(PVField pvField);
    void detach();
    boolean isAttached();
    void get(TimeStamp timeStamp);
    boolean set(TimeStamp timeStamp);
}
where
attach
Attempts to attach to pvField It returns (false,true) if a timeStamp structure is found. It looks first at pvField itself and if is not an appropriate pvData structure but the field name is value it looks up the parent structure tree.
detach
Detach from the pvData structure.
isAttached
Is there an attachment to a timeStamp structure?
get
Copies data from the pvData structure to a TimeStamp. An exception is thrown if not attached to a pvData structure.
set
Copies data from TimeStamp to the pvData structure. An exception is thrown if not attached to a pvData structure.
PVTimeStampFactory
class PVTimeStampFactory implements PVTimeStamp {
    public static PVTimeStamp create();
}

alarm

An alarm structure is defined as follows:

structure alarm
    int severity
    int status
    string message

Note that severity and status are NOT defined as enumerated structures. The reason is performance, i. e. prevent passing the array of choice strings everywhere. The AlarmStatus and AlarmSeverity provide the equivalent of choices for an enumerated structure.

AlarmSeverity

Alarm Severity defines the possible alarm severities

enum AlarmSeverity {
 NONE,MINOR,MAJOR,INVALID,UNDEFINED;

    public static AlarmSeverity getSeverity(int value);
    private static final String[] alarmSeverityNames;
    public static String[] getSeverityNames() { return alarmSeverityNames;}
}
where
getSeverity
Get the alarm severity corresponding to the integer value.
getSeverityNames
Get the array of severity choices.
AlarmStatus

Alarm Status defines the possible alarm status conditions

enum AlarmStatus {
    NONE,DEVICE,DRIVER,RECORD,DB,CONF,UNDEFINED,CLIENT;

    public static AlarmStatus getStatus(int value);
    private static final String[] alarmStatusNames;
    public static String[] getStatusNames() { return alarmStatusNames;}
}
where
getStatus
Get the alarm status corresponding to the integer value.
getStatusNames
Get the array of status choices.
Alarm
class Alarm {
    public Alarm();
    public String getMessage();
    public void setMessage(String message);
    public AlarmSeverity getSeverity();
    public void setSeverity(AlarmSeverity alarmSeverity);
    public AlarmStatus getStatus();
    public void setStatus(AlarmStatus alarmStatus);
}
where
Alarm
The constructor. It sets the severity to no alarm and the message to "".
getMessage
Get the message.
setMessage
Set the message.
getSeverity
Get the severity.
setSeverity
Set the severity.
getStatus
Get the status.
setStatus
Set the status.
PVAlarm
interface PVAlarm {
    boolean attach(PVField pvField);
    void detach();
    boolean isAttached();
    void get(Alarm alarm);
    boolean set(Alarm alarm);
}

where

PVAlarm
The default constructor. Attach must be called before get or set can be called.
attach
Attempts to attach to pvField It returns (false,true) if it found an appropriate pvData structure. It looks first a pvField itself and if is not an appropriate pvData structure but the field name is value it looks to see if the parent structure has an appropriate sub structure.
detach
Just detaches from the pvData structure.
isAttached
Is there an attachment to an alarm structure?
get
Copies data from the pvData structure to an Alarm. An exception is thrown if not attached to a pvData structure.
set
Copies data from Alarm to the pvData structure. An exception is thrown if not attached to a pvData structure.
PVAlarmFactory
class PVAlarmFactory implements PVAlarm{
    public static PVAlarm create();
}

control

Control information is represented by the following structure

structure control
    double limitLow
    double limitHigh
    double minStep
Control
The java definition for Control is:
class Control {
    Control();
    double getLow();
    double getHigh();
    void setLow(double value);
    void setHigh(double value);
}

where

Control
The default constructure.
getLow
Get the low limit.
getHigh
Get the high limit.
setLow
Set the low limit.
setHigh
Set the high limit.
PVControl
interface PVControl {
    boolean attach(PVField pvField);
    void detach();
    boolean isAttached();
    void get(Control control);
    boolean set(Control control);
}

where

attach
Attempts to attach to pvField It returns (false,true) if it found an appropriate pvData structure. It looks first a pvField itself and if is not an appropriate pvData structure but the field name is value it looks to see if the parent structure has an appropriate sub structure.
detach
Just detaches from the pvData structure.
isAttached
Is there an attachment to a control structure?
get
Copies data from the pvData structure to a Control. An exception is thrown if not attached to a pvData structure.
set
Copies data from Control to the pvData structure. An exception is thrown if not attached to a pvData structure.
create
Create a PVControl instance. Attach must be called before get or set can be called.
PVControlFactory
class PVControlFactory{
    public static PVControl create();
}

Display

Display information is represented by the following structure

structure display
    double limitLow
    double limitHigh
    string description
    string format
    string units
Display
class Display {
    Display();
    double getLow();
    double getHigh();
    void setLow(double value);
    void setHigh(double value);
    String getDescription();
    void setDescription(String value);
    String getFormat();
    void setFormat(String value);
    String getUnits();
    void setUnits(String value);
}

where

Control
The default constructure.
getLow
Get the low limit.
getHigh
Get the high limit.
setLow
Set the low limit.
setHigh
Set the high limit.
getDescription
Get the description.
setDescription
Set the description.
getFormat
Get the format.
setFormat
Set the format.
getUnits
Get the units.
setUnits
Set the units.
PVDisplay
interface PVDisplay {
    boolean attach(PVField pvField);
    void detach();
    boolean isAttached();
    void get(Display display);
    boolean set(Display display);
}

where

attach
Attempts to attach to pvField It returns (false,true) if it found an appropriate pvData structure. It looks first a pvField itself and if is not an appropriate pvData structure but the field name is value it looks to see if the parent structure has an appropriate sub structure.
detach
Just detaches from the pvData structure.
isAttached
Is there an attachment to a display structure?
get
Copies data from the pvData structure to a Display. An exception is thrown if not attached to a pvData structure.
set
Copies data from Display to the pvData structure. An exception is thrown if not attached to a pvData structure.
create
Create a PVDisplay instance. Attach must be called before get or set can be called.
PVDisplayFactory
class PVDisplayFactory implements PVDisplay{
    public static PVDisplay create()
}

enumerated structure

An enumerated structure is a structure that has fields:

structure
    int index
    string[] choices
PVEnumerated
interface PVEnumerated {
    boolean attach(PVField pvField);
    void detach();
    boolean isAttached();
    boolean setIndex(int index);
    int getIndex();
    String getChoice();
    boolean choicesMutable();
    String[] getChoices();
    boolean setChoices(String[] choices);
}

where

PVEnumerated
The default constructor. Attach must be called before any get or set method can be called.
attach
Attempts to attach to pvField It returns (false,true) if pvField (is not, is) an enumerated structure.
detach
Just detaches from the pvData structure.
isAttached
Is there an attachment to an enemerated structure?
setIndex
Set the index field in the pvData structure. An exception is thrown if not attached to a pvData structure.
getIndex
Get the index field in the pvData structure.
getChoice
Get the String value corresponding to the current index field in the pvData structure. An exception is thrown if not attached to a pvData structure.
choicesMutable
Can the choices be changed? Note that this is often true. An exception is thrown if not attached to a pvData structure.
getChoices
Get the array of choices. An exception is thrown if not attached to a pvData structure.
getNumberChoices
Get the number of choices. An exception is thrown if not attached to a pvData structure.
setChoices
Change the choices. An exception is thrown if not attached to a pvData structure.
PVEnumeratedFactory
class PVEnumeratedFactory{
    PVEnumerated create();
}

multiChoice

NOTE: This is not currently used by anything. Bob sees it as an important facility in the future.

MultiChoice is support for a multiChoice structure, which is a structure containing two fields:

choices
An array of strings
bitMask
A bitMask that selects a subset of the choices.

MultiChoice

    public interface MultiChoice {
        interface Choices {
            String[] getChoices();
            int getNumberChoices();
        }
        byte[] getBitMask();
        String[] getChoices();
        Choices getSelectedChoices();
        void setBit(int index);
        void clear();
        int registerChoice(String choice);
    }

where

getBitMask
Returns the bitMask.
getChoices
Returns the complete set of choices..
getSelectedChoices
Returns the interface for getting the selected choices..
setBit
Select the choice for specified bit..
clear
Clear the bitMask, i.e. no choices are selected..
registerChoice
Register a new choice. If thed choice already exists then it''s index is returned. If not it is appended to the choices.

MultiChoiceFactory

    public class MultiChoiceFactory{
         public static MultiChoice getMultiChoice(PVField pvField);
    }

Package org.epics.pvdata.misc

Overview

This package provides utility code:

BitSet
An implementation of BitSet that can be serialized.
MessageQueue
Support for queuing messages for requesters.
Thread
ThreadCreate and Executor
TimeFunction
Time how long a function call requires.
LinkedList
A douuble linked list facility that requires the user to allocate a node. It is more efficient that ArrayList and does not require the implementation to allocate storage for the nodes.
Timer
An implementation of Timer that does not require an object to be created for each timer request.
Queue
A queue implementation.
Destroyable
A base interface for destroy.
Serialize
A helper for serialization.

bitSet

BitSet

This is adapted from the java.util.BitSet. It adds serializable. See java.util.BitSet for a description. This implementation adds the following additional methods:

    public boolean getAndSet(int bitIndex);
    public void set(BitSet src);
    public void or_and(BitSet set1, BitSet set2);

where

getAndSet
gets and sets the bit at bitIndex.
set
fast copy operation from src to this bitSet
or_and
The result is the or of the current bitSet with the value of set1.and set2. The number of bits is the Math.max(set1.bitsInUse,set2.bitsInUse);

This is an implementation of BitSet that supports serialization, which the standard Jave implementation does not allow.

BitSetUtil

interface BitSetUtil {
    boolean compress(BitSet bitSet,PVStructure pvStructure);
}

This provides functions that operate of a BitSet for a PVStructure. It currently has only one method:

compress
Compress the bits in a BitSet related to a structure.
For each structure:
  1. If the bit for the structure is set then the bit for all subfields of the structure are cleared.
  2. If the bit for the structure is not set but all immediate subfields have their bit set then the bit for the structure is set and the bits for all subfields are cleared.
Note that this is a recursive algorithm. That is if every immediate subfield has it's offset bit set then the bits for ALL fields that reside in the structure will be cleared.
Channel Access can call this before sending data. It can then pass entire structures if the structure offset bit is set.

BitSetUtilFactory

class BitSetUtilFactory {
    public static BitSetUtil getCompressBitSet();
}

message Queue

MessageNode

public class MessageNode {
    public String message;
    public MessageType messageType;
}

MessageQueue

public interface MessageQueue {
    MessageNode get();
    boolean put(String message,MessageType messageType,boolean replaceLast);
    boolean isEmpty();
    boolean isFull();
    int getClearOverrun();
}

This is for use by code that wants to handle messages without blocking higher priority threads.

A messageNode is a class with two public data members:

message
The message.
messageType
The message type.

A messageQueue is an interface with methods:

put
Put a new message into the queue. False is returned if the queue was full and true otherwise.
isEmpty
Is the queue empty?
isFull
Is the queue full?
getClearOverrun
Get the number of times replaceFirst or replaceLast have been called since the last call to getClearOverrun. The internal counter is reset to 0.

MessageQueueFactory

public class MessageQueueFactory {
    public static MessageQueue create(int size);
}
where
create
Create a MessageQueue and return the interface.

thread

ThreadPriority

public enum ThreadPriority {
    lowest,
    lower,
    low,
    middle,
    high,
    higher,
    highest;
    
    public static final int[] javaPriority;
    public int getJavaPriority();
    public static int getJavaPriority(ThreadPriority threadPriority);
}

ThreadReady

interface ThreadReady {
    void ready();
}

RunnableReady

interface RunnableReady {
    void run(ThreadReady threadReady);
}

ThreadCreate

interface ThreadCreate {
    Thread create(String name, int priority, RunnableReady runnableReady);
    Thread[] getThreads();
}

ThreadCreateFactory

public class ThreadCreateFactory {
    public static ThreadCreate getThreadCreate();
}

ThreadCreate provides two features:

  1. Create does not return until ReadyRunnable.run calls ThreadReady.ready().
  2. A list of all active threads is kept. getThreads provides access to the list.

executor

An Executor is a thread that can execute any object that implements the Java Runnable interface. The user can request that a single command be executed. If the command is already in the list of commands to be executed it is NOT added to the list when add is called.

ExecutorNode
public interface ExecutorNode {}
Executor
public interface Executor {
    ExecutorNode createNode(Runnable command);
    void execute(ExecutorNode executorNode);
    void stop();
}
ExecutorFactory
public class ExecutorFactory {
    static public Executor create(String name,ScanPriority priority);
}
where
createNode
Create a ExecutorNode that can be passed to execute.
execute
Request that command be executed. If it is already on the run list nothing is done.
stop
Stop the thread and refuse additional execute requests.

time a function call

TimeFunction is a facility that measures the average number of seconds a function call requires. When timeCall is called, it calls function in a loop. It starts with a loop of one iteration. If the total elapsed time is less then .1 seconds it increases the number of iterrations by a factor of 10. It keeps repeating until the elapsed time is greater than .1 seconds. It returns the average number of seconds per call.

TimeFunctionRequester

public interface TimeFunctionRequester {
    void function();
}

TimeFunction

public interface TimeFunction {
    double timeCall();
}

TimeFunctionFactory

public class TimeFunctionFactory {
    public static TimeFunction create(TimeFunctionRequester requester);
}

linked list

LinkedList implements a double linked list that requires a user to allocate the nodes. It is more efficent that ArrayList for implementing stacks and queues. For lists that are traversed while new elements can be added or removed, LinkedListArray provides a way to get an array of the currrent elements without allocating a new array each time the array is traversed.

LinkedListArray converts a LinkedList to an LinkNode array. The implementation provided by LinkedListFactory only creates a new LinkNode array w.en the number of elements in the linkedList passed to setNodes is greater than the length of the current LinkNode array.

LinkedListNode

public interface LinkedListNode<T> {
    public T getObject();
    boolean isOnList();
} 

LinkedList

public interface LinkedList {
    void addTail(LinkedListNode<T> listNode);
    void addHead(LinkedListNode<T> listNode);
    void insertAfter(LinkedListNode<T> listNode,LinkedListNode<T> addNode);
    void insertBefore(LinkedListNode<T> listNode,LinkedListNode<T> addNode);
    LinkedListNode<T> removeTail();
    LinkedListNode<T> removeHead();
    void remove(LinkedListNode<T> listNode);
    void remove(T object);
    LinkedListNode<T> getHead();
    LinkedListNode<T> getTail();
    LinkedListNode<T> getNext(LinkedListNode<T> listNode);
    LinkedListNode<T> getPrev(LinkedListNode<T> listNode);
    boolean isEmpty();
    boolean contains(T object);
}

LinkedListArray

public interface LinkedListArray<T> {
    void setNodes(LinkedList<T> linkedList);
    LinkedListNode<T>[] getNodes();
    int getLength();
    void clear();
}

LinkedListCreate

public class LinkedListCreate<T> {
    public static LinkedList<T> create();
    public static LinkedListNode<T> createNode(Object object);
    public static LinkedListArray<T> createArray();
}

LinkedListCreate is created as follows:

LinkedListCreate<SomeObject> linkedListCreate = new LinkedListCreate<SomeObject>();

Then a linked list can be created as follows:

LinkedList<SomeObject> linkedList = linkedListCreate.create();

The only way a node can be allocated is by calling linkedListCreate.createNode(SomeObject object). The object passed to createNode is what is returned by LinkedList.getObject. For example:

private static class SomeObject {
    private LinkedListNode<SomeObject> listNode = null;
    // other definitions


    private Node(/* arguments*/) {
        listNode = linkedListCreate.createNode(this);
    }

    LinkedListNode<SomeObject> getListNode() {return listNode};
}

// then

SomeObject someObject = new SomeObject(/* args */);
linkedList.addTail(someObject);

A node can only be on one list at a time but can be put, at different times, on different lists as long as they all hold the same type of objects.

The class does not provide a lock but the user can synchronized via calls like:

synchronized(linkedList) {
    linkedList.addTail(listNode);
}

The following is an example of how to use LinkedListArray.

    LinkedListNode<SomeObject>[] nodes = null;
    int length = 0;
    synchronized(linkedList) {
        linkedListArray.setNodes(linkedList);
        nodes = linkedListArray.getNodes();
        length = linkedListArray.getLength();
    }
    for(int i=0; i<length; i++) {
        SomeObject object = nodes[i].getObject();
        // do something with object
    }

timer

This provides a general purpose timer. It provides the following features not provided by java.util.Timer and java.util.TimerTask:

  1. Priority
    The java.util implementation does not allow the user to specify the priority of the timer thread. This implementation does.
  2. TimerNode
    A java.util.TimerTask is not reusable. Once a timerTask has been canceled or a delay timerTask has run, the TimerTask can not be reused. Instead a new TimerTask must be created. A TimerNode can be reused.

Timer

interface Timer {
    interface TimerCallback {
        void callback();
        void timerStopped();
    }
    interface TimerNode {
        void cancel();
        boolean isScheduled();
    }
    void scheduleAfterDelay(TimerNode timerNode,double delay);
    void schedulePeriodic(TimerNode timerNode,double delay,double period);
    void stop();
}

This is the interface for scheduling a timer callback. A timer is created by calling TimerFactory.create. It has the methods:

scheduleAfterDelay
A request to schedule a callback after a delay specified in seconds. If stop has been called then TimerCallback.timerStopped is called immediately.
schedulePeriodic
Schedule a periodic callback. If stop has been called then TimerCallback.timerStopped is called immediately.
stop
Stop the timer. The queue is emptied and TimerCallback.timerStopped is called for each element of the queue. Further schedule calls result in a call to TimerCallback.timerStopped. Once stopped a timer is no longer useful. A new timer must be created.

TimerFactory

class TimerFactory {
    static public Timer create(String threadName, ThreadPriority priority);
    static public TimerNode createNode(TimerCallback timerCallback);
}

This is the factory that implements the Timer and TimerNode interfaces. It has the methods:

create
Create a new Timer.
createNode
Create a TimerNode. A timerNode can be used to schedule any timer but a timeNode can only be on a single timer queue and only once on a given timer queue.

TimerCallback

This is an interface that must be implemented by the user. It has the following methods:

callback
This is called when a timer expires. This is called with no locks held. When called a delay timer is no longer on the queue but a periodioc timer is on a queue. Thus the callback for a delay timer can issue a new schedule request but a periodic timer must not. Note the explaination of TimerNode.cancel below.
timerStopped
Timer.stop was called when a timer request was queued. or if the timer is stopped and a schedule request is made.

TimerNode

This is an interface implemented by TimerFactory. It is allocated by calling TimerFactory.createNode. It is passed as an argument when scheduling a callback. It has the single method:

cancel
This is called to cancel a timer request. If a callback has been dequeued but the callback not called when cancel is called then a callback may still happen. New schedule requests can be made after a cancel request has been made.
isScheduled
Is this node in the timerQueue.

queue

This provides a queue which has an immutable capacity, which is specified when the queue is created. When the queue is full the user code is expected to keep using the current el;ement until a new free element becomes avalable. This is used by pvData.monitor.

QueueCreate

public class QueueCreate<T> {
    public Queue<T> create(QueueElement<T>[] queueElements) {
        return new QueueImpl<T>(queueElements);
    }

    public QueueElement<T> createQueueElement(T object) {
        return new QueueElementImpl<T>(object);
    }
}

QueueElement

public interface QueueElement<T> {
    public T getObject();
}

Queue

public interface Queue<T> {
    void clear();
    int getNumberFree();
    int capacity();
    QueueElement<T> getFree();
    void setUsed(QueueElement<T> queueElement);
    QueueElement<T> getUsed();
    void releaseUsed(QueueElement<T> queueElement);
}

The queue methods are:

clear
Make the queue empty.
getNumberFree
Get the number of fee elements in the queue.
capacity
Get the capacity, i.e. the maximun number of elements the queue can hold.
getFree
Get the next free element. Null is returned if no free elements are available. If a non null value is returned then the element belongs to the caller until setUsed is called.
setUsed
Set a queue element used. This must be the element returned by the last call to getFree.
getUsed
Get the next used element of null if no more used elements are available.
releaseUsed
Set a queue element free. This must be the element returned by the last call to getUsed.

A queueCreate instance is created via a call like the following:

 QueueCreate<MyObject> queueCreate = new QueueCreate<MyObject>();

Once a queueCreate is available a queue instance is created via code like the following:

Queue<MyObject> queue create(MyObject[] myObjects) {
    QueueElement<MyObject>[] queueElements = new QueueElement[length];
    for(int i=0; i<length; i++) {
        QueueElement<MonitorElement> queueElement =
                 queueCreate.createQueueElement(myObjects[i);
        queueElements[i] = queueElement;
    }
    return queueCreate.create(queueElements);
}

A producer calls getFree and setUsed via code like the following:

   MyObject getFree() {
       QueueElement<MyObject> queueElement = queue.getFree();
       if(queueElement==null) return null;
       return queueElement.getObject();
  }

A consumer calls getUsed and releaseUsed via code like the following:

     while(true) {
         QueueElement<MyObject> queueElement = queue.getUsed();
         if(queueElement==null) break;
         MyObject myObject = queueElement.getObject();
         // do something with myObject
         queue.releaseUsed(queueElement);
     }

Destroyable

This is a base interface used by many other interfaces.

interface Destroyable  {
    void destroy();
}

where

destroy
Destroy the object.

SerializeHelper

This is a helper class for serialization, which is required for sending and receiving pvData over the nerwork.

class SerializeHelper {
    static void writeSize(final int s, ByteBuffer buffer);
    static int readSize(ByteBuffer buffer);
    static void serializeString(final String value, ByteBuffer buffer);
    static void serializeSubstring(final String value,
         int offset, int length, ByteBuffer buffer);
    static String deserializeString(ByteBuffer buffer);
}

where

writeSize
Serialize the size.
readSize
Deserialize the size.
serializeString
Serialize a String.
serializeSubstring
Serialize a substring.
deserializeString
Deserialize a string.

Package org.epics.pvdata.monitor

Overview

Project javaIOC provides the ability to monitor changes to an arbitrary subset of the fields in a record. The next section describes how a client specifies monitor options. The rest of this package description is of interest to developers. Although this package does not implement monitors it does describe what the client and what pvAccess needs to know about monitors.

A client can monitor an arbitrary subset of the fields in a record instance. Each field has an associated monitor algorithm which decides if changes to that field should cause a monitor. The algorithms defined by this package are: onPut, onChange, and deadband. The set of algorithms is extensible.

The basic interface for monitoring is interface Monitor, which has four methods: start, stop, poll, and release. Code that implements the client side for monitors has code like the following:

    //somewhere the following request is issued
    monitor.start();
    //somewhere the following is done:
    while(true) {
       MonitorElement monitorElement = monitor.poll();
       if(monitorElement==null) {
          // no elements in the queue. Do something.
       } else {
          // got a monitor. Handle the element and then
          monitor.release(monitorElement);
       }
    }

This package provides the following support for monitors:

  1. How a client specifies monitor options
  2. Implementing new monitoring algorithms.
  3. Monitor Queues
    This package provides a complete implementation of montor queues for pvData.

Developers who need to understand or implement monitor algorithms will be interested in this package. For example it is used by pvAccess to implement monitors. The interfaces can be implemented by other servers, for example the javaIOC (org.epics.ioc.caV3) implements a version of interface Monitor that links to a version 3 EPICS IOC.

This package defines the following monitor algorithms:

onPut
A monitor is issued whenever a put is issued to the field. This is the default unless the record defines deadbands for a field. An exception is the top level timeStamp which by default is made onChange and monitor will not be raised.
onChange
This provides two options: 1) A monitor is raised whenever a field changes value, and 2) A monitor will never be raised for the field.
deadband
The field must be a numeric scalar. Whenever the absolute or percentage value of the field changes by more than a deadband a monitor is issued. The record instance can also define deadbands.
periodic
A monitor is issued at a periodic rate if a put was issued to any field being monitored.

The monitor queue implementation provides support for the following queue sizes greater than or equal to two.

Standard Monitor Requests

This section describes that monitor support provided by project javaIOC. Two issues are discussed: record options and field options.

Record Options

The options that apply to an entire record are:

periodic
A record can ask to be monitored periodically by specifying a periodic rate. A monitor will be issued no faster that the rate specified. A periodic monitor does not use a monitor queue.
queueSize
Queue size can be specified to be >=1. A size of 1 means no queue but just keep a single copy of the data. A size of 2 is the default.

Field Options

The following options are supported for all fields:

shareData
Has a value of true or false and specifies if the server just transfer data from the record keep a copy. This option can save memory for array fields. Note that it is implemented by PVCopy.

For each field the following monitor algorithms are supported:

onPut
A monitor is issued when a put is issued to the field. This is the default if no algorithm is specified and the field is not the top level timeStamp.
onChange
This has two features depending on the value of causeMonitor. If causeMomitor is true (the default) then a monitor is raised only if the value has changed since the last monitor. If causeMonitor is false then this field will never cause a monitor. An example is a top level timeStamp field. If a client monitors the top level timeStamp then unless the client requests causeMonitor to be false, if the only change is to the timeStamp field no monitior will be issued.
deadband
This can only be specified for a numeric scalar field. Details follow:

Monitor Request Options

The examples will use the syntax supported by calling:

   PVStructure pvRequest = org.epics.ca.client.CreateRequestFactory.createRequest(request);

The request string has the following:

   "record[option=value,...]field(fieldDef,...)"

The standard record options are:

queueSize
The value must be >=1.
periodicRate
The value is the maximum rate in seconds for monitors.

Each fieldDef is either of the form:

    fullRecordName

Where fullRecordName is the full name of the field in the record. The name in the structure the client will get is the field name from the record. Or fieldDef has the form:

    fieldName{fieldDef,...}
    

Each fieldDef is of the form:

    fullFieldName[option=value,...]

where fullFieldName is of the full field name of the record field and the options define the monitor options.

Monitor options are identified via the following option.

    algorithm=name
    

where name is the algorithm name. For the algorithms implemented by pvData this is one of: onPut, onChange, or deadband.

onPut is the default so it does not have to be specified.

onChange accepts one additional option:

    causeMonitor=value

where value must be "true" or "false". The default is true.

deadband accepts the following additional options:

    deadband=deadbandValue
    type=typeValue
    isPercent=isPercentValue

where

deadbandValue
The change in value (or percentage change) that causes a monitor. If not specified the deadband is taken from the record if the record defines it. If specified and the record also defines it the minimum value is taken.
typeValue
Must be "display" or "archive". This says if the record deadband is taken from display or from archive. The default is display.
isPercentValue
Must be true or false. The default is false. If true the deadband is a percentage change otherwise it is an absolute change.

Record Deadband

NOTE: This applys to records in a javaIOC.

Any numeric scalar field in a record instance can optionally have an associated deadband structure, which is defined as follows:

<structure structureName = "deadband">
    <structure name = "display">
         <scalar name = "isPercent" scalarType = "boolean"/>
         <!-- if true than percentage change. If false than absolute change -->
         <scalar name = "value" scalarType = "double"/>
         <!-- the deadband for display -->
    </structure>
    <structure name = "archive">
         <scalar name = "isPercent" scalarType = "boolean"/>
         <!-- if true than percentage change. If false than absolute change -->
         <scalar name = "value" scalarType = "double"/>
         <!-- the deadband for archive -->
    </structure>
</structure>

As an example:

<record name = "example">
    <scalar name = "value" scalarType = "double">
    <structure name = "deadband" extends = "deadband">
       <structure name = "display">
          <deadband>.1</deadband>
       </structure>
       <structure name = "archive">
          <deadband>.3</deadband>
       </structure
    </structure>
    <!-- other stuff -->
</record>

NOTE: If an algorithm is not defined by the user for a field and a deadband is defined for the record than the algorithm is made to be deadband and the display deadband is used as the deadband.

Examples

The following:

    String request = "alarm,timeStamp,power.value";
    PVStructure pvRequest = org.epics.ca.client.CreateRequestFactory.createRequest(request);

Creates a pvRequest that monitors the alarm, timeStamp, and power.value fields of a record. The client will receive a structure with the fields named alarm,timeStamp, and value. Since the client has not specified any options the defaults will be used. This means:

The following:

    String request = "timeStamp[algorithm=onChange,causeMonitor=true]";
    PVStructure pvRequest = org.epics.ca.client.CreateRequestFactory.createRequest(request);

Will cause monitior whenever the timeStamp is changed. This is a way to be notified whenever a javaIOC record is processed because this is normally the only time the timeStamp is changed.

The following:

    String request =
        "alarm,timeStamp,value{power.value[algortithm=deadband,isPercent=true,deadband=1.0}";
    PVStructure pvRequest = org.epics.ca.client.CreateRequestFactory.createRequest(request);

This requests a monitor whenever and alarm is raised or when the power.value changes by at least 1 percent.

Monitor Interfaces

Monitor

This is the interface implemented by a factory that implements a monitoring algorithm

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

where

destroy
destroy the monitor, i.e. release whatever resources are used by the implementation.
start
Start monitoring. An initial monitor with all data modified must be generated.
stop
Stop monitoring.
poll
Called to get modified data. If no data has been modified since the last poll null is returned.
release
release the element returned by the most recent poll request.

MonitorElement

This is the interface returned by a call to poll.

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

where

getPVStructure
The data structure.
getChangedBitSet
The bitSet showing which fields of the PVStructure have changed since the previous poll request.
getOverrunBitSet
the bitSey which shows which fields have been modified more than once since the last poll request.

MonitorRequester

This is the interface implemented by the code that request a monitor.

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

where

monitorConnect
The monitor has connected to a PVRecord.
monitorEvent
A monitor event has occured. Monitor.poll is called to get the data.
unlisten
The server has been told to disconnect from the record. The MonitorRequster can no longer issue any requests except destroy until monitorConnect is again called.

MonitorAlgorithm

The following are implemented by code that implements a monitor algorithm.

interface MonitorAlgorithm  {
    String getAlgorithmName();
    boolean causeMonitor();
    void monitorIssued();
}

where

getAlgorithmName
return the name of the algorithm.
causeMonitor
Called to see if a change to this field should cause a monitor
monitorIssued
Called after a monitor has been issued.

MonitorQueue

This is the interface implemented by MonitorQueueFactory.

interface MonitorQueue  {
    void clear();
    int getNumberFree();
    int capacity();
    MonitorElement getFree();
    void setUsed(MonitorElement monitorElement);
    MonitorElement getUsed();
    void releaseUsed(MonitorElement monitorElement);
}

MonitorQueueFactory

class MonitorQueueFactory {
    static MonitorQueue create(MonitorElement[] monitorElements);
}

where

clear
Set all elements of the queue free.
getNumberFree
Get the number of free queue elements.
capacity
Get the number of queue elements.
getFree
Get a free queue element. If no free elements null is returned.
setUsed
Set the latest element returned by getFree to used.
getUsed
Get the oldest used element. Null is returned when there are no more used elements.
releaseUsed
release the element returned by the latest call to getUsed.