Main Page | Features | Central Services | csv-Files | Types | Transfer | Access | API-C | API-.NET | API-Java | Examples | Downloads
page generated on 18.05.2024 - 04:45
Accessing Your Server in Java

Basic Synchronous Calls

We'll begin by getting a set of data from our Workshop server and displaying the output.

Start Eclipse and create a new Project in the workspace. You can call it something like "WorkshopClientTest", if you'd like. Create a package in the Project and call it something like "de.desy.helgoland.client". Now add a class to this package called "WorkshopTest".

Create a main() method and inside main add some variables for three different tine links (to get property "Sine", property "Gaussian", and property "Amplitude"). Also add the array variables to hold the results. You'll need two tine data type objects as well, and a variable to hold the completion code. In the spirit of "A picture is worth a thousand words", have a look at the following example code:

package de.desy.helgoland.client;
import de.desy.tine.client.*;
import de.desy.tine.dataUtils.*;
import de.desy.tine.definitions.*;
public class WorkshopTest
{
public static void main (String[] args)
{
int cc;
TLink sinlnk, gausslnk, amplnk;
TDataType dout, din;
float[] sinvals = new float[1024];
float[] gaussvals = new float[1024];
float[] amplitude = new float[1];
dout = new TDataType(sinvals);
din = new TDataType();
sinlnk = new TLink("/WORKSHOP/Station1/Device0","Sine",dout,din,TAccess.CA_READ);
if (sinlnk != null)
{
System.out.println("First 100 Sine Values for Device0:");
if ((cc=sinlnk.execute()) == 0) // synchronous access ...
{
for (int i=0; i<100; i++)
{
System.out.print("" + sinvals[i]);
System.out.print(i < 99 ? ", " : System.getProperty("line.separator"));
}
System.out.println("at " + TDataTime.toString(sinlnk.getLastTimeStamp()));
}
else
{
System.out.println("error: " + TErrorList.getErrorString(cc));
}
sinlnk.cancel();
}
dout = new TDataType(gaussvals);
gausslnk = new TLink("/WORKSHOP/Station1/Device0","Gaussian",dout,din,TAccess.CA_READ);
if (gausslnk != null)
{
System.out.println("First 100 Gaussian Values for Device0 :");
if ((cc=gausslnk.execute()) == 0) // synchronous access ...
{
for (int i=0; i<100; i++)
{
System.out.print("" + gaussvals[i]);
System.out.print(i < 99 ? ", " : System.getProperty("line.separator"));
}
System.out.println("at " + TDataTime.toString(gausslnk.getLastTimeStamp()));
}
else
{
System.out.println("error: " + TErrorList.getErrorString(cc));
}
gausslnk.cancel();
}
dout = new TDataType(amplitude);
amplnk = new TLink("/WORKSHOP/Station1/Device0","Amplitude",dout,din,TAccess.CA_READ);
if (amplnk != null)
{
System.out.println("The amplitude is :");
if ((cc=amplnk.execute()) == 0) // synchronous access ...
{
System.out.println("" + amplitude[0]);
System.out.println("at " + TDataTime.toString(amplnk.getLastTimeStamp()));
}
else
{
System.out.println("error: " + TErrorList.getErrorString(cc));
}
amplnk.cancel();
}
System.exit(0);
}
}

If you add tine.jar to the external jars in the project (on a Windows machine, you'll find this jar file in L:\java, on a Linux machine, you'll find it in /usr/local/tine) it should run without any problems and give you a simple text dump at the system console.

Note
Even though the Amplitude is a single number (unless you are returning the amplitudes of all sine curves as a multi-channel array) we still have to declare it as an array of 1 value, so that Java will treat it as an object and we can pass the reference to the object.
Unlike the C or VB interface, the constructor of the TLink object specifies the link parameters but does NOT start a link. If you get a valid link handle then you can call either the execute() method or the attach() method to acquire data synchronously or asynchronously.

Adding Asynchronous Calls

Now let's see what it means to monitor one of our properties, say "Gaussian", by using the asynchronous attach() method instead of execute().

Add another class to the package call gaussCallback and make it implement TLinkCallback as follows:

package de.desy.helgoland.client;
import de.desy.tine.client.TLink;
import de.desy.tine.client.TLinkCallback;
import de.desy.tine.dataUtils.TDataTime;
public class gaussCallback implements TLinkCallback
{
public void callback(TLink link)
{
float[] vals = (float[])(link.getOutputDataObject().getDataObject());
System.out.println("1st 100 Gaussian Values :");
for (int i=0; i<100; i++)
{
System.out.print("" + vals[i]);
System.out.print(i < 99 ? ", " : System.getProperty("line.separator"));
}
System.out.println("at " + TDataTime.toString(link.getLastTimeStamp()));
}
}

Now add a field to your WorkshopTest class called gaussCb with is and instance of gaussCallback, and change the call to gausslnk.execute() to gausslnk.attach() and pass this callback reference, along with an access mode of CM_POLL and a polling interval of 1000 msec.

Finally, before you call System.exit(0), sleep for 10 seconds to let a few callback come in. This illustrates how to handle asynchronous data transfer as opposed to the synchronous transfer exhibited by execute().

When you're done, your WorkshopTest class should look something like:

package de.desy.helgoland.client;
import de.desy.tine.client.*;
import de.desy.tine.dataUtils.*;
import de.desy.tine.definitions.*;
public class WorkshopTest
{
private static gaussCallback gaussCb = new gaussCallback();
public static void main (String[] args)
{
int cc;
TLink sinlnk, gausslnk, amplnk;
TDataType dout, din;
float[] sinvals = new float[1024];
float[] gaussvals = new float[100];
float[] amplitude = new float[1];
dout = new TDataType(sinvals);
din = new TDataType();
sinlnk = new TLink("/WORKSHOP/Station1/Device0","Sine",dout,din,TAccess.CA_READ);
if (sinlnk != null)
{
System.out.println("First 100 Sine Values for Device 0:");
if ((cc=sinlnk.execute()) == 0) // synchronous access ...
{
for (int i=0; i<100; i++)
{
System.out.print("" + sinvals[i]);
System.out.print(i < 99 ? ", " : System.getProperty("line.separator"));
}
System.out.println("at " + TDataTime.toString(sinlnk.getLastTimeStamp()));
}
else
{
System.out.println("error: " + TErrorList.getErrorString(cc));
}
sinlnk.cancel();
}
dout = new TDataType(gaussvals);
gausslnk = new TLink("/WORKSHOP/Station1/Device0","Gaussian",dout,din,TAccess.CA_READ);
if (gausslnk != null)
{
gausslnk.attach(TMode.CM_POLL,gaussCb,1000); // asynchronous access ...
}
dout = new TDataType(amplitude);
amplnk = new TLink("/WORKSHOP/Station1/Device0","Amplitude",dout,din,TAccess.CA_READ);
if (amplnk != null)
{
System.out.println("The amplitude is :");
if ((cc=amplnk.execute()) == 0) // synchronous access ...
{
System.out.println("" + amplitude[0]);
System.out.println("at " + TDataTime.toString(amplnk.getLastTimeStamp()));
}
else
{
System.out.println("error: " + TErrorList.getErrorString(cc));
}
amplnk.cancel();
}
try
{ // let the callbacks come in for 30 seconds ...
Thread.sleep(10000);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
if (gausslnk != null) gausslnk.cancel(); // be polite !
System.exit(0);
}
}

Now run this, to see the that the data handling occurs in the callback routine (at least for 10 seconds).

Notice that we use the access mode of TMode.CM_POLL. This instructs the server to monitor the requested data at the given polling interval and to return the data at that interval. Another common access mode is TMode.CM_DATACHANGE (synonym: TMode.CM_REFRESH). This instructs the server to monitor the data at the given polling interval, but to return the data only if they have changed since the last access (zero tolerance). If you use CM_DATACHANGE mode for our gaussian array, you will likely see and update every second anyway, because something is always changing. DATACHANGE mode is by itself very good for 'status' properties, i.e. properties which do not change their values very often. On the other hand, you may want to apply a tolerence regarding your callback notification. You can do this by calling the setNotificationTolerance() method, passing say 20 as the percent tolerance you will allow. If you do this you should see fewer updates in your gaussian readout.

templnk.attach(TMode.CM_DATACHANGE,gaussCb,1000); // asynchronous access ...
templnk.setNotificationTolerance(0,20);

Including the above link methods for the "Gaussian" link will in fact have fewer lines of output. You might notice that some of the output for the "Amplitude" is mixed up with that of the "Gaussian". This is because the callback for the "Gaussian" occurs in a different thread than that of the main class. You can correct this by adding a "synchronized" tag to the class definitions of main and tempCallback. More than likely the problem will go away if you put the print out for

System.out.println("The amplitude is :");

following the call to amplnk.execute(). You might also think that applying the CM_WAIT bit to the access mode would improve the print out here. The CM_WAIT flag is at times quite useful. (For the access mode you would use for instance TMode.CM_DATACHANGE | TMode.CM_WAIT). This forces a block on the current thread until the initial data set of the attach() link has returned (as if an execute() call followed by an attach() call were made). But, this only guarantees that the data have returned before continuing. It does not guarantee that the callback has completed. This may or may not be important, but it is sometimes worthwhile to pay attention to the multi-threaded nature of java, when doing this sort of "nuts and bolts".

This simple example exhibits explicit use of the fundemental client-side API. There is of course much more in the way of features and tweaking, but it is now a good time to move forward to GUI applications.

GUI Applications

Create a new project in eclipse, and add a package de.desy.helgoland.gui. In the package, add a new visual class. You might have to go to "File" -> "New" -> "Other" before you can find the Visual Class option. In the creation wizard, make sure its a javax.swing.JFrame class (the wizard might try to trick you into implementing a plane object, in which case you might not see anything at all in the visual editor).

Make sure that you have added tine.jar and acopbeans.jar to the external jar files belonging to the project. Now, from the selection palatte, select "Choose Bean" and type "acopbeans" in the "Select a type" dialog option. Then drag the acop bean to the JFrame. Since we haven't turned off the "layout" manager, it will fill the JFrame until we add some other components.

When the acopbeans bean is highlighted, you can fill in some of the properties in the Properties panel. Namely, for "AccessProtocol" type "TINE". For "AccessMode" type "POLL", for DeviceContext type "WORKSHOP" for DeviceGroup type your device server name, for DeviceName type your initial device name (probably "Device 0"), and for property type "Gaussian". The Visual Editor wizard has been busy generating code for you while you have been typing, so you can have a look at this now.

Add a field 'float[] gaussvals; and a field String[] devices; to the class and call the method

acop.acquireDisplayProperties();

after the device properties have been filled in. Then add calls to get the device list from the server, allocate the gaussian array and start an asynchronous link, attaching it to the temperatures array field you created before. This should look something like:

acop.acquireDisplayProperties();
devices = acop.getDeviceNames("WORKSHOP","Station1",null,null);
gaussvals = new float[devices.length];
acop.AttachLink(gaussvals);

Now add the "WindowClosing" event to the main JFrame and make sure you include the line

System.exit(0);

there. And add the AcopReceive event to the acop on the form. Inside the listener add the following two lines:

acop.ClearScreen();
acop.Draw(gaussvals,null,null,devices);

Now run the application and see if it works. You can spend some time cleaning it up, by changing the captions and labels on the acop display, etc.

If you try adding other Swing components onto the JFrame, you might find the default layout manager annoying. Try repeating this example, but after you have your initial JFrame, put a JPanel onto the JFrame first. Turn the layout manager on the panel off. Then add an acop as before and it will remain the size you set it to (however, it will not resize itself automatically if the layout manager is turned off!).

TErrorList
TErrorList
Definition: errors.h:74

Impressum   |   Imprint   |   Datenschutzerklaerung   |   Data Privacy Policy   |   Declaration of Accessibility   |   Erklaerung zur Barrierefreiheit
Generated for TINE API by  doxygen 1.5.8