Home > Services

UI Services

A UI Service (User Interface Service) is a HTTP resource, generally a JSP or a Java Servlet, that is integrated into webMethods Master Data Manager. It gives the opportunity to offer specific and advanced functionalities to the user.

The JSP or the Java Servlet application must be UTF-8 encoded because it is included in the Manager page which is itself UTF-8 encoded .

There are two kind of UI Services:

UI Services on adaptations

Such services are executed in the context of an adaptation instance (under the tab "Services"), of a table (under the menu "Actions"), of an occurrence (at the top of the pane).

Typical use cases

  • Update a table, or a user selection of table occurrences (for example, adjust the product price column by applying the ratio specified by the user).
  • Import data from an external source into the current adaptation instance.
  • Export the occurrences selected in a table.
  • Implement specific events of a "MDM entity" life-cycle (for example, a product creation impacts several tables or a product is "closed" at a date specified by the user).
  • Display some statistics on a table.
  • etc.

Implementation

A UI Service is added in two steps:

  1. Declare your UI Service in the adaptation model. See Schema Definition.
    Note that the schema must be packaged in a module.
  2. Implement your service by using JSP or Servlet API. The code will use com.softwareag.mdm.service.ServiceContext API class. JavaDoc

You may check out an Import/Export implementation example in Tutorial.

Use of services within Manager

Once you've developed, deployed and declared a UI Service, users will access it in webMethods Master Data Manager using the button.


UI Services on branches or versions

A UI Service may be also executed on a branch. This Java/JSP/Servlet application has to be declared in a module (see configuration).
That means it is mandatory to have at least one module in addition to the product's ones.
The purpose of such services is to allow end-user to write high-level core business procedures by giving flexibility on the functions such as merge, import/export, validations, and so on.

Typical use cases

  • Import data from an external source.
  • Export data to multiple systems.
  • Validate a branch and version it before its export
  • Send messages to a monitoring system before a merge
  • etc.

Access to services

The services are accessed through the main menu on branch or on version:

Menu.

 

Entering this submenu shows all services declared on all modules.

Menu.

 

Configuration

Those UI services have to be declared in the configuration of a module.

The general advice here is to create a webapp dedicated to this services since they will be available on all branches but may have a life cycle dissociated from the data's one and the product's one.

The services are declared in the file module.xml as follows:

<?xml version="1.0encoding="UTF-8"?>
<module xmlns="urn:mdm-schemas:module_2.1xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
     xsi:schemaLocation="urn:mdm-schemas:module_2.1 http://schema.softwareag.com/module_2.1.xsd">
    <name>mdm-test</name>
    <publicPath>mdm-test</publicPath>
    <locales>
        <locale>fr_FR</locale>
    </locales>
    <services>
        <service name="Service1">
            <resourcePath>/pages/mdm-test.jsp</resourcePath>
            <type>branch</type>
            <documentation lang="fr-FR">
                <label>Merge filles sur parent</label>
                <description>Ce service merge toutes les filles sur la branche parente si elles sont valides
                </description>
            </documentation>
            <documentation lang="en-US">
                <label>Merge children on parent</label>
                <description>This service merge all children on parent branch after validation</description>
            </documentation>
        </service>
        <service name="Service2">
            <resourcePath>/pages/mdm-merge-validate.jsp</resourcePath>
            <type>branch</type>
            <documentation lang="fr-FR">
                <label>Merge/Valide/Export</label>
                <description>Merge la branche courante avec son parent puis valide ce parent et l'exporte.
                </description>
            </documentation>
            <documentation lang="en-US">
                <label>MergeValidate/export</label>
                <description>Merge current branch to parent if valid. Then validates parent and export it.
                </description>
            </documentation>
        </service>
        <service name="Fake1">
            <resourcePath>/pages/fake.jsp</resourcePath>
            <type>version</type>
            <documentation lang="fr-FR">
                <label>Service fake</label>
                <description>Ne fait rien mais le fait sur une version.</description>
            </documentation>
            <documentation lang="en-US">
                <label>Service fake</label>
                <description>Do nothing but do it on a version.</description>
            </documentation>
        </service>
        <service name="Fake2">
            <resourcePath>/pages/fake.jsp</resourcePath>
            <type>any</type>
            <documentation lang="fr-FR">
                <label>Service fake</label>
                <description>Ne fait rien mais le fait sur une version ou une branch.</description>
            </documentation>
            <documentation lang="en-US">
                <label>Service fake</label>
                <description>Do nothing but do it on a version or a branch.</description>
            </documentation>
        </service>
    </services>
</module>

With the following elements definitions:

Element Mandatory Definition
services Yes, if there are services Root element for services
service Yes, if there is one service One for each service
attribute::name Yes Name of the service. Must be unique into the scope of a module
resourcePath Yes Path leading to the service. Relative to the path of the webapp matching the module.
type Yes Allows to restrict the execution of the service. Possible values are : branch, version, any.
documentation No Label and description of the service. To have a user-fridenly way of listing the services in the Manager.
attribute::lang Yes Local for the current documentation block.
label No Short text describing the service.
description No Long text describing the service.

 

Samples

The following code is a sample of such service implementation. The service validates the current home then redirect the user to the merge interface. At the end of the interactive merge procedure, the user is redirect to a jsp which does some validation and then export the branch.

merge-validate.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ page language="java" contentType="text/html; charset=UTF-8"  pageEncoding="UTF-8"%> 
<%@ page import="com.softwareag.mdm.service.ServiceContext" %> 
<%@ page import="java.io.*"%>  
<%@ page import="java.util.*"%> 
<%@ page import="com.softwareag.mdm.adaptation.*"%>   
<%@ page import="com.softwareag.mdm.base.text.*"%>   
<%@ page import="com.softwareag.mdm.service.*"%>   
<%@ page import="com.softwareag.mdm.ui.*"%> 
<% 
    final ServiceContext sContext = ServiceContext.getServiceContext(request);  
%>  
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Test Jsp</title>
</head>
<body>
<%= sContext.getServiceLabel() %> : Merge children on current branche : 
<%= sContext.getCurrentHome().getLabelOrName(sContext.getLocale()) %>
<hr width="50%" align="left" />
<%
final AdaptationHome currentHome = sContext.getCurrentHome();
final AdaptationHome parentHome  = currentHome.getParentBranch();
request.getSession().setAttribute("parentHome", parentHome);
if (!currentHome.getValidationReportsMap(Severity.ERROR).isEmpty()) {
   out.write("The current home is not valid, you cannot proceed to the merge decisions");
   return;

String myURL = sContext.getURLForIncludingResource("/docs/sample2-end.jsp");
UIHttpManagerComponent httpComponent = UIHttpManagerComponent.createOnServiceContext(sContext);
httpComponent.selectHome(currentHome);
httpComponent.setService(ServiceKey.MERGE);
httpComponent.setRedirectionURI(myURL);
out.write("The current home is valid, you can proceed to the merge decisions<br />");
out.write("<a href=\""+httpComponent.getURIWithParameters()+"\">Next step</a>");
%>
</body>
</html>

merge-validate-end.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"  pageEncoding="UTF-8"%> 
<%@ page import="com.softwareag.mdm.service.ServiceContext" %> 
<%@ page import="java.io.*"%>  
<%@ page import="java.util.*"%> 
<%@ page import="com.softwareag.mdm.adaptation.*"%>   
<%@ page import="com.softwareag.mdm.base.text.*"%>   
<%@ page import="com.softwareag.mdm.service.*"%>   
<%@ page import="com.softwareag.mdm.ui.*"%> 
<%@ page import=" com.softwareag.mdm.instance.*" %>
<% 
    final ServiceContext sContext = ServiceContext.getServiceContext(request);  
%>  
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>MDM Test Jsp</title>
</head>
<body>
<%= sContext.getServiceLabel() %>
<hr width="50%" align="left" />

<%
    UIHttpManagerComponentReturnCode rc = UIHttpManagerComponentHelper.getReturnCodeFromHttpRequest(request);
    if (rc.isMergeCancelled()) {
        out.println("The procedure has been canceled:");
        return;
    }
    AdaptationHome parent = (AdaptationHome) request.getSession().getAttribute("parentHome"); 
    if (!parent.getValidationReportsMap(Severity.ERROR).isEmpty())
    {
        out.println(parent.getLabelOrName(sContext.getLocale()) + " is not valid, cannot export.<br />");
        return;
    }
        out.println(parent.getLabelOrName(sContext.getLocale()) + " is valid, continue.<br />");
        String versionName = ""+ System.currentTimeMillis();
        parent.getRepository().createHome(
        parent,
        HomeKey.forVersionName(versionName),
        sContext.getSession().getUserReference(),
        sContext.getSession(),
        UserMessage.createInfo("My label"),
        UserMessage.createInfo("My Description"));
        out.println("A version has been created : "+versionName+"<br />");
        final Archive archive = Archive.forFile(new File(parent.getLabelOrName(sContext.getLocale())+".mdm"));
        Procedure proc = new Procedure()  
        {  
             public void execute(ProcedureContext aContext) throws Exception  
             {  
                  aContext.doExportArchive(archive);         
             }
        };
        ProcedureResult result = sContext.execute(proc);  
        out.println("Archive done. "+archive.getLocationInfo());
%>

</body>
</html>

Access control

The usual permissions on branches and versions still apply there. Though, it is possible to add some business code to provide illegal access to the services by checking the context. Such code is the responsibility of the developper.

Massive updates

In case of a service which purpose is to update massively the repository, it won't be able to run into only one atomic transaction. Obviously the number of changes depends of the amount of memory available in your JVM but there always will be an edge to that amount.
So, it is possible to define the size of the commit by calling the method ProcedureContext.setCommitThreshold(int commitThreshold); which leads for example with a limit to 1000 updates within a transaction to :

Procedure procedure = new Procedure()
{
   public void execute(ProcedureContext aContext) throws Exception
   {
      aContext.setCommitThreshold(1000);
      aContext.setAllPrivileges(true);
      aContext.doImportArchive(specs);
   }
};
One must be carefull that, by activating a commit theshold, when a problem occurs all datas previously commited will remain in the database.

Services IU

Un Service IU (Service d'Interface Utilisateur) est une ressource HTTP, en général une JSP ou une servlet Java, qui est intégrée à l'outil webMethods Master Data Manager. Elle permet de fournir aux utilisateurs des fonctionnalités spécifiques et avancées.

L'application JSP or la Servlet Java doit être encodée en UTF-8.

Il y a deux types de services IU :

Services IU de niveau adaptation

Ces services sont exécutés dans le contexte d'une adaptation instance (sous l'onglet "Services"), d'une table (sous le menu "Actions"), sur une occurrence (en haut de page).

Cas d'usage types

  • Mise à jour en masse des enregistrements (ou d'une sélection d'enregistrements) d'une table (par exemple, réévaluation des montants de la colonne "prix du produit" en appliquant un ratio saisi par l'utilisateur).
  • Import de données en provenance d'une source externe dans l'adaptation intance courante.
  • Export des occurrences sélectionnées d'une table vers un système tiers.
  • Implémentation d'événements spécifiques du cycle de vie d'une entité MDM. Par exemple, création d'un produit qui impacte plusieurs tables ou bien "fermeture" d'un produit à une date spécifiée par l'utilisateur.
  • Afficher des informations statistiques sur une table.
  • etc.

Implémentation

Un service IU est ajouté en deux étapes :

  1. Déclarer votre Service IU dans le modèle d'adaptation. Voir Définition du schéma.
  2. Implémenter votre service comme une application JSP ou Java Servlet. Le code de l'application utilisera la classe com.softwareag.mdm.service.ServiceContext. JavaDoc

Notons que le schéma considéré doit être packagé, au préalable, dans un module. Vous pouvez aussi consulter l'exemple d'implémentation d'import/export du Tutoriel.

Utilisation des services dans le Manager

Une fois que vous avez développé, déployé et déclaré un service IU, les utilisateurs y accèderont dans webMethods Master Data Manager en utilisant le bouton .


Services IU de niveau branche ou version

Un service IU peut aussi être exécuté au niveau d'une branche. Cette application Java/JSP/Servlet doit être déclarée dans un module (voir ci-dessous).

L'objectif de ce type de service est de permettre l'écriture de processus à caractères métier de haut niveau en donnant de la flexibilité sur l'accès aux fonctions comme le merge, l'import/export, la validation, etc.

Cas d'usage types

  • Import de données en provenance d'une source externe.
  • Export des données de la version vers un système tiers.
  • Valider et versionner une branche avant un export
  • Envoyer des messages à un système de supervision avant une fusion
  • Exporter une version et monitorer en asynchrone les acquittements des systèmes cibles
  • etc.

Accès à ces services

Ces services sont accessibles via le menu principal des branches :

Menu.

Au niveau de ce sous-menu, on trouve tous les services declarés sur tous les modules enregistrés sur la plate-forme.

Menu.

Déclaration

Les services doivent être déclarés au sein de la configuration d'un module.

La recommandation est de créer une application web dédiée à ce type de service puisqu'ils sont disponibles pour toutes les branches mais peuvent avoir un cycle de vie différent de celui des données et de celui du produit.

Les services sont declarés dans le fichier module.xml comme suit :

<?xml version="1.0encoding="UTF-8"?>
<module xmlns="urn:mdm-schemas:module_2.1xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance
     xsi:schemaLocation="urn:mdm-schemas:module_2.1 http://schema.softwareag.com/module_2.1.xsd">
    <name>mdm-test</name>
    <publicPath>mdm-test</publicPath>
    <locales>
        <locale>fr_FR</locale>
    </locales>
    <services>
        <service name="Service1">
            <resourcePath>/pages/mdm-test.jsp</resourcePath>
            <type>branch</type>
            <documentation lang="fr-FR">
                <label>Merge filles sur parent</label>
                <description>Ce service merge toutes les filles sur la branche parente si elles sont valides
                </description>
            </documentation>
            <documentation lang="en-US">
                <label>Merge children on parent</label>
                <description>This service merge all children on parent branch after validation</description>
            </documentation>
        </service>
        <service name="Service2">
            <resourcePath>/pages/mdm-merge-validate.jsp</resourcePath>
            <type>branch</type>
            <documentation lang="fr-FR">
                <label>Merge/Valide/Export</label>
                <description>Merge la branche courante avec son parent puis valide ce parent et l'exporte.
                </description>
            </documentation>
            <documentation lang="en-US">
                <label>MergeValidate/export</label>
                <description>Merge current branch to parent if valid. Then validates parent and export it.
                </description>
            </documentation>
        </service>
        <service name="Fake1">
            <resourcePath>/pages/fake.jsp</resourcePath>
            <type>version</type>
            <documentation lang="fr-FR">
                <label>Service fake</label>
                <description>Ne fait rien mais le fait sur une version.</description>
            </documentation>
            <documentation lang="en-US">
                <label>Service fake</label>
                <description>Do nothing but do it on a version.</description>
            </documentation>
        </service>
        <service name="Fake2">
            <resourcePath>/pages/fake.jsp</resourcePath>
            <type>any</type>
            <documentation lang="fr-FR">
                <label>Service fake</label>
                <description>Ne fait rien mais le fait sur une version ou une branch.</description>
            </documentation>
            <documentation lang="en-US">
                <label>Service fake</label>
                <description>Do nothing but do it on a version or a branch.</description>
            </documentation>
        </service>
    </services>
</module>

Avec les définitions suivantes pour les éléments :

Elément Obligatoire Définition
services Oui, s'il y a des services Racine pour la déclaration des services.
service Oui, s'il y a au moins un service Un par service
attribute::name Oui Nom du service. Doit être unique au périmètre d'un module.
resourcePath Oui Chemin menant au service. Relatif par rapport au chemin de la webapp correspondant au module.
type Oui Permet de restreindre l'exécution d'un service. Les valeurs possibles sont : branch, version, any.
documentation Non Libellé et description du service. Permet d'obtenir un texte compréhensible par l'utilisateur final.
attribute::lang Oui Variante de language pour la documentation.
label Non Texte court décrivant le service.
description Non Texte long décrivant le service.

Exemples

Le code suivant illustre une implémentation exemple de ce type de service. Le service valide la home courante puis redirige l'utilisateur vers le merge interactif. A la fin du merge, une jsp valide les résultat et exporte la branche.

merge-validate.jsp

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<%@ page language="java" contentType="text/html; charset=UTF-8"  pageEncoding="UTF-8"%> 
<%@ page import="com.softwareag.mdm.service.ServiceContext" %> 
<%@ page import="java.io.*"%>  
<%@ page import="java.util.*"%> 
<%@ page import="com.softwareag.mdm.adaptation.*"%>   
<%@ page import="com.softwareag.mdm.base.text.*"%>   
<%@ page import="com.softwareag.mdm.service.*"%>   
<%@ page import="com.softwareag.mdm.ui.*"%> 
<% 
    final ServiceContext sContext = ServiceContext.getServiceContext(request);  
%>  
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Test Jsp</title>
</head>
<body>
<%= sContext.getServiceLabel() %> : Merge children on current branche : 
<%= sContext.getCurrentHome().getLabelOrName(sContext.getLocale()) %>
<hr width="50%" align="left" />
<%
final AdaptationHome currentHome = sContext.getCurrentHome();
final AdaptationHome parentHome  = currentHome.getParentBranch();
request.getSession().setAttribute("parentHome", parentHome);
if (!currentHome.getValidationReportsMap(Severity.ERROR).isEmpty()) {
   out.write("The current home is not valid, you cannot proceed to the merge decisions");
   return;

String myURL = sContext.getURLForIncludingResource("/docs/sample2-end.jsp");
UIHttpManagerComponent httpComponent = UIHttpManagerComponent.createOnServiceContext(sContext);
httpComponent.selectHome(currentHome);
httpComponent.setService(ServiceKey.MERGE);
httpComponent.setRedirectionURI(myURL);
out.write("The current home is valid, you can proceed to the merge decisions<br />");
out.write("<a href=\""+httpComponent.getURIWithParameters()+"\">Next step</a>");
%>
</body>
</html>

merge-validate-end.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"  pageEncoding="UTF-8"%> 
<%@ page import="com.softwareag.mdm.service.ServiceContext" %> 
<%@ page import="java.io.*"%>  
<%@ page import="java.util.*"%> 
<%@ page import="com.softwareag.mdm.adaptation.*"%>   
<%@ page import="com.softwareag.mdm.base.text.*"%>   
<%@ page import="com.softwareag.mdm.service.*"%>   
<%@ page import="com.softwareag.mdm.ui.*"%> 
<%@ page import=" com.softwareag.mdm.instance.*" %>
<% 
    final ServiceContext sContext = ServiceContext.getServiceContext(request);  
%>  
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>MDM Test Jsp</title>
</head>
<body>
<%= sContext.getServiceLabel() %>
<hr width="50%" align="left" />

<%
    UIHttpManagerComponentReturnCode rc = UIHttpManagerComponentHelper.getReturnCodeFromHttpRequest(request);
    if (rc.isMergeCancelled()) {
        out.println("The procedure has been canceled:");
        return;
    }
    AdaptationHome parent = (AdaptationHome) request.getSession().getAttribute("parentHome"); 
    if (!parent.getValidationReportsMap(Severity.ERROR).isEmpty())
    {
        out.println(parent.getLabelOrName(sContext.getLocale()) + " is not valid, cannot export.<br />");
        return;
    }
        out.println(parent.getLabelOrName(sContext.getLocale()) + " is valid, continue.<br />");
        String versionName = ""+ System.currentTimeMillis();
        parent.getRepository().createHome(
        parent,
        HomeKey.forVersionName(versionName),
        sContext.getSession().getUserReference(),
        sContext.getSession(),
        UserMessage.createInfo("My label"),
        UserMessage.createInfo("My Description"));
        out.println("A version has been created : "+versionName+"<br />");
        final Archive archive = Archive.forFile(new File(parent.getLabelOrName(sContext.getLocale())+".mdm"));
        Procedure proc = new Procedure()  
        {  
             public void execute(ProcedureContext aContext) throws Exception  
             {  
                  aContext.doExportArchive(archive);         
             }
        };
        ProcedureResult result = sContext.execute(proc);  
        out.println("Archive done. "+archive.getLocationInfo());
%>

</body>
</html>

Contrôle d'accès

Les permissions sur les branches et les versions s'appliquent toujours au sein des services. Cependant, il est possible d'ajouter du code métier pour se prémunir d'accès non autorisés aux services. Ce code est de la responsabilité du développeur..

Mise à jour de masse

Quand un service effectue des mises à jours de masse sur le référentiel, il ne sera pas toujours possible d'inclure l'ensemble des opérations dans une seule transaction atomique. Le nombre de mises à jour dépendant de la taille mémoire allouée à la JVM, une telle limite existe par nature.
Il est par conséquent possible de définir l'empan de la transaction en présisant le nombre de modifications par transaction via la méthode ProcedureContext.setCommitThreshold(int commitThreshold); illustrée dans l'exemple suivant. Un commit sera effectué toutes les 1000 opérations :

Procedure procedure = new Procedure()
{
   public void execute(ProcedureContext aContext) throws Exception
   {
      aContext.setCommitThreshold(1000);
      aContext.setAllPrivileges(true);
      aContext.doImportArchive(specs);
   }
};
Il est à noter qu'en cas d'anomalie toutes les occurences précédemment commitées resteront en base.

 

Home > Services