MvanderVeeken

Accessing PI Webservices from Java

Blog Post created by MvanderVeeken Employee on Jan 17, 2012

There are a lot of examples available on vCampus on how to access PI Web Services from .NET. PI Web Services is based on Windows Communication Foundation (WCF) and integration with Visual Studio is very good. There are less examples on how to access PI Web Services from Java yet, and there has been some interest in this. Steve Mohr posted a Java sample for the CTP release of PI Webservices earlier.

 

I haven't worked with Java for years, so I thought it would be a nice challenge to dive into it a little bit and share it with the community.

 

Getting started

 

To get started, you will need the following

  • PI Web Services. PI Web Services in available at the Download Center. The PI Web Services User Guide (pdf or chm) is available in the Library under 'vCampus Library > vCampus PI Products Kit > Data Access Technologies'.
  • Java Development Kit (JDK). You need the JDK to develop, you cannot use the Java Runtime Environment (JRE) in this case. You can download the newest JDK versions here.
  • Eclipse. An IDE for Java, you can download it for free here. There is no installation required. You can run eclipse.exe it when you unpack it. You probably want to unpack it at a convenient location (e.g. 'C:\Program Files\Eclipse')
  • GlasFish Metro. The web service stack for Java we are going to be using. This is also free. You can download it here

Installing Metro is very straight forward. Go to a directory where you want to install Metro, copy the Metro_1_4.jar file and execute it by double clicking or running 'java -jar metro-1_4.jar' in the command prompt. This will create a new 'metro' sub directory.

 

Creating the Java classes for PI Web Services

 

What we want to do first is let Metro create all the appropriate Java classes for PI Web Services. We are going to use a tool called 'wsimport', which is roughly the equivalent of Microsoft's 'svcutil' tool. In order to do this, we are going to make a small 'description' file for our PI Web Services client. 

 

Go to the directory where you just installed 'Metro'. Create a new XML file called 'PIWebservices.xml' with the following content:

 

 

 

<bindings

 

    xmlns:xsd="http://www.w3.org/2001/XMLSchema"

 

    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"

 

    wsdlLocaption="http://ultralisk/PIWebservices/PiTimeSeries.svc?wsdl"

 

    xmlns="http://java.sun.com/xml/ns/jaxws">

 

    <bindings node="wsdl:definitions">

 

        <enableAsyncMapping>true</enableAsyncMapping>

 

    </bindings>

 

</bindings>

 

The URL (in red) should be the URL to you PiTimeSeries.svc service, don't forget the port number (e.g. http://piserver:8080/PIWebservices/PiTimeSeries.svc?wsdl). The 'enableAsyncMapping' makes sure we also generate asynchronous methods to the server. Save this file and close it. We are not ready to generate the java classes with wsimport. Startup a command prompt and navigate to your Metro directory.

 

First, we want to make sure we set the 'JAVA_HOME' variable. If it is already set properly (you can check this by executing 'echo %JAVA_HOME%' in the command prompt), you can skip this step. wsimport makes use of this variable to access the java tools from the JDK. When we are sure JAVA_HOME is set correctly, we can execute the following command:

 

bin\wsimport -extension -keep -Xnocompile -b PIWebservices.xml http://ultralisk/piwebservices/pitimeseries.svc?wsdl

 

Again, make sure that the URL in red is the URL to your PITimeSeries.svc file. The PIWebservices.xml file is the XML file we created previously. You should get the following output:

 

0878.metro_5F00_wsimport.png

 

If you look closely, you will see that a new directory called 'com' has been created in your Metro installation directory. If you browse to it, you will notice that it is a few levels deep ('\com\osisoft\xml\services\pidataservice'). You will see that a lot of .java files have been created. If you are familiar with PI Web Services, you will notice that these files are named after PI Web Services operations and data structures.

 

4452.metro_5F00_wsimport_5F00_generated_5F00_files.png

 

Creating the Java Project

 

We are going to use these generated classes in our Java project. Start up Eclipse, and create a new Java Project (File > New > Java Project) called 'PIWebservicesClient.

 

4370.metro_5F00_eclipse_5F00_new_5F00_project.png

 

Click Finish. In the package explorer, expand the 'PIWebservicesClient' node and right click on the 'src' folder. Select New > Class, and name it 'Main'. Also make sure the wizzard creates the 'public static void main(String[] args)' entry method.

 

6470.metro_5F00_eclipse_5F00_new_5F00_class.png

 

Click Finish. Now we are going to import the .java files we generated with wsimport. In Windows Explorer, select the 'com' folder (in the Metro directory) and drag the folder to the 'src' folder in Eclipse. If it asks how the files and folders should be imported, select 'Copy files and folders'. Click OK. You will see that a new 'com.osisoft.xml.services.pidataservice' package has been created in your 'src' folder.

 

1004.metro_5F00_eclipse_5F00_com_5F00_package.png

 

Now that all the preparations are done, let's get to some Java coding. For our first example we are going to get the snapshot value of a PI Point using the getPISnapshotData method.

 

Go to your Main class, and change it to look like this:

 
import java.net.URL;
import javax.xml.namespace.*;
import com.osisoft.xml.services.pidataservice.*;

public class Main {

     /**
      * @param args
      */
     public static void main(String[] args) {
          // TODO Auto-generated method stub
          try {
               
               PITimeSeriesService service = new PITimeSeriesService(new URL("http://ultralisk/PIWebservices/pitimeseries.svc?wsdl"),
                         new QName("http://xml.osisoft.com/services/PIDataService", "PITimeSeriesService"));
               
               IPITimeSeries port = service.getBasicEndpoint();
               
               ArrayOfString paths = new ArrayOfString();
               
               paths.getString().add("\\\\Ultralisk\\sinusoid");
               ArrayOfTimeSeries result = port.getPISnapshotData(paths);
               
               TimeSeries timeSerie = result.getTimeSeries().get(0);
              TimedValue value = timeSerie.getTimedValues().getTimedValue().get(0);
               
               System.out.println(timeSerie.getPath() + " " + value.getTime() + " " + value.getValue());
               
          } catch (Exception e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
          }          
     }
}

 Again, make sure you set the URL's to your PI Web Services URL, and change the path of the PI Point ('sinusoid') to your PI Server. Please note the double backslashes used for escaping. If we run this code in Eclipse, the output should be:

 

0284.metro_5F00_eclipse_5F00_com_5F00_output1.png

 

This means we have successfully called the GetPISnapshotData method on our PI Web Services service! You will probably have noticed that all the data is in container structures, so it's a little bit different than we are used to.

 

A little bit more advanced example would be getting archive data.

 
// TODO Auto-generated method stub
          try {
               
               PITimeSeriesService service = new PITimeSeriesService(new URL("http://ultralisk/PIWebservices/pitimeseries.svc?wsdl"),
                         new QName("http://xml.osisoft.com/services/PIDataService", "PITimeSeriesService"));
               
               IPITimeSeries port = service.getBasicEndpoint();
               
               
               ArrayOfPIArcDataRequest requests = new ArrayOfPIArcDataRequest();
               
               PIArcDataRequest request = new PIArcDataRequest();
               
               request.setPath("\\\\Ultralisk\\cdt158");
               
               TimeRange timeRange = new TimeRange();
               timeRange.setStart("*-1h");
               timeRange.setEnd("*");
               
               PIArcManner manner = new PIArcManner();
               request.setTimeRange(timeRange);
               
               request.setPIArcManner(manner);

               requests.getPIArcDataRequest().add(request);
               ArrayOfTimeSeries result = port.getPIArchiveData(requests);
               TimeSeries serie = result.getTimeSeries().get(0);
               for (TimedValue value : serie.getTimedValues().getTimedValue())     {
                    System.out.println(serie.getPath() + " " + value.getTime() + " " + value.getValue());
               
               }
               
          } catch (Exception e) {
               // TODO Auto-generated catch block
               e.printStackTrace();
          }          

 If we run this, the output should be something like:

 

0647.metro_5F00_eclipse_5F00_com_5F00_output2.png

 

From here

 

If you look at the 'PI Web Services User Guide', you should be able to roughly translate all the operations and structures to their Java equivalent. Getting the Java classes generated and creating the connection objects is probably the unfamiliar part. Once that is set up, accessing the right PI Web Services methods and extracting the right information from the structures should be straight forward.

 

If you have any questions about PI Web Services, please have a look at the Web Services and PI discussion forum.

 

 

 

 

Outcomes