Skip navigation
All Places > PI Developers Club > Blog > 2016 > October



I want to share with you how simple it is to create a simple Java app using PI JDBC  2016 and Eclipse IDE  Actually, I am using Eclipse IDE for Java Developers 4.6.0 (Neon release).



Before we start, let me explain the roles of each VM of my domain:


- MARC-PI2016 has the PI Data Archive 2016 and PI AF

- MARC-WEB-SQL has the PI SQL DAS 2016 installed

- MARC-WIN8 has the client tools including PI JDBC and Eclipse.



Here are the steps:


  1. Open Eclipse
  2. Click on File --> New --> Java Project. The window below will be opened:
  3. Type a project name, a location and click on Next.

  4. On the next window, you should define the Java Settings, click on the Libraries ribbon and then on "Add External JARs..." button.
  5. Find the PIJDBCDriver.jar file under the %PIHOME64%\JDBC folder.

  6. The new project is available on the package explorer.

  7. Expand the root folder of the project, right-click on the folder src and click on New --> Class.
  8. Type a Name and make sure to check the "public static void main(String[] args)" option.

  9. Replace the content of the new created file with the content below:

    import java.sql.Connection;
    import java.sql.DatabaseMetaData;
    import java.sql.DriverManager;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.Properties;
    public class SampleAppMain {
      public static void main(String[] args) {
      Console console = System.console();
      String dasName = "MARC-WEB-SQL";
      String dataSourceName = "MARC-PI2016";
      String isTrustedConnection = "Yes";
      String protocolOrder = "nettcp:5462";
      String logLevel = "0";
      String tagNamePattern = "sin%";
      System.out.println("\tData Access Server name: " + dasName);
      System.out.println("\tPI Data Archive name: " + dataSourceName);
      System.out.println("\tUse trusted connection?: " + isTrustedConnection);
      System.out.println("\tProtocol order: " + protocolOrder);
      System.out.println("\tLog level: " + logLevel);
      System.out.println("\tPI tag name/name pattern: " + tagNamePattern + "\n");
      Connection connection = null;
      String url = "";
      String driverClassName = "com.osisoft.jdbc.Driver";
      PreparedStatement pStatement = null;
      ResultSet resultSet = null;
      Properties properties = new Properties();
      url = "jdbc:pioledb://" + dasName + "/Data Source=" + dataSourceName + "; Integrated Security=SSPI";
      properties.put("TrustedConnection", isTrustedConnection);
      properties.put("ProtocolOrder", protocolOrder);
      properties.put("LogConsole", "True");
      properties.put("LogLevel", logLevel);
      try {
      connection = DriverManager.getConnection(url, properties);
      pStatement = connection.prepareStatement("SELECT tag, value FROM pisnapshot WHERE tag like ?");
      DatabaseMetaData metaData = connection.getMetaData();
      System.out.println(metaData.getDriverName() + " " + metaData.getDriverVersion()); 
      System.out.println(metaData.getDatabaseProductVersion() + "\n");  
             // bind Parameter representing the Tag name
      pStatement.setString(1, tagNamePattern);
      resultSet = pStatement.executeQuery();
      // read the data
      while ( {
      String value, tag;
      tag = resultSet.getString(1);
      value = resultSet.getString(2);
      System.out.println( tag + " " + value);
      catch (Exception ex) {
      try {
      if(resultSet != null) resultSet.close();
      if(connection != null) connection.close();
      } catch (SQLException ex) {

  10. This example was taken from the sample app available on %PIHOME64%\JDBC\Samples\GetSnap\src\
  11. Press F11 or click on Run --> Debug to execute your problem. You will see the results on the Console window.



Hope this is helpful for you! Please share your comments!


This is an introduction to the new asynchronous methods that may help improving performance in specific circumstances, particularly with UI-based applications such as WinForm and WPF.  This blog post will try to answer questions such as:

  • When should I use async calls with the PI AF SDK
  • How to use async combined with the await keyword – ( New in C# 5.0, .NET4.5 / VS2012+)



What is non-async?

Typically when you make a method call, you are blocking the calling method until the call completes. The calling method can only resume when control is passed back to it after the called methods completes and returns. Below is an example of this, the foo method will wait until bar has completed before it can complete.


public void foo()
    bar(); //bar will take time to return, foo will wait before
    Console.WriteLine("foo completed");

public void bar()
    for int i = 0; i < 9999999999; i++)
       //very busy and will take a long time



Async method

However, there are scenarios where you would want the client to continue doing some other work while the long running method continues, this concept can be generally referred to as asynchronous method invocation. This technique does not block the caller but it requires another thread to take care of the work and also to generate a notification when the method completes, this is also known as a callback method. Below is an example how you could have done it in the version 3.5 of .NET framework.


public void foo()
    bar(); //bar will take a long time to return, foo will terminate immediately
    Console.WriteLine("foo completed immediately");

public void barCompleted()
   Console.WriteLine("bar completed after a long wait");

public void bar()
    ThreadStartConsole ts = () =>
        for (int i = 0; i < 9999999999; i++)
           //very busy and will take a long time
   ts += barCompleted;
   Thread t = Thread(ts) {IsBackground = true};


As you can see above this construction is a little clogged. Fortunately, Microsoft .NET Team came up with a very elegant solution introduced in .NET 4.5, with the C# keywords async and await. The await keyword usually goes along with a method call that have a suffix 'async'. The async/await construction instruct the compiler to generate a callback method internally when code is compiled, for simplicity you may imagine this is done like the example above, if you want all the details you should check the MSDN documentation.

Here is another example where we are making use of the new async/await keywords, you may notice that there is no callback required. When you see the await keyword, the code will do a non-blocking pause there and will resume later, when ready.


public async void fooAsync() 
    var response = await fooBar() // the code will pause here, until content is returned, however this will not block the thread

public async Task<HttpResponseMessage> barAsync();
   var barClient= new System.NetHttp.HttpClient()
   HttpResponseMessage response = await barClient.GetAsync("/get/bar/info");
   return response;


This may seem strange at first as it takes a little time to get used to it.


Async Await works with both I/O bound and CPU bound methods


So far we said that Async means a separate thread that will execute a long task, but it is not only that. Imagine that the long running task simply waits for a network call to return since there is no CPU involved, so why should we create a thread to wait? This is wasting resources. This is why Microsoft provided async I/O methods in the .NET framework for tasks related to the file system or network access. The async/await construction can be used the same way and can handle both CPU-bound and I/O-bound types of tasks. For PI AF SDK async calls there is a good portion of the wait time that is related to the network (I/O-bound), so using PI AF SDK async methods help minimize the wait times of the calling method. If you are interested in the difference between I/O-Bound and CPU-Bound methods with async/await you should look at this article on Stack OverFlow that gives a good explanation.


Async availability in PI AF SDK


Requests for asynchronous AFData and AFListData methods have been requested since Microsoft included async await methods in Visual Studio 2012. Some use cases for async methods are PI Data Services, PI Saas REST calls and buffered data writes. For all these methods, the architecture requires non-blocking calls for all server access, provide programmers with optimizations for networking and server performance expected in SaaS, buffered writes are asynchronous so it makes sense that the calls should be asynchronous as well. Async methods provide concurrent access to PI Data Archive that aid in reducing the effect of latency. This can be significant for ASP.NET Web API applications to serve more requests since waiting threads can be returned to the thread pool for re-use. For a list of the async methods see the AFData Class and the AFListData Class. PIPoint data methods are similar to the AFData methods.


PI AF SDK Example Code




The AFAsyncDataReader is a simple console application that demonstrates making a summary call to get the attribute values using the sync and async methods.


For the sync call example, it demonstrates how the code will stop and wait for the synchronous call to GetSummariesSync. The call will not show any activity until the method returns and then will print out a message, “Doing work on the Main Thread AFTER waiting“. It has a stopwatch that will print out the elapsed time the method takes to execute and prints it to the console.


For the async call section, it shows how the code will continue to execute on the main thread while waiting for the asynchronous call to GetSummariesAsync. The call will show the execution on the main thread by printing to the console the message, “Doing work on the Main Thread “until

the method completes. It also has a stopwatch that will print out the elapsed time the method takes to execute and prints it to the console.                    


public static class AFAsyncDataReader
   public static async Task<IList<Dictionary<AFsummaryTypes,AFValue>>>
               GetSummariesAsync(AFAttributeList attributeList)

      Task<IDictionary<AFSummaryTypes,AFvalue>>{} tasks = attributeList
         .Where (attr => (attr.SupportedDataMethods & AFDataMethods.Asynchronous) == AFDataMethods.Asynchronous)
         .Select(async attr =>
              AFSummaryTypes mySummaries = AFSummaryTypes.Minimum | AFSummaryTypes.Maximum | AFSummaryTypes.Average | AfSummaryTypes.Total;
              TimeRange timeRange = new AFTimeRange(new AFTime("*-1d"), new AFTime("*"));

               return await attr.Data.SummaryAsync(
               timerange:timeRange, summaryRange:mySummaries, calculationBasis:AFCalculationBasis.TimeWeighted, timeType:AFTimestampCalculation.Auto);
           catch(AggregationException ae)
               return null;
    return await Task.WhenAll(tasks);


When we launch an async call for each attribute (GetSummariesAsync() will make an AFData.SummaryAsync call. We launch them all at once and then await for them all to complete. This suspends the current execution until all calls complete. The method only returns once we've received results from all of our async calls. The async caller in this case must block (with Task.Result) and can only write to the Console (i.e. process the results) once all the tasks are complete.


Timestamp Inspector


Rick Davin’s Timestamp Inspector project is worth a look as well. This tool is dual purposed and primarily is a tool to quickly and easily diagnose issues regarding timestamps of the selected PI Points in a windows program. The secondary purpose of the app, of which we are interested, is to demonstrate making async PI calls, how to keep the form UI responsive while the async calls run in another task and how to cancel upon request. This project was written in C# 6.0, Visual Studio 2016, .NET 4.6.1, and PI AF SDK 2.8. It also has a dependency on the PIDevClub.Library.

The code shows 2 ways to run a background task.


//var completed = await RunBackgroundTaskWithoutlambda(token, tag, timeRange, DataProgress, statsProgress);
var completed = await RunBackgroundTaskWithoutLambda(token, tag, timeRange, dataProgress, statsProgress);


However, only one branch is active. You can run either branch by commenting/uncommenting the desired await call. For the method RunBackgroundTaskWithoutLambda, is an async method that calls another async method, BackgroundDoWorkAsync, which can be awaited.

For the method RunBackgroundTaskWithLambda, awaits a lambda delegate for which you cannot await a call inside the lambda but use .Result. The project is well documented as it walks you through the process of executing these aysnc methods in a Windows forms application.



The PI AF SDK Asynchronous data methods provide a mechanism for concurrency during a data access call to the PI Data Archive. Concurrency occurs in 2 scenarios: Data requests to the PI Data Archive and Non-waiting client side execution.

Async calls are useful to optimize client application development that will not wait until server execution completes. However, it may take some trial to be able to understand and implement these async methods in a way that is the most optimal for your application.


We encourage you to use these new PI AF SDK async methods and give us your feedback.


Building Responsive UI using Async Await in CSharp – CodeProject

Async/Await – Best Practices in Asynchronous Programming - MSDN

Working with PI AF SDK 2016 – Introduction to the blog post series

OSIsoft TechCon 2016 – Advanced Programming with PI AF SDK

PI Developers Club Webinar Series – New Features and Best Practices with PI AF SDK 2016

Filter Blog

By date: By tag: