Category Archives: Business Objects

BusinessObjects

How to change universe of a webi document using BO RE Java SDK

Web Intelligence documents use one or many universes. Sometimes it is necessary to change universes for a bunch of reports. Changing universe might be very difficult if you need to modify dozens of documents. Luckily it is possible to utilize BusinessObjects Report Engine Java SDK.

There is a number of Webi documents in a folder which use a number of universes. The task is to make a copy of these on the same BOE server.

It is easy to copy documents (in CMC) and universes (using Universe Designer. The complex problem is to change a copied document to use the copied universes.

The manual procedure of changing universe for a document is the following:

  • Open Webi document in Web Intelligence in edit mode.
  • Click Edit query.
  • For each query, change universe in the query properties.
  • Changing universe you have to confirm mapping. If you change a universe to its copy, you do not need to do anything in this mapping. But just confirming it takes few seconds.

The automated procedure for all documents will do the following:

  • Get list of universe IDs that used by the copied documents.
  • Get list of all available universes.
  • Create a mapping of IDs.
  • Map all reports from the original universes to their copies using the mapping.

If you have to modify 5 documents, the writing code might take even more time then do it manually, but anyway coding is more fun then clicking 🙂

If you have to modify 50  documents, think twice before starting manual work.

Java Function

public static boolean changeUniverses(DocumentInstance widoc,
                                      HashMap<String, String> mapping)
{
   boolean failed = false;
   DataProviders dps = widoc.getDataProviders();
   HashSet<DataSource> dataSources = new HashSet<DataSource>();
   for (int i = 0; i < dps.getCount(); ++i) {
      DataProvider dp = (DataProvider) dps.getItem(i);
      dataSources.add(dp.getDataSource());
   }
   for (DataSource ds: dataSources) {
      String universeId = ds.getUniverseID();
      String oldID = universeId;
      String newID = mapping.get(oldID);
      System.out.println(oldID + "->" + newID);
      dps.changeUniverse(oldID, newID, true);
      if (dps.mustFillChangeUniverseMapping()) {
         ChangeUniverseMapping unvMapping = dps.getChangeUniverseMapping();
         ChangeDataSourceMapping[] dsMappings = unvMapping.getDataSourceMappings();
         for (ChangeDataSourceMapping dsMapping : dsMappings) {
            ChangeDataSourceObjectMapping[] objMappings = dsMapping.getAllMappings();
            for (ChangeDataSourceObjectMapping objMapping : objMappings) {
               if (objMapping.getToObject() == null) {
                  failed = true;
               }
            }
         }
         dps.setChangeUniverseMapping();
         if (widoc.getMustFillContexts()) {
            failed = true;
         }
         widoc.applyFormat();
         widoc.refresh();
      }
      if (failed) {
         return false;
      }
   }
   return true;
}

BTW, the universe id is something like:

UnivCUID=ASiM_T4jxmJIj0aKWpbeXro;UnivID=41709;ShortName=Finance;UnivName=Finance

Complete code

https://bukhantsov.org/tools/WidRemapping.zip

How to add variable using BO RE Java SDK

I got an interesting task – add variable VERSION specifying the service pack to about 50 webi documents. I had to invent something more clever then going through all them manually.

The following function can be used to add a dimension variable with name name and value value to webi document widoc.

public static boolean addReplaceVariable(DocumentInstance widoc,
                                              String name,
                                              String value)
{
   ReportDictionary dic = widoc.getDictionary();
   VariableExpression[] variables = dic.getVariables();
   boolean found = false;
   for (VariableExpression e : variables) {
      if (e.getName().equalsIgnoreCase(name)) {
         System.out.println("variable " + name
             + " expression " + e.getFormula().getValue()
             + " was replaced with " + value);
         e.setValue(value);
         found = true;
         break;
      }
   }
   if (!found) {
      try  {
         dic.createVariable(name, ObjectQualification.DIMENSION, value);
         System.out.println("variable " + name
                          + " with value " +  value
                          + " has been created");
      } catch (Exception e) {
         System.out.println("ERROR: the variable " + name + " cannot be created");
         return false;
      }
   }
   return true;
}

It can be executed

if (addReplaceVariable(widoc, "VERSION", "=\"12.00.18.00\"")) {
   widoc.save();
}

More information

Getting started with BO RE Java SDK

Purging data provider queries using BO RE Java SDK

Before copying webi documents from test to production environment it might be useful to clean up document queries.

The following function

  • purges data providers queries,
  • removes saved prompt values, and
  • regenerates queries.
public static void purgeQueries(DocumentInstance widoc) {
   DataProviders dps = widoc.getDataProviders();
   for (int i = 0; i < dps.getCount(); ++i) {
      DataProvider dp = (DataProvider)dps.getItem(i);
      if (dp instanceof SQLDataProvider) {
         System.out.println("Data provider: " + dp.getName());
         SQLDataProvider sdp = (SQLDataProvider)dp;
         sdp.purge(true); // true means purge prompt values
         sdp.generateQuery();
         sdp.resetSQL();
      }
   }
}

The code is very simple but I use this functionality most often.

More Information

Getting started with BO RE Java SDK
Package com.businessobjects.rebean.wi.*

Universe Documenter – Some Best Practices

Beside the straightforward use of the Universe Documenter for documenting list of objects, tables etc, it can help developer to speedup some verification tasks.

1. Some guys do not believe in automatic context detection and create contexts manually. In my experience if the database schema is designed properly and join cardinalities are set properly, automatic context detection works perfect. However when you are creating the first draft of the universe, cardinalities of some joins might be not set. In this case automatic context detection will prompt a warning “All Cardinalities are not set. The detection can be wrong or incomplete because of the unknown cardinalities “.

If the schema is complex, it might be difficult to see the join, and a solution is to go through all joins in List Mode and check that all join cardinalities are set. The other option is to run Universe Documenter, and check the column “Outer Join” on the worksheet “Joins” for value “Unknown”. This will indicate the wrong join.

2. You can define a custom tables for an object to force a join. This might be useful for example for performance optimization. The problem with this feature is that the tables are reset if you change anything in the object expression (even if this is just a space). If you have a lot of such objects it might be really difficult task to verify all them. Verification of each object requires several mouse clicks. It is too easy to miss an object. An option is to build a list of objects and check column “Tables” on the worksheet “Objects”.

3. TBW

How to diff universes using Universe Documenter

I have added a new feature to the tool Universe Documenter which allows to find differences between universes. I will describe on an example.

Let’s open Island Resorts Marketing universe and make some changes: remove table Age_group and object Age group, and save the universe with a different name.
Universe Documenter - Diff Example - Universe

Now we will start the tool, open the modified and original universes, select the option Diff in Post processing, and click Quick View.
Universe Documenter - Diff Example - Dialog

In the Excel spreadsheet, you will see the information from both universes with the differences marked in yellow.

If you built the Excel for two universes one of which is the copy of another, there should be two rows for each object (condition, join etc) with the same values. If universes are different, e.g. there is additional object in one of them, there will be a corresponding row for this object in the Excel which does not have corresponding row from the other universe and such this row will be marked.

We removed table and therefore we removed corresponding join. This is shown in the Excel spreadsheet:

Universe Documenter - Diff Example - Result

If for example an object was changed in the copy, e.g. the name or type were changed then both corresponding rows are marked. You can further sort rows in Excel to find what exactly changed.

Universe Documenter

The tool exports BusinessObjects universe metadata into Excel file including information about objects, predefined conditions, tables, joins, contexts, index awareness and incompatibilities.

Requirements

  • Microsoft .Net Framework 3.5
  • BusinessObjects XI 3.1 SP3
  • Microsoft Office 2007 or OpenOffice 3.0

Installation

The tool is provided and supported by biclever.com.

The tool is build using Express version of Visual Studio, therefore it does not have a normal installer. Maybe I will do something about this later.

How to use

  • Start the tool  UnvDoc.exe as Administrator
  • Login to BOE system. If you cancel login, the tool will run in standalone mode.
  • Open universes from the disk or import from CMS.
  • Select output options. Do not check “List of values details” unless you need it – extraction of this information is very slow.
  • Save result to a specific file or click Quick View to get the result in Excel. ( Example of the result)

More Information

How to diff universes using Universe Documenter

Best practices of using Universe Documenter

List of output Excel columns

Objects
Universe Name
Universe Full Name
Class Path
Class Id
Class Name
Object Id
Object Name
Object Type
Object Format
Object Description
Object Show
Object Select
Object Where
Tables
Object Qualification
Measure Projection
Associated Object
Object Has LoV
LoV Allow Edit
LoV Automatic Refresh
LoV Hierarchical
LoV Export With Universe
LoV Delegate Search
LoV Name
LoV Is Custom SQL
LoV SQL
Can Be Used In Condition
Can Be Used Result
Can Be Used Sort
Security Access Level
Database Format

Classes
Universe Name
Universe Full Name
Class Path
Class Id
Class Name
Class Description
Class Show
Parent Class

Conditions
Universe Name
Universe Full Name
Class Path
Class Id
Class Name
Condition Id
Condition Name
Condition Description
Condition Show
Condition Where
Tables
Mandatory Condition
Apply On LoV

Hierarchies
Universe Name
Universe Full Name
Hierarcy Id
Hierarchy Name
Object Id
Object Name

Tables
Universe Name
Universe Full Name
Table Id
Table Name
Alias
Is Derived
Derived SQL

Table Columns
Universe Name
Universe Full Name
Table Id
Table Name
Column Name

Joins
Universe Name
Universe Full Name
Join Id
Left Table
Right Table
Outer Join
Short Cut
Expression

Contexts
Universe Name
Universe Full Name
Context Name
Context Description
Join Id
Left Table
Right Table

Index Awareness
Universe Name
Universe Full Name
Class Path
Class Name
Object Name
Type
Select
Where
Enable

Incompatibilities
Universe Name
Universe Full Name
Table
Type
Object Id
Object Name

Regular backup of BOE

Sometimes the only thing people do to backup BusinessObjects Enterprise server data is to backup CMS database. Unfortunately CMS database does not contain universes, documents and other stuff, it has only metadata about them (ids, descriptions etc). Backup of CMS database is not enough to restore the system from the scratch. Complete BIAR is often sufficient to restore the server.

The complete BIAR can be build from Import Wizard or using BIAR command line tool (biarengine.jar). The purpose of the command line tool is to automate importing and exporting of BIARs.

Simplest solution (example)

1. Create file export.properties in D:\Backup on the server with the following content:

action = exportXML
exportBiarLocation = complete.biar
userName = Administrator
password =
authentication = secEnterprise
CMS = localhost
exportDependencies = true
includeSecurity = true
exportQueriesTotal = 3
exportQuery1 = select * from CI_INFOOBJECTS
exportQuery2 = select * from CI_SYSTEMOBJECTS
exportQuery3 = select * from CI_APPOBJECTS

2. Create batch D:\Backup\backupBOE.bat executing the BIAR command line tool with the properties file.

java -jar "D:\Business Objects\common\4.0\java\lib\biarengine.jar" export.properties

3. Schedule the backupBOE.bat to run regularly in Windows scheduler.

Note that to import the BIAR you will have to use biarengine.jar and not Import Wizard. Import and export of BIAR files is not supported across tools. However it usually works if you export and import only universes and documents. I.e. when export.properties is:

action = exportXML
exportBiarLocation = complete.biar
userName = Administrator
password =
authentication = secEnterprise
CMS = localhost
exportDependencies = true
includeSecurity = true
exportQueriesTotal = 2 
exportQuery1 = select * from CI_INFOOBJECTS 
exportQuery2 = select * from CI_APPOBJECTS

Further information

+0 does matter in Web intelligence

In university I learned that adding zero does matter sometimes. However I did not expect to see this in Web Intelligence.

The fact is that the following two expressions are not the equal:

=(Average([Revenue])) In ([Year])
=(Average([Revenue])+0) In ([Year])

The query:

The result:

So the expression (Average([Revenue])+0) In ([Year]) is not equal to (Average([Revenue])) In ([Year]).  But it is equal to: Average([Revenue] In ([Year];[Quarter];[Month])) In ([Year]).

The funny thing this that this is a normal behavior, and there is explanation for this (provided by SAP):

The output context of the aggregation is [Year] in both cases, however the input context of the aggregation is different. In first expression the input is Body ([Year], [Quarter]), however in the second expression the input is the detail context of the [Year], [Quarter] and [Month].

Getting started with BusinessObjects Java SDK

BusinessObjects Report Engine Java SDK is primarily used for Web Intelligence customization. This post describes how to start development of a command line tool. Such tools can make life of report developers easier. They can be used for:

You will need:

  • A bit of programming experience
  • Eclipse IDE for Java Developers (http://www.eclipse.org/downloads/)
  • BusinessObjects Enterprise XI 3.1 server (to connect to)
  • BusinessObjects SDK libraries (see the list below)

New project in Eclipse

Download and extract Eclipse. Start it. Select default workspace folder (the new projects will be created in this folder). On the welcome page click “Go to Workbench”.

Create a new project:

1. File>New>Java Project

2. Specify project name (e.g. JavaTool).

3. Click Finish.

4. In the project folder on the disk (e.g. C:\Users\dbu\workspace\JavaTool\), create a folder lib and copy the jar files into it.

5. In Eclipse: Project>Properties>Java Build Path>Libraries, click “Add External JARs…”, OK.

6. Create package in the project. File>New>Package, type a name (e.g. org.bukhantsov.javatool), and click OK.

7. Create new class which will be starting point of the application. File>New>Class, type a name (e.g. Program), select option “public static void main” and click OK.

The generated class will be something like this:

package org.bukhantsov.javatool;
public class Program {
   /** 
   * @param args 
   */
   public static void main(String[] args) {
      // TODO Auto-generated method stub
   }
}

Let’s start

The first program will print all variables defined in Web Intelligence documents from a BOE server folder. Let’s consider functional blocks of the application.

Connect to CMS

The first thing you have to do is to connect to the BOE server.

ISessionMgr sessionMgr = CrystalEnterprise.getSessionMgr();
IEnterpriseSession enterpriseSession =
  sessionMgr.logon("Administrator", "", "localhost", "secEnterprise");

Replace “localhost” with the name of your BOE server.

Get Webi documents from CMS

When you connected, you can get the objects corresponding to Webi documents from CMS.

IInfoStore infoStore = (IInfoStore) enterpriseSession.getService("InfoStore");
String query = "select SI_NAME, SI_ID from CI_INFOOBJECTS "
             + "where SI_KIND = 'Webi' and SI_INSTANCE=0";
IInfoObjects infoObjects = (IInfoObjects) infoStore.query(query);

You can build and test the query in BusinessObjects Query Builder.

Get report engine proxy

To open Webi document, you need to get a proxy to Webi report engine web service.

ReportEngines reportEngines =
   (ReportEngines) enterpriseSession.getService("ReportEngines");
ReportEngine wiRepEngine =
   (ReportEngine) reportEngines.getService(
      ReportEngines.ReportEngineType.WI_REPORT_ENGINE);

Process Webi documents from a folder

In a loop you can process all Webi documents from a folder

for (Object object : infoObjects) {
   IInfoObject infoObject = (IInfoObject) object;
   String path = getInfoObjectPath(infoObject);
   if (path.startsWith("/")) {
      DocumentInstance widoc = wiRepEngine.openDocument(infoObject.getID());
      // process document
      widoc.closeDocument();
   }
}

The function getInfoObjectPath builds path to the Webi document. Parent of Webi document is folder, and parent of folder is folder. The root folder has id = 0.

public static String getInfoObjectPath(IInfoObject infoObject) throws SDKException {
   String path = "";
   while (infoObject.getParentID() != 0) {
      infoObject = infoObject.getParent();
      path = "/" + infoObject.getTitle() + path;
   }
   return path;
}

Print Webi document variables

ReportDictionary dic = widoc.getDictionary();
VariableExpression[] variables = dic.getVariables();
for (VariableExpression e : variables) {
   String name = e.getFormulaLanguageID();
   String expression = e.getFormula().getValue();
   System.out.println(" " + name + " " + expression);
}

Error handling

An important part of each program is error handling.

public static void main(String[] args) {
   IEnterpriseSession enterpriseSession = null;
   ReportEngines reportEngines = null;
   try {
      // * connect to CMS
      // * get report engine proxy
      // * get Webi documents from CMS 
      // * process the documents
   }
   catch (SDKException ex) {
      ex.printStackTrace();
   }
   finally {
      if (reportEngines != null) reportEngines.close();
      if (enterpriseSession != null) enterpriseSession.logoff();
   }
}

Put all together

The complete code can be downloaded from here (however without libs). You can import it from File menu: File > Import… > Existing Project into Workspace.

package org.bukhantsov.javatool;

import com.businessobjects.rebean.wi.DocumentInstance;
import com.businessobjects.rebean.wi.ReportDictionary;
import com.businessobjects.rebean.wi.ReportEngine;
import com.businessobjects.rebean.wi.ReportEngines;
import com.businessobjects.rebean.wi.VariableExpression;
import com.crystaldecisions.sdk.exception.SDKException;
import com.crystaldecisions.sdk.framework.CrystalEnterprise;
import com.crystaldecisions.sdk.framework.IEnterpriseSession;
import com.crystaldecisions.sdk.framework.ISessionMgr;
import com.crystaldecisions.sdk.occa.infostore.IInfoObject;
import com.crystaldecisions.sdk.occa.infostore.IInfoObjects;
import com.crystaldecisions.sdk.occa.infostore.IInfoStore;

public class Program {
   public static void main(String[] args) {
      IEnterpriseSession enterpriseSession = null;
      ReportEngines reportEngines = null;
      try {
         System.out.println("Connecting...");
         ISessionMgr sessionMgr = CrystalEnterprise.getSessionMgr();
         enterpriseSession = sessionMgr.logon("Administrator",
               "", "localhost", "secEnterprise");
         reportEngines = (ReportEngines) enterpriseSession
               .getService("ReportEngines");
         ReportEngine wiRepEngine = (ReportEngine) reportEngines
               .getService(ReportEngines.ReportEngineType.WI_REPORT_ENGINE);         

         IInfoStore infoStore =
               (IInfoStore) enterpriseSession.getService("InfoStore");
         String query = "select SI_NAME, SI_ID from CI_INFOOBJECTS "
                      + "where SI_KIND = 'Webi' and SI_INSTANCE=0";
         IInfoObjects infoObjects = (IInfoObjects) infoStore.query(query);
         for (Object object : infoObjects) {
            IInfoObject infoObject = (IInfoObject) object;
            String path = getInfoObjectPath(infoObject);
            if (path.startsWith("/")) {
               DocumentInstance widoc = wiRepEngine.openDocument(infoObject.getID());
               String doc = infoObject.getTitle();
               System.out.println(path + "/" + doc);               
               printDocumentVariables(widoc);
               widoc.closeDocument();
            }
         }
      }
      catch (SDKException ex) {
         ex.printStackTrace();
      }
      finally {
         if (reportEngines != null)
            reportEngines.close();
         if (enterpriseSession != null)
            enterpriseSession.logoff();
      }
      System.out.println("Finished!");
   }

   public static void printDocumentVariables(DocumentInstance widoc ) {
      ReportDictionary dic = widoc.getDictionary();
      VariableExpression[] variables = dic.getVariables();
      for (VariableExpression e : variables) {
         String name = e.getFormulaLanguageID();
         String expression = e.getFormula().getValue();
         System.out.println(" " + name + " " + expression);
      }
   }        

   public static String getInfoObjectPath(IInfoObject infoObject) 
                                        throws SDKException {
      String path = "";
      while (infoObject.getParentID() != 0) {
         infoObject = infoObject.getParent();
         path = "/" + infoObject.getTitle() + path;
      }
      return path;
   }
}

Compile and run

You can run the program Run>Run.

Getting started with BusinessObjects RE Java SDK

To build executable JAR: go File>Export, select Java>Runnable JAR file. Select launch configuration (you will probably have the only one), select destination, select “Package required libraries into generated JAR”, and click Finish.

You can run the program using the following command:

java -jar javatool.jar

Final notes

Before running your tool on a bunch of reports it should be carefully tested. Especially if you do modifications.

The purpose of the code was to demonstrate how to access report engine. It does not demonstrate the best programming practices.

Java SDK Libraries

The Java SDK libraries can be found in the installation folder with BusinessObjects client tools or on the server.

C:\Program Files (x86)\Business Objects\common\4.0\java\lib

Required libraries:

  boconfig.jar
  cecore.jar
  celib.jar
  cesdk.jar
  cesession.jar
  corbaidl.jar
  ebus405.jar
  jtools.jar
  logging.jar
  rebean.common.jar
  rebean.jar
  rebean.wi.jar
  wilog.jar
  xpp3.jar
  xpp3_min.jar
  SL_plugins.jar

Links

Webi Report Engine Documentation

How to determine BusinessObjects service pack and fix pack

Method 1. Software Inventory Tool

The best way to determine the current version is through Software Inventory Tool. It has complete history of your BOE updates.

Method 2. CMC Settings

If you don’t have access to the server with the BOE, you can check the metrics of BusinessObjects servers.

Open CMC, go to Settings. In the properties, you will find the Product Version. Lookup BOE SP/FP using the reference table below.

Method 3. BO Executable Version

If you have access to file system of the server, you may find the following method to be the quickest.

Browse to the folder with BO installation. For example:

C:\Program Files\Business Objects\BusinessObjects Enterprise 12.0\win32_86

Right-click the busobj.exe file, click Properties, on the the Version tab. Lookup BOE SP/FP using the reference table below.

Reference

Continue reading