I. Introduction

Depuis la version XI de BO, l'accès au référentiel (stocké base de données) de BO est crypté et de ce fait, on ne peut plus y accéder pour en extraire les métadonnées :

  • Liste des classes et objets de l'univers
  • Propriétés de chaque objet (source SQL, dimension, etc.)


Faire ces listes permettait de faire des comparaisons entre univers (exemple, entre une version de développement et une version de production), ou de lister les objets base de données utilisés par les univers (études d'impacts de modification des bases de données)

Pour pallier ce manque, il est possible d'utiliser le SDK de Designer.

Pour rappel, une définition de SDK (Software Developpement Kit) : kit de développement ou trousse de développement logiciel est un ensemble d'outils permettant aux développeurs de créer des applications de type défini (source wikipedia fr).

Business Objects met à disposition pour chacun des clients lourds (Desktop Intelligence, Designer) un modèle objet ou SDK. Nous étudierons dans ce document l'utilisation de ce SDK pour le module Designer avec l'interface de développement Excel + VBA.

La Version de BO concernée est XI R2, mais cela doit être transposable dans les versions plus récentes ou antérieures.

Nous étudierons deux applications concrètes d'utilisation du SDK :

  • retro engineering d'univers, export vers Excel


A partir d'un univers existant (déposé sur le disque, pas sur le référentiel de BO), nous allons déverser les informations les plus importantes de cet univers dans un fichier Excel (code SQL de chaque objet, type d'objets indicateurs ou dimension, tables de la base de données utilisées). Cet export Excel permet de faire des analyses d'impact, de la documentation technique. On peut également déterminer les colonnes de tables qui ne sont pas utilisées dans des objets de l'univers, en croisant la liste du SQL de chaque objet et la liste des tables/colonnes déposées dans l'univers.

  • création d'univers BO automatique à partir d'un fichier Excel


Le fichier Excel contient la liste des classes et objets BO, les tables et colonnes des bases de données associées. Par un programme VBA nous allons générer automatiquement l'univers, ce qui présente un intérêt dans certains cas : Designer nomme automatiquement les classes et objets BO à partir de leurs noms en base de données, noms qui sont souvent inadaptés pour une utilisation par un utilisateur « métier ». Il faut alors renommer chaque objet, ce qui est très fastidieux quand il y en a une centaine. Avec VBA, on peut donc directement associer le bon nom fonctionnel (issu d'un document métier par exemple). On peut également associer à chaque objet BO une définition fonctionnelle (qui peut être issue de Power AMC ou d'un référentiel entreprise).

II. Description du modèle objet BO XI Designer

II-A. Documentation officielle du SDK Designer

Le Universe Designer SDK est décrit (classes, propriétés et méthodes) à l'adresse suivante :

http://devlibrary.businessobjects.com/BusinessObjectsXIR2/en/devsuite.htm

Et le diagramme du modèle objet :

http://devlibrary.businessobjects.com/BusinessObjectsXIR2/en/en/BO_SDK/dessdk_com_doc/doc/dessdk_com_omd.pdf

Ces liens sont valides au 02/11/2009.

Tout ceci parait bien compliqué pour faire une « simple » retro engineering d'univers. Nous allons donc étudier par la suite les éléments clés du modèle objet de Designer pour arriver à nos fins.

II-B. Rappel de la fenêtre Designer

La fenêtre de l'application Designer a la configuration suivante :

designer


Sur la partie gauche, on trouve les classes, et sous les classes, on peut trouver d'autres classes ou des objets. Les classes servent à ranger les objets de manière cohérente pour l'utilisateur final (comme des dossiers). Les objets sont les données manipulées par les utilisateurs (dimensions, indicateurs.). A chaque objet on associe un équivalent SQL, le plus souvent un simple « mapping » d'une colonne d'une table d'une base de données. A droite, on retrouve l'ensemble des tables utilisées dans l'univers, ainsi que les jointures utilisées pour lier les tables. Les jointures peuvent être regroupées dans des contextes.

Les éléments que l'on trouve sur cette fenêtre vont être repris presque à l'identique dans le modèle objet ! (comme quoi ce n'est pas si compliqué.)

  • Les classes,
  • Les objets et leurs propriétés (indicateur ou dimension, sql associé.),
  • Tables utilisées,
  • Colonnes des tables utilisées,
  • Jointures,
  • Contextes.

II-C. Desription simple du modèle objet Designer

Les manipulations suivantes sont possibles uniquement si Excel et BO XI Designer sont installés sur le poste.

Tout d'abord, ouvrir l'éditeur VBA intégré à Excel (Alt + F11). Puis insérer un module dans notre fenêtre VBA : menu « Insertion - Module ». Il faut enfin référencer la bibliothèque (dll) contenant le modèle objet (les objets, leurs propriétés et méthodes) de Designer via le menu "Outils - Références" :

image


Dans le code, on appellera les bibliothèques Designer avec l'instanciation de l'objet « univers BO » :

Dim objBO as New Designer.Application

Enfin, pour naviguer plus facilement dans les objets, leurs méthodes et propriétés, afficher l'explorateur d'objet (F2), et choisir Designer : en sélectionnant l'objet tables (qui est en fait une collection), nous remarquons que cet objet contient des propriétés (Item, Count) et des méthodes (Add.).

Cela est vrai pour tous les objets clés du SDK :

  • La collection Classes contient tous les objets Classe
  • La collection Objects contient tous les objets Object,
  • La collection Tables contient tous les objets Table,
  • La collection Columns contient tous les objets Column,
  • La collection Joins contient tous les objets Join
  • La collection Contexts contient tous les objets Context

II-C-1. Collection Tables

image

Pour le vocabulaire « objet » (objet, méthode, collection « Tables » surlignée ; elle représente l'ensemble des tables déposées dans l'univers.

La propriété Count de la collection Tables nous propriétés, collections) vous trouverez des cours spécialisés, mais nous pouvons expliquer simplement les notions de base au travers de l'exemple ci-dessus.

A gauche de la fenêtre, nous trouvons les classes (une classe est la gestion de l'objet : sa création, l'affectation de ses propriétés, et ses fonctions ou méthodes), et à droite, les propriétés et méthodes.

  • Sur la copie d'écran ci-dessus, nous voyons la renvoie le nombre de tables de la base de données utilisées dans l'univers.
  • La méthode Add nous permet (en passant le nom en paramètre) d'ajouter une table dans l'univers (et l'on devine dès maintenant que l'on peut construire un univers dynamiquement !)


En balayant la collection à l'aide de l'instruction For Each . Next, nous lirons chaque table utilisée dans l'univers, et cette instruction renvoie pas à pas un objet « Table », dont voici la classe ci-dessous :

image

Nous remarquons ici que l'élément Table de la collection Tables contient lui-même une collection Columns, ce qui est tout à fait logique !

II-C-2. Collection Columns

image

La collection Columns possède également la méthode Add (comme toutes les collections en fait).

image


Pour chaque colonne, nous trouvons des propriétés « classiques » comme Key (clé ou non), Name, etc.

II-C-3. Collection Classes

image
image


On retrouve ici le principe de la récursivité des « Classes » BO, qui sont des répertoires : un répertoire peut contenir des sous-répertoires, donc un objet Class peut contenir à son tour une collection Classes représentant ses sous-classes.

II-C-4. Collection Objects

image
image


Les propriétés d'un objet sont nombreuses. On retrouve en fait la multiplicité des options disponibles dans la fenêtre propriétés d'un objet. Une propriété importante est , car c'est l'aide en ligne de l'utilisateur, la description fonctionnelle de chaque objet. Il peut être utile de mettre à jour ces Description par code VBA, à partir d'un référentiel entreprise de documentation (Power AMC par exemple). De même, la propriété Name (le nom en clair de l'objet) peut être mis à jour massivement avec du code VBA, car par défaut, le Name d'un objet est le nom SQL du champ associé, ce qui n'est pas très pratique pour l'utilisateur !

III. Programme d'export d'univers BO vers Excel

Le code présenté dans cet exemple est du VBA pour Excel, mais écrit de manière la plus simple possible :

  • pas de déclaration de variables mis à part les objets BO (VBA sait s'en débrouiller pour un code simple),
  • peu d'objets Excel utilisés,
  • pas de gestion des erreurs.


Ce code est suffisamment documenté pour une compréhension générale.

Rappel indispensable sous l'éditeur VBA : F8 pour exécuter le programme en mode pas à pas, clic-droit sur une variable et « ajouter un espion » pour connaître les valeurs des variables en cours d'exécution.

 
Sélectionnez

Sub EXPORT_UNIVERS()

'Initialisation de la feuille Liste_BO
Sheets("liste_BO").Select
Cells.ClearContents
Cells(1, 1).Value = "classe"
Cells(1, 2).Value = "sous_classe"
Cells(1, 3).Value = "objet"
Cells(1, 4).Value = "sql"
Cells(1, 5).Value = "type"
Cells(1, 6).Value = "qualification"
ligne = 2

'Ouvre Business Object et l'univers choisi
filtre = "Univers (*.unv),*.unv"
nomFichier = Application.GetOpenFilename(filtre)
If nomFichier = False Then
    GoTo fin
End If
Dim objBO As New Designer.Application
objBO.Visible = True
On Error Resume Next
    objBO.Logon "", "", False, enterprise
If Err.Description <> "" Then
    MsgBox ("Anomalie de login Designer...")
    Set objBO = Nothing
    GoTo fin
End If
Set UniversBO = objBO.Universes.Open(nomFichier)

'On balaie les classes
'ATTENTION !! une profondeur de 2 niveaux (classe et sous-classe) est codée. Si plus de profondeur, adapter le code (ou utiliser des fonctions récursives)
For Each Classe In UniversBO.Classes
    nom_classe = Classe.Name
    nom_sous_classe = ""
    For Each objet In Classe.Objects
        description_univers ligne, nom_classe, nom_sous_classe, objet
        ligne = ligne + 1
    Next
    For Each sous_classe In Classe.Classes
        nom_sous_classe = sous_classe.Name
        For Each objet In sous_classe.Objects
            description_univers ligne, nom_classe, nom_sous_classe, objet
            ligne = ligne + 1
        Next
    Next
Next

'On balaie les tables et colonnes des tables de l'univers pour en faire la liste
Sheets("liste_table").Select
Cells.ClearContents
Cells(1, 1).Value = "table"
Cells(1, 2).Value = "colonne"
ligne = 2

UniversBO.RefreshStructure
For Each Table In UniversBO.Tables
    tablename = Table.Name
    For Each Column In Table.Columns
        Cells(ligne, 1).Value = tablename
        Cells(ligne, 2).Value = Column.Name
        ligne = ligne + 1
    Next
Next

'On balaie les jointures et contextes pour en faire la liste
Sheets("liste_jointures").Select
Cells.ClearContents
Cells(1, 1).Value = "table source"
Cells(1, 2).Value = "table cible"
Cells(1, 3).Value = "expression"
ligne = 2

For Each Item In UniversBO.Joins
    Cells(ligne, 1).Value = Item.FirstTable
    Cells(ligne, 2).Value = Item.SecondTable
    Cells(ligne, 3).Value = Item.Expression
    ligne = ligne + 1
Next


Set UniversBO = Nothing
Set objBO = Nothing
Beep
MsgBox ("L'export est terminé.")
fin:

End Sub
_______________________________________________________________________

Function description_univers(ligne, nom_classe, nom_sous_classe, objet)
Cells(ligne, 1).Value = nom_classe
Cells(ligne, 2).Value = nom_sous_classe
Cells(ligne, 3).Value = objet.Name
Cells(ligne, 4).Value = objet.Select
Select Case objet.Type
    Case dsDateObject '(3) date
        Cells(ligne, 5).Value = "date"
    Case dsNumericObject '(1) numérique
        Cells(ligne, 5).Value = "numerique"
    Case dsCharacterObject '(2) alphanum
        Cells(ligne, 5).Value = "alphanumérique"
    Case dsBlobObject '(4) texte long
        Cells(ligne, 5).Value = "texte"
    Case Else
        Cells(ligne, 5).Value = "inconnu"
End Select
Select Case objet.Qualification
    Case dsDimensionObject '(1) dimension
        Cells(ligne, 6).Value = "dimension"
    Case dsDetailObject '(2) information
        Cells(ligne, 6).Value = "information"
    Case dsMeasureObject '(3) indicateur
        Cells(ligne, 6).Value = "indicateur"
    Case Else
        Cells(ligne, 6).Value = "inconnu"
End Select
End Function

IV. Programme de création automatique d'univers

Il ne faut pas espérer faire l'univers entièrement, il faudra bien sûr l'affiner par la suite. Ce programme permet toutefois d'initialiser un (ou plusieurs) univers à partir d'informations externes (dans notre cas une feuille Excel) et ainsi d'avoir les noms en clair, des définitions d'objets, etc.

Vous trouverez une vidéo d'exemple de création automatique d'univers ici :

http://excel-methode.blogspot.com/2009/08/creer-un-univers-business-objects.html

 
Sélectionnez
Sub GENERATION_UNIVERS()

'Ouvre Business Object et crée un univers vide
Dim objBO As New Designer.Application
objBO.Visible = True
objBO.Logon "logon", "password", False, enterprise
Set UniversBO = objBO.Universes.Add()

'ETAPE 1 : ON CREE TABLES ET COLONNES
Sheets("tables").Select
ligne = 2
Do While Cells(ligne, 3).Value <> ""
'test ajout table
    If Cells(ligne - 1, 3).Value <> Cells(ligne, 3).Value Then
        nom_table = Cells(ligne, 3).Value
        Set table1 = UniversBO.Tables.Add(nom_table)
    End If
'ajout colonnes
    nom_colonne = Cells(ligne, 5).Value
    table1.Columns.Add nom_colonne
'destruction objet table
    If Cells(ligne, 3).Value <> Cells(ligne + 1, 3).Value Then
        Set table1 = Nothing
    End If
    ligne = ligne + 1
Loop
UniversBO.ArrangeTables

'ETAPE 2 : ON CREE CLASSES ET SOUS-CLASSES
Sheets("tables").Select
ligne = 2
Do While Cells(ligne, 1).Value <> ""
'test ajout classe
    If Cells(ligne - 1, 1).Value <> Cells(ligne, 1).Value Then
        nom_classe = Cells(ligne, 1).Value
        Set classe1 = UniversBO.Classes.Add(nom_classe)
    End If
'test ajout sous-classe
    nom_sous_classe = Cells(ligne, 2).Value
    If nom_sous_classe <> "" Then
        If Cells(ligne - 1, 2).Value <> Cells(ligne, 2).Value Then
            Set sous_classe1 = classe1.Classes.Add(nom_sous_classe)
        End If
    End If
'affectation de la colonne à la classe / sous-classe
    nom_objet = Cells(ligne, 6).Value
    If nom_sous_classe = "" Then
        Set Object1 = classe1.Objects.Add(nom_objet)
    Else
        Set Object1 = sous_classe1.Objects.Add(nom_objet)
    End If
    Object1.Select = Cells(ligne, 3).Value & "." & Cells(ligne, 5).Value
    texte1 = "Table : " & Cells(ligne, 3).Value & _
                          ". Colonne : " & Cells(ligne, 5).Value
    If Cells(ligne, 8).Value <> "" Then
        texte1 = texte1 & ". " & Cells(ligne, 8).Value
    End If
    Object1.Description = texte1
'affectation du type
'1 : numérique (dsNumericObject)
'2 : alphanumérique (dsCharacterObject)
'3 : date (dsDateObject)
'4 : texte long (dsBlobObject)
    Object1.Type = 2
    format_source = Cells(ligne, 9).Value
    mode_aggreg = Cells(ligne, 10).Value
    If format_source = "DATE" Then
        Object1.Type = 3
    End If
    If Left(format_source, 6) = "NUMBER" Then 'Adapter selon la saisie Excel
        Object1.Type = 1
    End If
    If format_source = "SMALLINT" Then 'Adapter selon la saisie Excel
        Object1.Type = 1
    End If
    If format_source = "INTEGER" Then 'Adapter selon la saisie Excel
        Object1.Type = 1
    End If
    If mode_aggreg = "somme" Or mode_aggreg = "moyenne" Then
        Object1.Type = 1
    End If
'Affectation de la qualification
'1 : dimension (dsDimensionObject)
'2 : information (dsDetailObject)
'3 : indicateur (dsMeasureObject)
    type_source = Cells(ligne, 7).Value
    If type_source = "dimension" Then
        Object1.Qualification = 1
    End If
    If type_source = "indicateur" Then
        Object1.Qualification = 3
    End If
'Affectation de la fonction d'aggregation
'1 : Somme
'4 : Moyenne
    aggregat = Cells(ligne, 10).Value
    If aggregat = "somme" Then
        Object1.AggregateFunction = 1
    End If
    If aggregat = "moyenne" Then
        Object1.AggregateFunction = 4
    End If
'destruction objet sous-classe
    If Cells(ligne, 2).Value <> "" Then
        If Cells(ligne, 2).Value <> Cells(ligne + 1, 2).Value Then
            Set sous_classe1 = Nothing
        End If
    End If
'destruction objet classe
    If Cells(ligne, 1).Value <> Cells(ligne + 1, 1).Value Then
        Set classe1 = Nothing
    End If
    ligne = ligne + 1
Loop

'ETAPE 3 : ON AJOUTE LES JOINTURES
Sheets("jointures").Select
ligne = 2
Do While Cells(ligne, 1).Value <> ""
    jointure = Cells(ligne, 3).Value
    UniversBO.Joins.Add jointure
    ligne = ligne + 1
Loop
UniversBO.ArrangeTables

'ETAPE 4 : ON AJOUTE LES CONTEXTES
'Attention, on trie par contexte pour ne créer qu'une seule fois le contexte (sinon, erreur)
Sheets("jointures").Select
ActiveSheet.UsedRange.Sort Key1:=Cells(1, 4)
ligne = 2
Do While Cells(ligne, 1).Value <> ""
    jointure = Cells(ligne, 3).Value
    contexte = Cells(ligne, 4).Value
'test ajout contexte
    If contexte <> Cells(ligne - 1, 4).Value Then
        Set Contexte1 = UniversBO.Contexts.Add(contexte)
    End If
    Contexte1.Joins.Add jointure
'destruction objet contexte
    If contexte <> Cells(ligne + 1, 4).Value Then
        Set Contexte1 = Nothing
    End If
    ligne = ligne + 1
Loop

UniversBO.ArrangeTables
UniversBO.LongName = "NOM LONG"
UniversBO.Description = "DESCRIPTION A SAISIR"

Set UniversBO = Nothing
Set objBO = Nothing

MsgBox ("ajouter la connexion, nommer l'univers et enregistrer")

End Sub

V. Conclusion

Les exemples proposés dans ce tutoriel n'ont pas vocation à se substituer à l'expertise du logiciel BO Designer, mais toutefois, la manipulation du modèle objet BO Designer permet d'automatiser des tâches parfois pénibles sous l'outil (renommer les objets un par un avec des noms fonctionnels, analyses d'impacts.).

Utiliser le SDK BO Designer est pour finir un excellent moyen de contourner un des problèmes récurrents avec la version XI, la non-accessibilité du référentiel BO.