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:
- Declare your UI Service in the adaptation model.
See Schema Definition.
Note that the schema must be packaged in a module. - Implement your service by using JSP or Servlet API.
The code will use
com.softwareag.mdm.service.ServiceContext
API class.
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:
.
Entering this submenu shows all services declared on all modules.
.
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:
<module xmlns="urn:mdm-schemas:module_2.1" xmlns: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
<%@ 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 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 :
{
public void execute(ProcedureContext aContext) throws Exception
{
aContext.setCommitThreshold(1000);
aContext.setAllPrivileges(true);
aContext.doImportArchive(specs);
}
};
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 :
- Déclarer votre Service IU dans le modèle d'adaptation. Voir Définition du schéma.
- Implémenter votre service comme une application JSP ou Java Servlet.
Le code de l'application utilisera la classe
com.softwareag.mdm.service.ServiceContext
.
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 :
.
Au niveau de ce sous-menu, on trouve tous les services declarés sur tous les modules enregistrés sur la plate-forme.
.
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 :
<module xmlns="urn:mdm-schemas:module_2.1" xmlns: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
<%@ 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 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 :
{
public void execute(ProcedureContext aContext) throws Exception
{
aContext.setCommitThreshold(1000);
aContext.setAllPrivileges(true);
aContext.doImportArchive(specs);
}
};
Home > Services