Currently Being Moderated

Synopsis: In this series of Blogs, I'll explore how the Web Intelligence RESTful Raylight Web Services allow users to automate and simplify the management, modification, creation and updates to a batch of Web Intelligence documents.  This series will be of interest to Web Intelligence administrators, designers, consultants and power users, to save time and effort and get the most out of your investment in Web Intelligence.

 

Intro

 

I work in SAP Support, specializing in SAP BusinessObjects suite of products, specifically Web Intelligence and the Software Development Kit (SDK).

 

Being a Support Guy, I live to help people out - resolve problems, fix issues, overcome difficulties, go for the happy ending.

 

But sometimes in this job, you have to deliver a tough message: "You can't do that".  "That's too difficult".  "Not supported"  "Beyond the product's capabilities"

 

Important part of the job, but not something I care to deliver.

 

One such conversation, that's happened more times that I care to remember, goes like this:

 

Customer: "Hey, I need to make a simple change to a Web Intelligence document."

Support Guy: "That sound simple enough."

Customer: "But there's hundreds of these WebI docs that needs this change."

Support Guy: "Oh."

Customer: "Any way I can automate the task?  It'll take me days or even weeks to make changes to all the docs."

Support Guy: "Sure!  Do you know Java(tm)?"

Customer: "Uh no. I've wrangled a bit of VBScript"

Support Guy: "Nope.  Sorry"

Customer: "I used some C# .NET for a project."

Support Guy: "It's gotta be Java.  The WebI API for report modification is Java-only..."

Customer "Well, ok.  I learned a bit of Java in college.  I can get by."

Support Guy: "..in a web application."

Customer: "Huh?  Why.  It's Java.  That shouldn't matter."

Support Guy: "Well, the WebI API doesn't care, but you need to access the WebI document from  BI Platform using the Platform SDK.  And that's only supported in a web application, because of how the Enteprrise Framework CORBA TCP/IP is designed."

Customer: "Starting to sound complicated.  Ok, so once I can get a Java web application, then I can make simple changes to a WebI doc?"

Support Guy: "Absolutely!  You need to learn the ReportEngine Java, REBean for short.  To get started, you need to become familiar with, say, about 40 classes, and the structure of ReportBlocks, ReportElements, and walk down the report hierarchy."

Customer: "But all I want to do is make one simple change!  For a few hundred WebI docs, but it's really simple! Don't you have any other solution?"

Support Guy: "Well, uh.  You wouldn't happen to have a Intern over the Summer?  That can go and manually fix up all the reports?"

 

 

So the last comment's a bit in jest.  But I do know customers who've done that.  They, their co-workers, their assistants, or temporary help had to go through hundreds of reports to make simple changes in each one.

 

The REBean API - the one used to implement the Web Intelligence viewer and designer - is extremely powerful, but extremely complicated, and difficult to deploy.  It's just not made for simple tasks.

 

I've always thought if there was just a simple API, that is supported using any programming language, simple to use, and accessible anywhere, then that would be the coolest - it'll open up automating WebI talks to the casual coders and power users.

 

That's where the Web Intelligence RESTful Raylight Web Services API comes in - it's WebI scripting that everyone can use, everywhere.

 

Web Intelligence Scripting for Everyone Everywhere

 

You can read about Raylight in the SCN Community here: http://scn.sap.com/community/restful-sdk

 

It's Simple. It's Easy to Learn.  It Supports any Programming Language that Supports HTTP, meaning pretty much all programming languages common today. And you can run the program anywhere that has access to the web.  That's pretty much everywhere nowadays.

 

And you don't have to be an expert code wranglers to get something useful out of it.  To give and example, when I first learned REBean API, it took me days till I stopped feeling like I was stumbling and mumbling along.  But when I started learning Raylight, within an hour I was exporting a WebI document to PDF, and by the end of the day, I was doing some pretty nifty stuff - scheduling, modifying document images and pages,changing chart color styles,, batch processing documents, all the good stuff.

 

And the scripts I was writing to accomplish this was concise, modular, easy to read and understand, and simple to modify.  I can take a 'cookbook' approach when trying to accomplish a given task.   

 

If you've looked at any of the RESTful Web Services APIs out there, you'll know why.  REST is based on HTTP verbs - essentially, Raylight is built on four methods: HTTP GET, POST, PUT and DELETE.  All functional dstinction beyond that is specified via  the URI and content - the HTTP headers, parameters and body.

 

An exmple:  to log onto the Raylight API, you HTTP POST to http://<host>:<port>/biprws/logon/long, Content-Type application/json and Body {"userName": "Administrator", "password": "Password", "auth": "secEnterprise"}, and to export a WebI document to PDF, you HTTP GET to http://<host>:<port>/biprws/raylight/v1/documents/<document SI_ID>/pages with Accept application/pdf.

 

Pretty intuitive and simple.

 

Now, the first decision to make is what scripting language to use?  Most scripting languages support REST - Java, .NET, Python, Perl, Ruby, even VBScript.    My decision for this series of blogs came down to these criteria:  (1) economy of expression, (2) feature modern language constructs, (3) generally available, (4) robust support for needed functionality, and (5) ease of use.  One scripting language stood out, particularly when it came to ease of use.

 

Microsoft Powershell

 

Powershell version 4 (http://technet.microsoft.com/en-us/library/hh857339.aspx) recently was made public, and that's what I decided to use.  It's featureset is impressive -

access to .NET and COM libraries, direct and fully-featured support for REST via the Invoke-RestMethod Cmdlet, and native support for both XML and JSON.  It's the scripting language and IDE supplied with Microsoft products such as SQL Server to accomplish administrative tasks.

 

Powershell version 3 had an inadequate implementation of Invoke-RestMethod, particularly the non-support for setting Accept HTTP Headers, but that's all resolved with version 4. 

 

The native support for JSON is pretty nify- you can generate JSON structures by dynamically creating a Powershell CustomObject, and have that translated to JSON serialization form.  For example to generate my logon body, I invoke:

 

$logonInfo = @{}

$logonInfo.userName = "Administrator"   

$logonInfo.password = "Password1"

 

$logonInfo.auth = "secEnterprise"  

 

$logon = ($logonInfo | ConvertTo-Json)

 

=>

 

{

    "username" : "Administrator",

    "password" : "Password",

  "auth": "secEnterprise"

}

 

So I can dynamically build up objects with the required members, then have Powershell simply translate them to JSON structures that I can then send through to the REST HTTP call.  The Invoke-RestMethod is intuitive:

 

$result = Invoke-RestMethod -Method <method> -URI <url> -Headers <headers> -Body <body>

 

where <method> is one of Get, Post, Put or Delete, the <url> is the REST resource URI, the headers are a dictionary of HTTP Header values and <body> represents the string or object to send with the REST call.

 

Here is how one would log onto Raylight using Powershell:

 

 

$logonInfo = @{}

 

 

$logonInfo.userName = "Administrator" 

$logonInfo.password = "Password1"

$logonInfo.auth = "secEnterprise"

 

$logon = ($logonInfo | ConvertTo-Json)

 

 

 

$headers = @{"Accept" = "application/json";"Content-Type" = "application/json"}

 

 

 

$result = Invoke-RestMethod -Method Post -Uri "http://host:8080/biprws/logon/long" -Headers $headers -Body $logon

 

 

 

where I'm sending in the logon credentials to the logon/long resource in Raylight, specifying that the content is in JSON by setting Content-Type to be the JSON MIME type.

 

 

I can extract the logon token from the $result and use that for subsequent calls. For example, here is how I would retrieve the PDF export for a WebI document identified by the id SI_ID=2269 and save to a file:

 

$filePath = "C:\Folder\webidoc.pdf"

$logonToken = "`"" + $result.logonToken + "`""

$headers = @{ "X-SAP-LogonToken" = $logonToken; "Accept" = "application/pdf"}

 

 

 

 

Invoke-RestMethod -Method Get -Uri "http://host:8080/biprws/raylight/v1/documents/2269/pages" -Headers $headers -OutFile $filePath

 

 

 

 

I've added export_pdf.ps1, a Powershell script, to this Blog post.  It adds a bit more functionality - refresh the document, unload the document from Raylight, and log off.

 

Have a look!

 

Summary

 

I want to take a cookbook approach to scripting Web Intelligence using the Raylight API and Powershell.  In subsequent blogs, I'll cover the commonly-requested tasks: export, schedule, change styles, add reports, change Universes, etc. 

 

If you have any functionality you'd like me to illustrate, that you'll think others would also like to see, please let me know, and I'll see what I can do. 

 

Next entry: http://scn.sap.com/community/restful-sdk/blog/2013/09/06/scripting-web-intelligence-the-restful-raylight-web-services--working-it

 

 

Code: export_pdf.ps1

 

<#
.Synopsis
Exports WebI to PDF.
.Description
Logs onto BI Platform, retrieves PDF export of a Web Intelligence document and save to specified file.
Modify this script to enter the logon credentials, URL to the RESTful Web Services, Language, Document SI_ID and folder path.
#>

############################################################################################################################
# Input: $logonInfo, $hostUrl, $locale, $documentId and $folderPath to suite your preferences
$logonInfo = @{}
$logonInfo.userName = "Administrator"
$logonInfo.password = "Password1"
$logonInfo.auth     = "secEnterprise"

$hostUrl = "http://10.160.206.89:6405/biprws"

$documentId = 7827         # SI_ID for the document

$locale = "en-US"          # Format language for the WebI exporter
$contentLocale = "en-US"   # Format language for the WebI document contents

$folderPath = "C:\Users\I819039\Desktop\RESTful"  # Folder where PDF file will be saved.
############################################################################################################################

$raylightUrl = $hostUrl + "/raylight/v1"
$documentUrl = $raylightUrl + "/documents/" + $documentId

# Logon and retrieve the logon token to be used in subsequent RESTful calls.
$headers = @{"Accept"       = "application/json" ;
             "Content-Type" = "application/json"
            }
$result = Invoke-RestMethod -Method Post -Uri ($hostUrl + "/logon/long") -Headers $headers -Body (ConvertTo-Json($logonInfo))

$logonToken =  "`"" + $result.logonToken + "`""  # The logon token must be delimited by double-quotes.

# Get Web Intelligence document information.
$headers = @{ "X-SAP-LogonToken" = $logonToken ;
              "Accept"           = "application/json" ;
              "Content-Type"     = "application/json";
              "Accept-Language"  = $locale;
              "X-SAP-PVL"        = $contentLocale
              }
$result = Invoke-RestMethod -Method Get -Uri $documentUrl -Headers $headers
$document = $result.document

# Refresh the document by sending empty prompts (assumes document has no prompts).
$headers = @{ "X-SAP-LogonToken" = $logonToken ;
              "Accept"           = "application/json" ;
              "Content-Type"     = "application/json" ;
              "X-SAP-PVL"        = $contentLocale
              }
$parametersUrl = $documentUrl + "/parameters"
$result = Invoke-RestMethod -Method Put -Uri $parametersUrl -Headers $headers

# Retrieve and save PDF first ensuring the file path is valid.
$filePath = $folderPath + "/" + $document.name + ".pdf"
if(Test-Path $filePath -isValid) {
    # Get PDF and save to file
    $headers = @{ "X-SAP-LogonToken" = $logonToken ;
                  "Accept"           = "application/pdf" ;
                  "X-SAP-PVL" = $contentLocale
               }
    Invoke-WebRequest -Method Get -Uri ($documentUrl + "/pages") -Headers $headers -OutFile $filePath

} else {
    Write-Error "Invalid file path " + $filePath
}

# Unload document from Raylight.
$headers = @{ "X-SAP-LogonToken" = $logonToken ;
              "Accept"           = "application/json" ;
              "Content-Type"     = "application/json" ;
              "X-SAP-PVL"        = $contentLocale
              }
$result = Invoke-RestMethod -Method Put -Uri $documentUrl -Headers $headers -Body (ConvertTo-Json(@{"document"=@{"state"="Unused"}}))

# Log off the Session identified by the X-SAP-LogonToken HTTP Header
$headers = @{ "X-SAP-LogonToken" = $logonToken ;
              "Accept"           = "application/json" ;
              "Content-Type"     = "application/json"
            }
Invoke-RestMethod -Method Post -Uri ($hostUrl + "/logoff") -Headers $headers

Comments

Actions