SLAC ESD Software Engineering
Group
|
||||||||||
|
|
|
This page describes how to use AIDA to program some simple data acquisitions from the B-factory accelerator databases and control systems in Java. The setup and examples are for the SLAC AFS Unix system, but can be generalized to Windows.
Contents: Setup for Development The AIDA API
See also: Aida
javadoc, in particular the classes DaObject
and
DaReference
(and DaReference's
parent _DaReference)
in aida.lib.da
which
form Aida's programming interface.
One can also use Matlab.
This web page describes tutorially how to program an application in Java that uses Aida to do data acquisition. First is described the required setup for development, then what is required in the environment of an application using Aida, and finally the Application Programming Interface (API) of Aida. More systematic documentation can be found in the Aida Javadoc.
Setup files to create the appropriate environment for Aida have been written, so, the short version of setup is simply to run those. The long version below describes what is in those setup files.
Create the basic development environment. This puts AIDA things in the CLASSPATH.
> source /afs/slac/g/cd/soft/dev/script/ENVS.cshSet up specific Aida environment variables, and say which Aida network (dev or prod) you want to join (like the distinction between MCCDEV and MCC. Basically, if you want real accelerator data, join the prod network).
> source $CD_SOFT/dev/script/aidaSetEnv.csh [{dev|prod}]Run a program with:
> java ${AIDABCSTRING} -DAIDA_DATABASE_USERID=AIDA${AIDA_MODE} -DAIDA_NAMESERVER_IOR_URL=${AIDA_NAMESERVER_IOR_URL} yourprogramSee the alias 'aidatest', which is defined by ENVS.csh (see above). It does this java invocation line for you, in order to run Aida test suite programs in /afs/slac/g/cd/soft/ref/package/aida/test/java/. The *.java files named *Tests.java contain java examples of getting data with Aida; those named da*Test.java are wrappers for their respective tests. For instance, daApiTest.java wraps ApiTests.java, and in fact that test suite is a good place to start for examples.
This section describes the Aida runtime environment in detail:
The following jar files must be in the CLASSPATH:
JAR file | Use in AIDA |
/afs/slac/g/cd/soft/ref/package/aida/lib/aida.jar |
The AIDA client side, including AIDA's API |
/afs/slac/g/cd/soft/ref/package/except/lib/except.jar |
Exception (error object) definitions |
/afs/slac/g/cd/soft/ref/package/err/lib/err.jar |
Error Handling and Logging |
/afs/slac/package/iona/orbacus/prod/JOB/lib/OB.jar |
Orbacus implementation of CORBA, on which Aida is founded |
/afs/slac/package/iona/orbacus/prod/JOB/lib/OBUtil.jar |
CORBA utilities used by AIDA. |
/afs/slac/package/iona/orbacus/prod/JOB/lib/OBEvent.jar |
The mechanism for passing exception objects around. |
Marginally better performance can be achieved for ref/package/{aida,err,except} by using the .class files directly in the CLASSPATH, rather than the jars. those are available in the edu.stanford.slac. package subdirectories of those packages.
Aida must be run in Java 1.4 or above, though as of this writing (Mar-2010) it has not been tested in Java 6. So, for instance:
> setenv JAVAVER 1.5OB.jar must be in the bootclasspath of a JVM running an application program using Aida. That is, you must start a program using Aida with:
> java -Xbootclasspath/p:/afs/slac/package/iona/orbacus/prod/JOB/lib/OB.jar ...There are three networks of Aida servers, one "AIDADEV" (used for development of Aida itself), and one "AIDAPROD", for real accelerator data, and available for general physics at SLAC, and thirdly "AIDALCLS", which is a high availibility network serving the same data as AIDAPROD, but exclusively for LCLS operations and only available on LCLS CA production network. On SLAC "AFS" computers (tersk, linux desktops etc), an Aida client can connect to either AIDADEV or AIDAPROD network when it starts. It does this by talking first to the right Aida NameServer (the one for the AIDADEV network or the one for AIDAPROD), and secondly telling the server which names database it wants to use. These two items are specified at the runtime of an Aida client program, by setting two Java properties to values which specify dev or prod:
See /afs/slac/g/cd/soft/ref/package/aida/common/script/aidaSetEnv.csh for how the valid values of these two properties are derived, and how to use them in the "java" command that starts an Aida client program.
aidalist <instance-pattern> [<attribute-pattern>]Some example queries:
> aidalist XCOR:PR10:9042 - Confirms XCOR:PR10:9042 is known
> aidalist XCOR:PR10:9% - All "9 something" XCOR in PR10
> aidalist XCOR:PR10:9042 X% - All X attributes of XCOR:PR10:9042
> aidalist XCOR:PR10:9042 % - All attributes of XCOR:PR10:9042
> aidalist XCOR% % - All XCOR with all their attributes
> aidalist XCOR:LI%:502 twiss - Which linac 502 units have twiss
This section describes how to use the Aida API. Most API features are described by example, but clearly an example can't be given for all combinations. The examples described here are taken from the demo ApiTests.java, but many more examples can be found in the Aida test suite.
The following explanation of the AIDA API, is based on the examples in $CD_SOFT/ref/package/test/java/ApiTests.java. Each example is implemented as a method of that class. Each can be run individually using the wrapper daApiTest.java:
Eg, to setup and run test 2, which gets an array value from the SLC db, do this:
> source /afs/slac/g/cd/soft/dev/script/ENVS.csh
> source $CD_SOFT/dev/script/aidaSetEnv.csh prod
> cmlog -u &
> aidatest daApiTest 2
Constructing Err facility. Init ORB.
Sun Dec 12 21:06:58 PST 2004: Making connection to Name Service
Sun Dec 12 21:06:59 PST 2004: Making connection to daServer
IMMS of XCOR:LI03:120
-5.0
5.0
0.0
Important Notes: You only have to source the scripts once (obviously). Note also that, in this mode of testing, each execution of daApiTest goes through the whole Aida initialization, which includes things like connecting to the error service, connecting to Oracle etc. All these need only be done once. To get an idea of how fast Aida is after a program has been initialized, run 2 or more tests in the same execution (aidatest daApiTest 1 2 3), or run the performance test suite.
This section outlines the required code inside an Aida client which is necessary prior to using the Aida API to get data.
Import the classes you'll be using; these are like include statements in c code. Aida's API is in the last two of these. Additionally, the general purpose return object which Aida defines to help it return structured data, called DaValue, extends java.util.Vector, so you'll want that to help you manipulate Vectors. You'll also need the Err package, since Aida uses it to communicate errors.
import java.util.*;
// useful stuff: Vector, Enumeration etc
import edu.stanford.slac.err.*; // error handling
import edu.stanford.slac.aida.lib.da.*; // Basic API
import edu.stanford.slac.aida.lib.util.common.*; // DaValue
Error handling in Aida is done through the Err package, which uses cmlog to log messages. Err uses a static singleton programming pattern - basically, the first time you call its getInstance() method, you must supply a string being the label it will use when logging your messages in cmlog (in the "Sys" column of a cmlog browser). It will return an Err object to you, with which you can log messages.
public class daApiTest
{
static Err err_; // Error issuance singleton.
/**
*/
public static void main(String args[])
{
// Register with the Error Messaging Service
err_ = Err.getInstance("daApiTest");
...
Note that, in ApiTests.java, the messages written in the catch block are written with System.out. In a real application, one would use Err.log(), using the Err object returned from Err.getInstance().
Note also that the Aida API methods (DaObject get() etc) described below, all throw Java checked exceptions. That means, you have to put them in a try{} block - the compiler will complain if you don't. See ApiTests.Test01 for example.
To talk to Aida you need DaObject object. This connects to the Aida DaServer, and its methods allow you to get data. Its constructor throws checked exceptions, so you have to create it in a try block. See the example in ApiTests.java, in its case the constructor for DaObject is in the constructor for ApiTests:
private DaObject da;
try
{
da = new DaObject(args);
}
catch ( Exception e ) {...}
DaObject is described in detail in its javadoc entry. Here I shall work up some examples starting from the most basic and progressively adding features. The try blocks are omitted for clarity in the following examples.
Atomic types (like Double, Int, and including String) are acquired using DaObject.get.
For example see ApiTests.Test01:
Double v = (Double)da.get("TEST//VAL", DaValue.Type.DOUBLE);
Arrays of atomic types (like Double[], Int[], and String[]) are acquired using DaObject.geta.
Note that you both use the "get an array" geta method, and use an array variant of the type specified (so to get an array of Double you use DOUBLEA not DOUBLE). This is because the type argument of get and geta methods in AIDA, is formally the type that is required, not what type the data actually is in the native database. It tells Aida, and the Data Provider involved, to attempt to acquire the value, and if necessary make a conversion to the type given. However, bare in mind that a Data Provider that makes very general types of acquisition, like the SLC DB data provider, will take your argument as a clue about how to acquire the data, so it's a good idea to use something sensible. Check in the relevant Data Provider's user guide, under the Methods section of the Attribute you're trying to acquire, to see which methods are supported for that Attribute.
For example see ApiTests.Test02:
Double[] v = (Double[])da.geta("XCOR:LI03:120//IMMS", DaValue.Type.DOUBLEA);
for (int i=0; i < v.length; i++)
System.out.println( v[i] );
Aida allows you to supply arguments to an acquisition, using the setParam
method of DaObject
(or DaReference).
Functionally, each argument consists of argument name assigned to an
argument value, but this can be expressed two ways, either
a single string like "MODE=7", or two strings
like "MODE","7". Note that the arguments are always given as
strings, even when the argument value is numerical eg
da.setParam("MODE=7").
For example see ApiTests.Test03:
Float[] twiss;
String query = "BPMS:PR02:8032//twiss";
da.setParam("MODE=7");
twiss = (Float[])da.geta(query, DaValue.Type.FLOATA);
Aida can return structured data in a special Aida class object called DaValue which extends java.util.Vector. This uses DaObject's method getDaValue (also available in DaReference). Vector can hold heterogeneous elements, so the first can be a float, the second can be a String etc. getDaValue automatically packages up the data you asked for as a DaValue, and you can use the methods of Vector to extract your data. For instance, the Aida SLC History Data Provider can return history data as a DaValue, in which case its structure is a Vector of 3 Vectors; the values, the times, and a "repeat count" (always valued all 0s and not interesting but maintained for compatibility with data returned by the EPICS channel archiver).
The following example acquires history, using DaObject arguments to specify the time range, and then calling getDaValue. Then 3 ways of looking at the data returned are given as examples. The example below is a hybrid of ApiTests.Test04 and Test05 (Test05 in fact illustrates a more direct way of inspecting the contents of the returned Vectors using Enumeration).
String query = "XCOR:LI03:120//BACT.HIST";
da.setParam("STARTTIME", "07/30/2004 00:00:00");
da.setParam("ENDTIME", "07/31/2004 00:00:00");
DaValue v = da.getDaValue(query);
// returns a Vector of 3 Vectors. First just toString() it.
System.out.println( "Test unparameterized history \t=" + v.toString() );
// Extract the values sub-Vector "v[0]", and times sub-Vector "v[1]"
Vector valuesvec = (Vector)v.get(0);
Vector timesvec = (Vector)v.get(1);
System.out.println("history values vector "+ valuesvec.toString());
System.out.println("history times vector "+ timesvec.toString());
// Convert the subvectors to array of Doubles and array of Strings.
int N = valuesvec.size(); // Get values Vector's length
Double[] values = new Double[N]; // Allocate an array of Doubles.
values = (Double[])valuesvec.toArray(values); // Copy Vector into array.
String[] times = new String[N]; // Allocate an array of Strings.
times = (String[])timesvec.toArray(times); // Copy Vector into array.
for (int i = 0;i<N;i++)
{
System.out.println( "history values [" + i + "]=" + values[i] );
System.out.println( "history times [" + i + "]=" + times[i] );
}
da.reset(); // Reset the arguments on da
Note the use of da.reset(). This is used to clear the parameters assigned to a DaObject. So, for instance, if you want to acquire history of a number of devices for the same time period, set the parameters once, then make the acquisitions with the same DaObject before doing the DaObject.reset.
To Add
DaObject.getAny
DaReference
Compiling a DaReference
Creating a DaReference with a DaObject
taxonomy of DaReference get calls
Calling DaObject methods with a DaReference
taxonomy of DaObject get calls passing a DaReference
Author: Greg White, 19-Nov-2004
Modified by: