Reports as a Service

Introduction

With UKG Reports-as-a-Service, you can leverage your existing IBM Cognos reports to access your data without running the reports in the Cognos application.

This document is intended for individuals who are familiar with software development, web service technologies and IBM Cognos.

Reports-as-a-Service API

The UKG Pro Reports-as-a-Service API enables customers to feed integration needs by providing a programmatic interface to their UKG Pro Business Intelligence Reports via a SOAP-based web service. By leveraging the integration between UKG Pro and Cognos, the API enables the integration of UKG Pro data in a variety of use cases from KPI dashboards and mashups to data replication and custom reporting front-ends.

With the UKG Pro Reports-as-a-Service API, reports become integration data sources. The API supports the execution of reports and subsequent retrieval of report output in standardized XML, comma-delimited, pipe-delimited, and space-delimited file formats. This flexibility enables maximum reuse of integration code. Any standard report can be utilized and by using Report Studio—the Cognos report authoring tool—customers are able to create reports tailored specifically to the problem at hand.

In addition to report execution, the API supports the retrieval of report listings based on the permissions of the current user. Information about each report is provided, including the name and path of the report, and any input parameters the report may have.

The API offers several forms of security, using SOAP over HTTPS to ensure data is kept secure, and requiring all service clients to perform a login in order to authenticate. Authentication requires a valid Customer Identifier, an existing UKG Pro Service Account or UKG Pro user name and password, and a User API Key. Users are authorized using the same permissions configured in the UKG Pro portal, therefore no additional security steps are required.

Web Service Feature Highlights

  • Access all reports the user is authorized to see, including reports delivered by UKG and customer reports authored via Cognos Report Studio
  • Retrieve report properties including the report name, path (URL), and input parameters
  • Run reports asynchronously and retrieve results as XML, with support for supplying input parameter values for dynamic report execution
  • Streaming support avoids service call timeouts when retrieving large report results
  • Authenticate using the same user credentials as the UKG Pro Web Portal
  • Report XML provided by the service is the same XML report output generated when run from the web portal

Technical Specifications

  • Simple Object Access Protocol (SOAP) 1.2
  • WS HTTPBinding
  • HTTPS / Secure Sockets Layer (SSL)
  • XML Data Format

Overview

Reports-as-a-Service gives developers access to build applications or perform automated tasks by leveraging Cognos to retrieve your UKG Pro data. This document describes the methods of the service and provides code examples using Microsoft’s Visual Studio 2008 using C# and XML (.NET Framework 3.0 or higher).

The following information describes the service requirements.

Service Specifications
ProtocolSimple Object Access Protocol (SOAP) 1.2
Data FormatXML
SSL SupportRequired
Signup and Licensing
Account RequiredUKG Pro Service Account or UKG Pro Web User with Web Services Permissions

Using a UKG Pro Service Account is recommended. For information regarding establishing and maintaining a UKG Pro Service Account, please refer to the document Maintaining Service Accounts located in the UKG Pro Technical Content section of the Ultimate Library under UKG Pro Web Services and APIs.

Quick Start

This section provides steps for creating a sample application in your development environment to retrieve data from an IBM Cognos report.

Prerequisites

In order to use the service, you will need the following items:

  • A UKG Pro Service Account username and password OR a UKG Pro Web User username and password
    • Please note that Service Accounts do not have access to UTM or Recruitment report data. To access these reports you must use a UKG Pro Web user account.
  • The Customer API key from the UKG Pro Web Service administrative page
  • If you use a UKG Pro Service Account:
    • You will need the User API key from the Service Account administrative page.
    • You must have appropriate permissions granted to the Service Account for the Reports-as-a-Service service. Before a service account can access BI via Reports-as-a-Service or Report Exports, you need to submit a service case from the Customer Success Portal to request this.
  • If you use a UKG Pro Web User account:
    • You will need the User API key from the Web Service administrative page.
  • Report path of an IBM Cognos report that returns the data you desire. (Refer to section: Locating the Report Path in this document.)
  • Review the configuration section for recommended settings for your application

Methods

This section introduces the API methods for Reports-as-a-Service.

Logon Method

The Logon method logs the user into the login service and starts your session.

The Logon method requires a log on request which is comprised of a user name, password, customer API key, and user API key. The customer and user API keys are automatically generated IDs. These IDs can be obtained by contacting your Named Support Representative.

GetReportList Method

Returns a list of the public IBM Cognos reports.

You can programmatically retrieve a list of reports and the path to the report. This is helpful if you are designing an application that allows the user to select the report they want to execute.

GetReportParameters Method

Retrieves a list of parameters for a report.

Use this method to return the list of parameters associated to a report. This is useful for creating applications that the user will enter the parameter values at execution time.

ExecuteReport Method

Runs a report request.

Use this to method to execute the report and return a response object.

To run the report in a format other than XML, create a custom HTTP Header "US-DELIMITER" with the value of the delimiter you would like. For example, for a:

  • Comma-delimited report, use US-DELIMITER: ,
  • Pipe-delimited report, use US-DELIMITER: |
  • Space-delimited report, use US-DELIMITER: SP

ReportStream Method

Runs the string that is the base 64 encoded version of a report. This string must be decoded in order to return the XML version of the report.

Use this to retrieve the ReportKey string.

Logoff Method

Runs a logoff request.

Use this to method to end the session.

Locating the Report Path

Cognos 10

For Cognos 10, the report path is used to identify the report you want to execute. The report path can be found on the properties of the IBM Cognos report.

Launch IBM Cognos and navigate to the report list. Select the properties icon from the action column.

Image-1

On the properties page, select the View the search path link which will display the view dialog. Copy the contents of the Search path input. This is the report path you need to pass to Reports-as-a-Service.

Image-2

Configuration Settings

The following are guidelines for the binding settings in the app.config file on your local application. You may need to adjust these settings depending on the data you are retrieving.


<wsHttpBinding>
        <binding name="service" closeTimeout="00:02:00"
            openTimeout="00:02:00" receiveTimeout="00:10:00" sendTimeout="00:10:00"
            bypassProxyOnLocal="false" transactionFlow="false" hostNameComparisonMode="StrongWildcard"
            maxBufferPoolSize="524288" maxReceivedMessageSize="2147483647"
            messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
            allowCookies="false">
          <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
              maxBytesPerRead="4096" maxNameTableCharCount="16384" />
          <reliableSession ordered="true" inactivityTimeout="00:10:00"
              enabled="false" />
          <security mode="None">
            <transport clientCredentialType="Windows" proxyCredentialType="None"
                realm="" />
            <message clientCredentialType="Windows" negotiateServiceCredential="true" />
          </security>
        </binding>
      </wsHttpBinding>

Cognos 11

For Cognos 11, you can:

  1. Request a list of all reports available via Reports-as-a-Service using the GetReportList Method. The properties will display the report search path. You can use that search path to run that report in Reports-as-a-Service.
  2. Use the ID (as shown in the example screenshot below) from the UI > Properties page to run that report via Reports-as-a-Service.
    Note: Do not copy and paste the sample code as there may be hidden characters that will generate errors.

Image-3

In the C# example below, replace the ReportResponse code with:

ReportResponse response =
	dataClient.ExecuteReport(
		new ReportRequest
		{
			ReportPath = “storeID(\"ID\")"
		},
		context);
		

In the XML examples below, replace the ReportPath code with the storeID value:

<ReportPath>storeID("ID")</ReportPath>

C# Example

Generate the Service Reference

Once you have a user and a report, you need to create a service reference to the BI Data Service and the BI Streaming Service. In your development environment, add a service reference for each endpoint.

In Visual Studio, select the Add Service Reference menu item from the Project menu. Once you enter the service information you should have the reference display in the solution explorer.

Created service reference

Created service reference

Example Code

The following code is an example of running the IBM Cognos birthday report in a console application. You can copy the entire contents to a C# console application and update the following values and have an operable application.

UserName = "YOUR SERVICE ACCOUNT OR WEB USER NAME ",
Password = "YOUR PASSWORD",
UserAPIkey = "YOUR USER API KEY",
CustomerAPIkey = "YOUR CUSTOMER API KEY"


//Example Quick Start Code Begin

using BiDataServicesParametersSample.BiDataServices;
using BiDataServicesParametersSample.BiStreamingService;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Text;
using System.Threading.Tasks;
namespace BiDataServicesParametersSample
{
    class Program
    {
        static void Main(string[] args)
        {
            BIDataServiceClient dataClient = new BIDataServiceClient("WSHttpBinding_IBIDataService");
            try
            {
                // Step 2: Logon the user to retrieve his/her data context
                DataContext context =
                    dataClient.LogOn(
                        new LogOnRequest
                        {
                            ClientAccessKey = "ENXTX",
                            UserName = "rcloud",
                            Password = "password",
                            UserAccessKey = "A1RCL0UD1979"                             
                        });
                // If the user successfully authenticates, execute the report
                if (context.Status == ContextStatus.Ok)
                {
                    //note the following four lines set the US-DELIMITER header that causes the report output to be csv using the delimiter you set as the value of that header
                    //valid values are: ",", "SP", "HT", any single character with a decimal ASCII code between 33 and 126
                    //"SP" means space is the delimiter
                    //"HT" means horizontal tab(|) delimited
                    using (new OperationContextScope(dataClient.InnerChannel))
                    {
                        var httpHeader = new HttpRequestMessageProperty();
//Comment out the next 2 lines of code if you do not want the output to be in CSV
                        httpHeader.Headers["US-DELIMITER"] = ",";
                        OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = httpHeader;
                        // Step 3: Submit a report request
                        ReportResponse response =
                        dataClient.ExecuteReport(
                            new ReportRequest
                            {
                                ReportPath = "/content/folder[@name='UKG Pro BI Content']/folder[@name='UKG Pro BI for Core HR and Payroll']/folder[@name='_UKG Pro Delivered Reports']/folder[@name='Human Resources Reports']/report[@name='Employee Birthdays']",
                                ReportParameters = new ReportParameter[]
                                {
                                    new ReportParameter
                                    {
                                        Name = "EmploymentStatus",
                                        Value = "A",
                                        Required = false,
                                        DataType = "xsdString",
                                        MultiValued = true
                                    },
                                    new ReportParameter
                                    {
                                        Name = "Month",
                                        Value = "11",
                                        Required = false,
                                        DataType = "xsdDouble",
                                        MultiValued = true
                                    }
                                }
                            },
                            context);
                    }
                    // Step 4: Get the report from the streaming service if the status is success
                    if (response.Status == ReportRequestStatus.Success)
                    {
                        GetReportStreamFromResponse(response);
                    }
                    else
                    {
                        Console.WriteLine(response.StatusMessage);
                    }
                }
                else
                {
                    // Inspect the StatusMessage on an authentication failure
                    Console.WriteLine(context.StatusMessage);
                    Console.ReadKey(true);
                }
                // Step 5: Logoff the user from the data service
                dataClient.LogOff(context);
            }
            catch (Exception ex)    // Some unexpected exception...
            {
                // Display any errors that may have occurred
                Console.WriteLine(ex);
            }
            finally
            {
                // Step 6: Finally, close or abort the client
                CloseClientProxy(dataClient);
            }
            Console.Write("Press any key to exit...");
            Console.ReadKey(true);
        }
        /// <summary>
        /// Opens a new connection to the streaming service and streams the results
        /// into a file on the consumers file system
        /// </summary>
        /// <param name="response">The response object which contains the ReportRetrievalUri</param>
        private static void GetReportStreamFromResponse(ReportResponse response)
        {
            string msg;
            Stream input = null;
            BIStreamServiceClient streamClient = null;
            try
            {
                // Step 1: Create the stream client using the ReportRetrievalUri 
                //         provided by the ReportResponse object
                streamClient = new BIStreamServiceClient("WSHttpBinding_IBIStreamService", new EndpointAddress(response.ReportRetrievalUri));
                // Step 2: Call the RetrieveReport method in a loop, exit the loop when 
                //         it is no longer in a Working state
                ReportResponseStatus status;
                do
                {
                    status = streamClient.RetrieveReport(response.ReportKey, out msg, out input);
                } while (status == ReportResponseStatus.Working);
                // Make sure that you succeeded in retrieving the report
                if (status == ReportResponseStatus.Failed)
                {
                    Console.WriteLine("Failed to retrieve report due to \"{0}\"", msg);
                    return;
                }
                // Step 3: Read the contents of the stream to its destination
                using (StreamReader reader = new StreamReader(input))
                {
                    using (Stream output = new FileStream("C:\\StreamOutput.xml", FileMode.Create, FileAccess.Write))
                    {
                        using (StreamWriter writer = new StreamWriter(output))
                        {
                            int bytesRead;
                            char[] buffer = new char[1024];
                            while ((bytesRead = reader.Read(buffer, 0, buffer.Length)) > 0)
                            {
                                writer.Write(buffer, 0, bytesRead);
                            }
                        }
                    } // will implicitly close the stream
                }
            }
            finally
            {
                // Make sure that we close the stream, if we have one
                if (input != null)
                {
                    input.Close();
                }
                // Close or abort the client
                CloseClientProxy(streamClient);
            }
        }
        /// <summary>
        /// Closes the channel which is currently being used by the client
        /// </summary>
        private static void CloseClientProxy(ICommunicationObject client)
        {
            if (client == null) return;
            // In order to close the the channel we must first check if an error
            // occurred on the channel (a.k.a. checking for a faulted state).
            // If its not faulted call Close, otherwise call Abort
            if (client.State != CommunicationState.Faulted)
            {
                // There is a small chance that the close method can cause 
                // an exception so we need to be extra safe and wrap it up
                // in a try/catch
                try
                {
                    client.Close();
                }
                catch
                {
                    client.Abort();
                }
            }
            else
            {
                client.Abort();
            }
        }
    }
}
// Example Quick Start Code End

XML Examples

For Cognos 11, in the XML examples below, replace the ReportPath code with the storeID value:

<ReportPath>storeID("ID")</ReportPath>

Login Request

  <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
  <s:Header>
<a:Action s:mustUnderstand="1">http://www.ultimatesoftware.com/dataservices/bidata/2/IBIDataService/LogOn</a:Action> 
<a:To s:mustUnderstand="1">https://servicehost/services/BiDataService</a:To> 
</s:Header>
  <s:Body>
  <LogOn xmlns="http://www.ultimatesoftware.com/dataservices/bidata/2">
  <logOnRequest xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<UserName>username</UserName> 
<Password>password</Password> 
<ClientAccessKey>12345</ClientAccessKey> 
<UserAccessKey>01234567890</UserAccessKey> 
</logOnRequest>
</LogOn>
</s:Body>
</s:Envelope>

Login Response

  <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
  <s:Header>
<a:Action s:mustUnderstand="1">http://www.ultimatesoftware.com/dataservices/bidata/2/IBIDataService/LogOnResponse</a:Action> 
</s:Header>
   <s:Body>
      <LogOnResponse xmlns="http://www.ultimatesoftware.com/dataservices/bidata/2">
         <LogOnResult xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
            <ServiceId>551f6626-35cc-4239-b829-9d4e79d37de0</ServiceId>
            <ClientAccessKey>RXD3C</ClientAccessKey>
            <Token>807fd472-5196-49b2-bb4c-db7085f59796</Token>
            <Status>Ok</Status>
            <StatusMessage i:nil="true"/>
            <InstanceKey>74e6c146-9bea-43b4-8432-df2755905f92</InstanceKey>
  </LogOnResult>
</LogOnResponse>
</s:Body>
</s:Envelope>

GetReportList

  <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
  <s:Header>
<a:Action s:mustUnderstand="1">http://www.ultimatesoftware.com/dataservices/bidata/2/IBIDataService/GetReportList</a:Action> 
<a:To s:mustUnderstand="1">https://servicehost/services/BiDataService</a:To> 
</s:Header>
  <s:Body>
  <GetReportList xmlns="http://www.ultimatesoftware.com/dataservices/bidata/2">
  <context xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ServiceId>3ccd26d5-94b2-4c0f-b88a-5ccfbe3d7fb0</ServiceId> 
<ClientAccessKey>12345</ClientAccessKey> 
  <!-- GUID, unique per user session --> 
<Token>b8f55e30-d68a-4815-a0de-27417ab7c242</Token> 
<Status>Ok</Status> 
<StatusMessage i:nil="true" /> 
  <!-- GUID, unique per user session --> 
<InstanceKey>06366f8b-999f-433d-a429-aa50153f2d7c</InstanceKey> 
</context>
</GetReportList>
</s:Body>
</s:Envelope>

GetReportParameters

  <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
  <s:Header>
<a:Action s:mustUnderstand="1">http://www.ultimatesoftware.com/dataservices/bidata/2/IBIDataService/GetReportParameters</a:Action> 
<a:To s:mustUnderstand="1">https://servicehost/services/BiDataService</a:To> 
</s:Header>
  <s:Body>
  <GetReportParameters xmlns="http://www.ultimatesoftware.com/dataservices/bidata/2">
<reportPath>/content/folder[@name='UKG Pro BI Content']/folder[@name='UKG Pro BI for Core HR and Payroll']/folder[@name='_UKG Pro Delivered Reports']/folder[@name='Human Resources Reports']/report[@name='Employee Birthdays']</reportPath> 
  <context xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ServiceId>3ccd26d5-94b2-4c0f-b88a-5ccfbe3d7fb0</ServiceId> 
<ClientAccessKey>12345</ClientAccessKey> 
  <!-- GUID, unique per user session --> 
<Token>b8f55e30-d68a-4815-a0de-27417ab7c242</Token> 
<Status>Ok</Status> 
<StatusMessage i:nil="true" /> 
  <!-- GUID, unique per user session --> 
<InstanceKey>06366f8b-999f-433d-a429-aa50153f2d7c</InstanceKey> 
</context>
</GetReportParameters>
</s:Body>
</s:Envelope>

ExecuteReport

  <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
  <s:Header>
<a:Action s:mustUnderstand="1">http://www.ultimatesoftware.com/dataservices/bidata/2/IBIDataService/ExecuteReport</a:Action> 
<a:To s:mustUnderstand="1">https://servicehost/services/BiDataService</a:To> 
</s:Header>
  <s:Body>
  <ExecuteReport xmlns="http://www.ultimatesoftware.com/dataservices/bidata/2">
  <request xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ReportPath>/content/folder[@name='UKG Pro BI Content']/folder[@name='UKG Pro BI for Core HR and Payroll']/folder[@name='_UKG Pro Delivered Reports']/folder[@name='Human Resources Reports']/report[@name='Employee Birthdays']</ReportPath> 
  <ReportParameters>
  <ReportParameter>
<Name>Month</Name> 
<Value>1</Value> 
<Required>false</Required> 
<DataType>xsdDouble</DataType> 
<MultiValued>true</MultiValued> 
</ReportParameter>
</ReportParameters>
</request>
  <context xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ServiceId>3ccd26d5-94b2-4c0f-b88a-5ccfbe3d7fb0</ServiceId> 
<ClientAccessKey>12345</ClientAccessKey> 
<Token>b8f55e30-d68a-4815-a0de-27417ab7c242</Token> 
<Status>Ok</Status> 
<StatusMessage i:nil="true" /> 
<InstanceKey>06366f8b-999f-433d-a429-aa50153f2d7c</InstanceKey> 
</context>
</ExecuteReport>
</s:Body>
</s:Envelope>

RetrieveReport (buffered method)

Endpoint: http://serviceHost/services/BiDataStream

Headers:
Content-Type: text/xml;charset=UTF-8
SOAPAction: http://www.ultimatesoftware.com/dataservices/bistream/2/IBIStreamService/RetrieveReport

Request:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://www.ultimatesoftware.com/dataservices/bistream/2">
<soap:Header>
<ns:ReportKey>78399808-8a8f-4a55-84f5-235c6d04ccf1</ns:ReportKey>
</soap:Header>
<soap:Body>
<ns:RetrieveReportRequest/>
</soap:Body>
</soap:Envelope>

ReportStream (streaming method)

Endpoint: http://serviceHost/services/BIStreamingService

Headers:
Content-Type: application/soap+xml;charset=UTF-8;action=http://www.ultimatesoftware.com/dataservices/bistream/2/IBIStreamService/RetrieveReport

Request:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ns="http://www.ultimatesoftware.com/dataservices/bistream/2">
<soap:Header>
<ns:ReportKey>78399808-8a8f-4a55-84f5-235c6d04ccf1</ns:ReportKey>
</soap:Header>
<soap:Body>
<ns:RetrieveReportRequest/>
</soap:Body>
</soap:Envelope>

Logoff

  <s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope" xmlns:a="http://www.w3.org/2005/08/addressing">
  <s:Header>
<a:Action s:mustUnderstand="1">http://www.ultimatesoftware.com/dataservices/bidata/2/IBIDataService/LogOff</a:Action> 
<a:To s:mustUnderstand="1">http://servicehost/services/BiDataService</a:To> 
</s:Header>
  <s:Body>
  <LogOff xmlns="http://www.ultimatesoftware.com/dataservices/bidata/2">
  <context xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ServiceId>04873c39-fe29-4cad-9842-9a5c4a289758</ServiceId> 
<ClientAccessKey>12345</ClientAccessKey> 
<Token>b58358a0-c9cf-43b2-b9ce-eb63d0c52b9c</Token> 
<Status>Ok</Status> 
<StatusMessage i:nil="true" /> 
<InstanceKey>f8f65ba1-87de-4ac4-950a-104c1754c5e2</InstanceKey> 
</context>
</LogOff>
</s:Body>
</s:Envelope>

Using Parameters

If your report requires a parameter, it is possible to add this to the XML. For instance, if you want to retrieve a report for a particular pay date, you can add the following parameter in your C# code:

ReportParameter param = new ReportParameter
{Name = "PayDate", Value = "2014-06-06T00:00:00"}

Additional Debugging Support

API clients can optionally provide a log correlation id by passing a GUID or UUID in the US-CORRELATION-ID HTTP header. If you do use this feature you should record the correlation id of failed requests and provide it to our support team so they can easily identify the logs for your request and save time when troubleshooting issues.