Services WEB/REST
En standard, beCPG propose un service HTTP REST appelé Remote API qui permet :
- d'importer les données d'une entité au format Xml,
- d'exporter les données d'une entité au format Xml selon des critères (Ex : je souhaite tous les produits qui sont validés et effectifs à la date DD/MM/YYYY).
Ce service REST permet de réaliser des interfaces avec des logiciels tiers tel que l'ERP. Par entité, on entend le produit, le client, le fournisseur, le projet, etc... avec l'ensemble de ses informations et cela de manière dynamique sans développement.
L'interface d'échange peut donc être réalisée par un outil tiers dont le rôle est de :
- piloter les échanges,
- transformer les flux (règles de transformation sur des listes de valeurs par exemple),
- gérer les erreurs. Cette outil tiers dialogue avec la Remote API pour importer et exporter les données de beCPG. 2 approches sont possibles :
- le client possède un outil tiers permettant de réaliser l'interface,
- le client souhaite que beCPG mette en place un outil tiers permettant de réaliser l'interface. Par ailleurs, toutes les API de l'application sont accessibles par services REST :
- opérations CRUD, Create/Read/Update/Delete
- formulation
- génération documentaire
- récupération des versions, des fiches techniques
- etc...
API beCPG
La remote API de beCPG propose les URL REST suivantes:
<url>/becpg/remote/entity/list?path={path}</url>
<url>/becpg/remote/entity/list?query={query}&maxResults={maxResults}</url>
<url>/becpg/remote/entity?nodeRef={nodeRef}</url>
<url>/becpg/remote/entity?path={path}</url>
<url>/becpg/remote/entity?query={query}</url>
<url>/becpg/remote/formulate?nodeRef={nodeRef}</url>
<url>/becpg/remote/formulate?path={path}</url>
<url>/becpg/remote/formulate?query={query}</url>
<url>/becpg/remote/merge?nodeRef={nodeRef}</url>
<url>/becpg/remote/branch?nodeRef={nodeRef}</url>
<url>/becpg/remote/report?nodeRef={nodeRef}&tplNodeRef={tplNodeRef}</url>
<url>/becpg/remote/report?nodeRef={nodeRef}&tplNodeRef={tplNodeRef}&locale={locale}</url>
<url>/becpg/remote/report?nodeRef={nodeRef}&tplNodeRef={tplNodeRef}&locale={locale}&format={format}</url>
Les méthodes POST/GET/PUT/DELETE permettent respectivement d'ajouter, retrouver, mettre à jour et supprimer des entités dans le PLM (produit, client, fournisseur, etc ..).
Lister les entités
La liste des entités est obtenue avec la requête LIST et peut être filtrée suivant des critères de recherche avancés (dernier produit modifié depuis une date spécifiée par exemple).
<url>/becpg/remote/entity/list?path={path}</url>
<url>/becpg/remote/entity/list?query={query}&maxResults={maxResults}&fields={fields}</url>
<url>/becpg/remote/entity/list?path={path}&maxResults={maxResults}&fields={fields}</url>
La syntaxe de recherche est la syntaxe Lucène FTS Alfresco 1 : http://docs.alfresco.com/5.0/concepts/rm-searchsyntax-intro.html
1. Vous pouvez aussi vous référer à la partie Construction de requêtes Lucène de la documentation ↩
Un exemple de requête permettant d'avoir un produit fini suivant son code erp :
+TYPE:"bcpg:finishedProduct" AND +@bcpg\\:erpCode:"codeErp" AND -ASPECT:"bcpg:compositeVersion"
(-ASPECT:"bcpg:compositeVersion" permet d'exclure les versions antérieur)
L'Url correspondante :
http://localhost:8080/alfresco/service/becpg/remote/entity?query=%2BTYPE%3A%22bcpg%3AfinishedProduct%22%20AND%20%2B%40bcpg%5C%3AerpCode%3A%22codeErp%22%20AND%20-ASPECT%3A%22bcpg%3AcompositeVersion%22
Pour obtenir l'URL encodé (dans la console de firefox):
encodeURIComponent('+TYPE:"bcpg:finishedProduct" AND +@bcpg\\:erpCode:"codeErp" AND -ASPECT:"bcpg:compositeVersion"')
Le paramètre maxResults permet de spécifier un nombre de résultat (-1 pour avoir tous les résultats)
Le paramètre format permet de modifier le format XML de la réponse
- format=xml (Par défaut)
- format=json (Format json)
Le paramètre fields permet de spécifier des champs ou des associations à extraire dans les résultats :
http://localhost/alfresco/service/becpg/remote/entity/list?query=%2BTYPE%3A%22bcpg%3AfinishedProduct%22&fields=bcpg:legalName,bcpg:clients
Exemples :
Exemple de script bash permettant de récupérer directement sous forme de fichier xml une liste d'entités :
#!/bin/sh
export REMOTE_SERVER=http://localhost:8080/alfresco/service/becpg/remote/entity
export REMOTE_USER=admin
echo "Entrez le mots de passe"
read REMOTE_PASSWORD=
#Récupération de la liste des noeuds :
wget --quiet --http-user=$REMOTE_USER --http-password=$REMOTE_PASSWORD --header=Accept-Charset:iso-8859-1,utf-8 --header=Accept-Language:en-us -O list.xml $REMOTE_SERVER/list
count=1
#On parcourt la liste
while [ -n "$nodeRef" -o $count = 1 ]
do
nodeRef=`cat list.xml | xpath -q -e //*[$count]/@nodeRef | sed s/nodeRef=//g |sed s/\"//g`
echo "\Obtention du noeud $nodeRef";
#On enregistre chaque noeud
wget --quiet --http-user=$REMOTE_USER --http-password=$REMOTE_PASSWORD --header=Accept-Charset:iso-8859-1,utf-8 --header=Accept-Language:en-us -O entity_$count.xml $REMOTE_SERVER?nodeRef=$nodeRef
count=$((count+1))
done
Obtenir une entité
Pour l'obtention d'entités, deux services REST sont disponibles :
La remote API en utilisant des requêtes de TYPE GET suivantes
<url>/becpg/remote/entity?nodeRef={nodeRef}&format={format}</url>
<url>/becpg/remote/entity?path={path}&format={format}</url>
<url>/becpg/remote/entity?query={query}&format={format}</url>
<url>/becpg/remote/entity?nodRef={nodeRef}&lists={lists}&fields={fields}</url>
<url>/becpg/remote/entity?path={path}&lists={lists}&fields={fields}</url>
<url>/becpg/remote/entity?query={query}&lists={lists}&fields={fields}</url>
Le paramètre format permet de modifier le format XML de la réponse :
- format=xml (Par défaut)
- format=json (Format json))
- format=xml_all (Contient le détails de toutes les associations)
- format=xml_excel (Format adapter pour l'utilisation comme datasource dans excel)
- format=xml_light (Ce format ne contient pas les associations de type enfants)
- format=xsd (Ce format permet d'extraire la XSD)
- format=xsd_excel (Ce format permet d'extraire la XSD pour excel)
Vous pouvez également passer des paramètres supplémentaires de filtrage pour alléger la réponse. Il y a 3 types de filtrage :
- Filtrage des Propriétés : inclus uniquement les propriétés listées (fields=bcpg:legalName)
- Filtrage des Associations : inclus uniquement les associations listées (fields=bcpg:clients)
- Filtrage des Listes : inclus uniquement les listes listées (lists=bcpg:compoList)
Par ailleurs, vous pouvez extraire les propriétés d'une association en passant dans le paramètre fields le nom des associations et leurs propriétés, en respectant le format suivant : ASSOC_Name1|PROP_Name1,ASSOC_Name1|PROP_Name2.
Exemple
http://localhost/alfresco/service/becpg/remote/entity?nodeRef=workspace://SpacesStore/9b4dd09a-afaa-41ec-84eb-db062146975c&fields=bcpg:legalName,bcpg:clients,bcpg:compoListProduct|bcpg:productState&lists=bcpg:compoList
L'API Rapport
<url>/becpg/report/datasource?nodeRef={nodeRef}</url>
L'API rapport effectue un retravail de la donnée et permet d'obtenir un XML plus facile à exploiter. Les données de formulation, tare, coût, ainsi que les listes multi-niveaux sont directement exploitables. Cette API est conseillée si vous souhaitez extraire des données produits. Cette API est moins performante.
Mettre à jour une entité
La mise à jour et la création d'une entité sont réalisées en utilisant les méthodes PUT (Création) et POST (Mise à jour) et les requètes suivantes :
<url>/becpg/remote/entity?nodeRef={nodeRef}</url>
<url>/becpg/remote/entity?path={path}</url>
<url>/becpg/remote/entity?query={query}</url>
<url>/becpg/remote/entity?nodeRef={nodeRef}&createVersion=true&majorVersion={majorVersion}&versionDescription={description}</url>
Le contenu de la requête doit contenir un XML au format par défaut de la remote API. Il n'est pas nécessaire d'avoir tous les champs. Seuls les champs présents sont créés/mis à jour.
Lorsque createVersion=true alors majorVersion (true/false) et versionDescription permettent de créer une nouvelle version de l'entité à mettre à jour.
Exemple:
Exemple de requête CURL pour créer une entité
curl --user username:password -H "Content-Type: application/xml" -X PUT --data @sample-entity.xml http://localhost/alfresco/service/becpg/remote/entity?format=json
Exemple de XML permettant de créer un projet sample-entity.xml
<?xml version='1.0' encoding='UTF-8'?>
<pjt:project xmlns:pjt="http://www.bcpg.fr/model/project/1.0" path="/app:company_home/st:sites/cm:simulation/cm:documentLibrary"
type="node" name="Sample project">
<pjt:projectPriority type="d:int"><![CDATA[2]]></pjt:projectPriority>
<cm:description xmlns:cm="http://www.alfresco.org/model/content/1.0" type="d:mltext" fr="Texte - texte -texte"><![CDATA[Texte - texte -texte]]></cm:description>
<cm:name xmlns:cm="http://www.alfresco.org/model/content/1.0" type="d:text"><![CDATA[Sample project]]></cm:name>
<cm:title xmlns:cm="http://www.alfresco.org/model/content/1.0" type="d:mltext" fr="Sample project"><![CDATA[Sample project]]></cm:title>
<pjt:projectState type="d:text"><![CDATA[Planned]]></pjt:projectState>
</pjt:project>
Vous pouvez également utiliser le format JSON qui est le format conseillé pour la création et la mise à jour à partir de la version 3.2. Ce format a l'avantage de permettre la mise à jour de certains champs impossible auparavant.
curl --user username:password -H "Content-Type: application/json" -X PUT --data @sample-json.json http://localhost/alfresco/service/becpg/remote/entity
Pour chaque élément, la racine définit les clés sur lesquelles rechercher un élément et attributes permet de spécifier les valeurs à mettre à jour.
Exemple :
{
"entity": {
"bcpg:erpCode": "TEST-REMOTE001",
"cm:name":"Test remote",
"type": "bcpg:finishedProduct",
"params" : {
"replaceExistingLists" : true,
"dataListsToReplace": "bcpg:allergenList,bcpg:compoList"
},
"attributes": {
"bcpg:legalName_en": "Legal Produit fini EN",
"bcpg:legalName": "Legal Produit fini FR",
"bcpg:clients": [
{
"bcpg:code": "C1"
},
{
"bcpg:code": "C2"
}
],
"bcpg:productHierarchy2": {
"path": "/app:company_home/cm:System/cm:ProductHierarchy/bcpg:entityLists/cm:finishedProduct_Hierarchy",
"bcpg:lkvValue": "Pizza",
"type": "bcpg:linkedValue"
}
},
"datalists": {
"bcpg:allergenList": [
{
"bcpg:allergenListAllergen": {
"bcpg:charactName": "Allergen 4"
},
"attributes": {
"bcpg:allergenListVoluntary": false,
"bcpg:allergenListInVoluntary": true
},
"type": "bcpg:allergenList"
}
],
"bcpg:compoList": [
{
"bcpg:compoListProduct": {
"bcpg:code": "LSF411"
},
"attributes": {
"bcpg:compoListQtySubFormula": 15,
"bcpg:compoListUnit": "kg"
}
},
{
"bcpg:compoListProduct": {
"bcpg:erpCode": "TEST1"
},
"attributes": {
"bcpg:compoListQtySubFormula": 10,
"bcpg:compoListUnit": "kg"
}
}
]
}
}
}
L'attribut params permet de passer certains paramètres à l'API:
- replaceExistingLists (false) : Permet de supprimer les lignes dans les listes non présentes dans le fichier JSON
- dataListsToReplace ("") : Permet de supprimer les lignes dans certains listes uniquement
Mettre à jour une propriété multi-langue
Vous pouvez importer les champs de type mltext en spécifiant pour chaque langue la valeur :
<cm:title xmlns:cm="http://www.alfresco.org/model/content/1.0" type="d:mltext" de="Beispielprojekt" fr="Exemple de projet" en="Sample project"><![CDATA[Sample project]]></cm:title>
En json la propriété est suivie d'un underscore et du code de la langue
"bcpg:legalName_en_US": "Valeur US"
Mettre à jour une association
Une association peut être identifiée par son nodeRef, son nom, son code (beCPG ou ERP) et son chemin
N.B : Dans les précédentes versions < 2.2.X, il faut fournir un nodeRef factice.
Exemple : l'association entité d'un projet
<pjt:projectEntity type="assoc"><bcpg:finishedProduct type="node" name="ENTITY_NAME" code="BCPG_CODE" nodeRef="FAKE_NODEREF"></bcpg:finishedProduct></pjt:projectEntity>
Supprimer une entité
La remote API permet de supprimer des entités en utilisant des requêtes de TYPE DELETE suivantes:
<url>/becpg/remote/entity?nodeRef={nodeRef}&format={format}</url>
<url>/becpg/remote/entity?path={path}&format={format}</url>
<url>/becpg/remote/entity?query={query}&format={format}</url>
Exemple de script permettant de supprimer en masse des entités (Toutes les matières)
#!/bin/sh
export REMOTE_SERVER=http://localhost/alfresco/service/becpg/remote/entity
export REMOTE_USER=admin
echo "Entrez le mots de passe"
read REMOTE_PASSWORD=
if [ $# -ne 1 ]
then
#LIST
wget --quiet --http-user=$REMOTE_USER --http-password=$REMOTE_PASSWORD --header=Accept-Charset:iso-8859-1,utf-8 --header=Accept-Language:en-us -O list.xml $REMOTE_SERVER/list?query=%2BTYPE%3A%22bcpg%3ArawMaterial%22%20-ASPECT%3A%22sys%3Atemporary%22%20-ASPECT%3A%22bcpg%3AentityTplAspect%22
count=1
while [ -n "$nodeRef" -o $count = 1 ]
do
nodeRef=`cat list.xml | xpath -q -e //*[$count]/@nodeRef |sed s/nodeRef=//g|sed s/\"//g|sed s/\:\\\///g| xargs`
echo "DELETE ${nodeRef}";
curl --user $REMOTE_USER:$REMOTE_PASSWORD -X $REMOTE_SERVER?nodeRef=$nodeRef
count=$((count+1))
done
exit 0
fi
Obtenir une fiche technique
La remote API permet aussi de télécharger des rapports en utilisant GET suivantes:
<url>/becpg/remote/report?nodeRef={nodeRef}&tplNodeRef={tplNodeRef}</url>
<url>/becpg/remote/report?nodeRef={nodeRef}&tplNodeRef={tplNodeRef}&locale={locale}</url>
<url>/becpg/remote/report?nodeRef={nodeRef}&tplNodeRef={tplNodeRef}&locale={locale}&format={format}</url>
- nodeRef étant l'identifiant système du produit
- tplNodeRef étant l'identifiant du modèle de rapport
- locale étant le code de la langue
- format étant le format du rapport (PDF, XLSX, DOCX, ODT, ZIP)
De plus, il est possible de télécharger des rapports en spécifiant les paramètres au format JSON dans une requête POST
Exemple en utilisant l'outil CURL
#!/bin/sh
export LOCAL_SERVER=http://localhost/alfresco/service/becpg/remote/report
export LOCAL_USER=admin
export LOCAL_PASSWORD=becpg
curl --user $LOCAL_USER:$LOCAL_PASSWORD -H "Content-Type: application/json" -X POST --data @params.json "$LOCAL_SERVER?nodeRef=$1&tplNodeRef=$2" > report.pdf
Les variables $1 et $2 sont respectivement l'identifiant du produit et l'identifiant du modèle de rapport. Le fichier params.json contient les paramètres :
{
iterationKey : "bcpg:plant",
params : [{
id: "param1",
prop : "cm:name"
}],
prefs : {
assocsToExtract : "bcpg:plants,bcpg:suppliers,bcpg:storageConditionsRef,bcpg:precautionOfUseRef,bcpg:nutListNut",
assocsToExtractWithDataList : "bcpg:compoListProduct"
},
nameFormat : "{entity_cm:name}- {report_cm:name} - {locale} - {param1} ",
titleFormat : " {report_cm:name} - {locale} - {param1}"
}
Pour plus de détails sur le paramétrage des rapports voir Extracteur - Partie 1
Créer et fusionner une branche
Les requêtes POST suivantes permettent respectivement de créer et fusionner une branche
<url>/becpg/remote/branch?nodeRef={nodeRef}&destNodeRef={destNodeRef?}</url>
destNodeRef est optionnel, par défaut la branche est créé dans le même dossier que l'entité.
<url>/becpg/remote/merge?nodeRef={nodeRef}&branchToNodeRef={branchToNodeRef?}&majorVersion={majorVersion?}&impactWused={impactWused?}</url>
Contenu de la requête:
{
"description":"Branche description}
}
Utilitaire JAVA
beCPG fournit également une librairie utilitaire JAVA permettant de faciliter les appels aux services REST. Cette librairie peut être compilée depuis le code source :
https://www.becpg.fr/hg/becpg-tools (read-only:read-only)
ou obtenue sous forme de jar : becpg-tools.jar
Ci-dessous un exemple de classe java permettant de récupérer la liste des entités puis d'itérer chaque entité.
import java.io.IOException;
import java.io.InputStream;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.client.HttpClient;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import fr.becpg.tools.http.GetEntityCommand;
import fr.becpg.tools.http.ListEntitiesCommand;
public class SampleInstanceImporter {
private static Log logger = LogFactory.getLog(InstanceImporter.class);
private String serverUrl;
public InstanceImporter(String serverUrl) {
super();
this.serverUrl = serverUrl;
}
public void loadEntities(String query, HttpClient client) throws Exception {
ListEntitiesCommand listEntitiesCommand = new ListEntitiesCommand(serverUrl);
try (InputStream entitiesStream = listEntitiesCommand.runCommand(client, query)) {
DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
domFactory.setNamespaceAware(true); // never forget this!
DocumentBuilder builder = domFactory.newDocumentBuilder();
Document doc = builder.parse(entitiesStream);
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
int count = 1;
String nodeRef = null;
while ((nodeRef = (String) xpath.evaluate("//*[" + count + "]/@nodeRef", doc, XPathConstants.STRING)) != null && nodeRef.length() > 0) {
count++;
try {
loadEntity(client, nodeRef);
} catch(Exception e){
logger.error("Invalid Xml for "+nodeRef+" skipping node");
if(logger.isDebugEnabled()){
logger.debug(e,e);
}
}
}
}
}
private void loadEntity(HttpClient client, String nodeRef) throws Exception {
logger.info("Import nodeRef:" + nodeRef);
GetEntityCommand getEntityCommand = new GetEntityCommand(serverUrl);
try (InputStream entityStream = getEntityCommand.runCommand(client, nodeRef)) {
//Parse XML and do ETL transformation
}
}
public String buildQuery(Date lastImport) {
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
String dateRange = "MIN";
if (lastImport != null) {
dateRange = dateFormat.format(lastImport);
}
logger.info("Import from :[ " + dateRange + " TO MAX ]");
String query = "@cm\\:created:[%s TO MAX] OR @cm\\:modified:[%s TO MAX]";
return String.format(query, dateRange, dateRange);
}
public static void main(String[] args) throws Exception {
InstanceImporter remoteETLClient = new InstanceImporter("http://localhost:8080/alfresco");
DefaultHttpClient httpclient = new DefaultHttpClient();
UsernamePasswordCredentials creds = new UsernamePasswordCredentials("username", "password");
CredentialsProvider credsProvider = new BasicCredentialsProvider();
credsProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT), creds);
httpclient.setCredentialsProvider(credsProvider);
try {
Date lastImportDate = null; // Date de dernier import
remoteETLClient.loadEntities(remoteETLClient.buildQuery(lastImportDate), httpclient);
} finally {
httpclient.getConnectionManager().shutdown();
}
}
}
}
Sample REST Requests
GET List Finished Product Sample
curl --location --request GET 'https://$server/alfresco/service/becpg/remote/entity/list?query=+TYPE:"bcpg:finishedProduct"&format=json&fields=bcpg:legalName,bcpg:clients'
PARAMS
| query | +TYPE:"bcpg:finishedProduct" | | format | json | | fields | bcpg:legalName,bcpg:clients |
GET List of products by last modified Sample
curl --location --request GET 'https://$server/alfresco/service/becpg/remote/entity?format=json&query=(@cm\:created:[2020-02-10 TO MAX] OR @cm\:modified:[2020-02-10 TO MAX]) AND ( TYPE:"bcpg:finishedProduct" OR TYPE:"bcpg:semiFinishedProduct")
PARAMS
| query | (@cm\:created:[2020-02-10 TO MAX] OR @cm\:modified:[2020-02-10 TO MAX]) AND ( TYPE:"bcpg:finishedProduct" OR TYPE:"bcpg:semiFinishedProduct") | | format | json |
Get Entity allergen list Sample
curl --location --request GET 'https://$server/alfresco/service/becpg/remote/entity?format=json&query=+@bcpg\:erpCode:"TEST1"&lists=bcpg:allergenList&fields=bcpg:allergenListAllergen|bcpg:allergenCode,bcpg:allergenListVoluntary,bcpg:allergenListInVoluntary'
PARAMS
| query | @bcpg\:erpCode:"TEST1"| | format | json | | lists | bcpg:allergenList | | fields | bcpg:allergenListAllergen|bcpg:allergenCode,bcpg:allergenListVoluntary,bcpg:allergenListInVoluntary |
Get Compo List Sample
curl --location --request GET 'https://$server/alfresco/service/becpg/remote/entity?format=json&query=+@bcpg\:erpCode:"TEST1"&lists=bcpg:compoList&fields=bcpg:compoListProduct,bcpg:compoListQtySubFormula,bcpg:compoListUnit'
PARAMS
| query | @bcpg\:erpCode:"TEST1"| | format | json | | lists | bcpg:compoList | | fields | bcpg:compoListProduct,bcpg:compoListQtySubFormula,bcpg:compoListUnit |
GET Get Entity
curl --location --request GET 'https://$server/alfresco/service/becpg/remote/entity?format=json&query=+@bcpg\:erpCode:"TEST1"'
PARAMS
| query | @bcpg\:erpCode:"TEST1"| | format | json |
API Alfresco
Alfresco propose également une API REST documenté ici :
https://docs.alfresco.com/5.2/pra/1/topics/pra-welcome.html
Que vous pouvez parcourir à cette URL:
https://api-explorer.alfresco.com/api-explorer/