1. API
1.1 Préférences Utilisateurs (MemberPreference)
Certaines fonctions de JPlatform (portées par coeur ou par les modules) proposent à l'utilisateur des options qui peuvent être persistées.
Par exemple, la nouvelle Topbar de JPlatform 10 propose le menu "Applications" dans lequel l'utilisateur peut choisir ses applications préférées et l'ordre dans lequel elles apparaissent dans le menu.
Jusqu'à présent les développeurs devaient gérer eux même un mode de stockage spécifique pour ces préférences utilisateur (ExtraDBData ou type dédié).
JPlatform 10 fournit désormais une API homogène et performante pour le stockage des préférences utilisateurs.
L'article JPlatform 10 - API des préférences utilisateurs (MemberPreference) présente en détail cette nouvelle API.
1.2 Evolutions sur les DBPublication
1.2.1 DB Publication multilingues
Avec JPlatform 10 un type de publication stockés en base de données peut désormais avoir des champs multilingues. Il dispose ainsi de la plupart des capacités multilingues des publications du store. Le multilinguisme peut s'appliquer sur des champs mono-valués ou multi-valués. Les publication en base ont maintenant un champ "Langue principale". Enfin, elles disposent aussi des copies de traduction.
Il y a néanmoins quelques limites :
- Seuls les champs multivalués de type List peuvent être multilingues (ce n'est pas possible pour les champs de type Set)
- Le tri sur le titre ne porte que sur la langue du site. Il ne peut pas porter sur la langue de navigation
- Lors de la comparaison de 2 versions d'une publication, le détail de changement sur les champs multivalués (monolingue ou multilingue) n'apparait pas.
En standard, les types suivants disposent de champs multilingues :
- DBDocument (titre et description)
- Media (titre et description)
- DBWebPage (titre et description)
C'est aussi le cas de certains types livrés par des modules
- Module Blog
- Billet
- Module JLearn
- JLearn - Savoir
- JLearn - Cours
- JLearn - Parcours
Techniquement, les textes dans les langues additionnelles d'un champ multilingue sont sérialisés en JSON et stockés dans un champ dédié. Ce champ reprend le nom du champ texte associé avec le suffixe MLE (pour MultiLingual Encoding). Par exemple, au champ title
est associé le champ titleMLE
contenant une Map JSON contenant le titre dans les langues additionnelles.
1.2.2 Copie de travail pour les DB Content
Les contenus stockées dans la base de données disposent désormais de la fonction "copie de travail".
3 champs sont utilisées pour les copies de travail
- mainInstance : renseigné dans la copie de travail et pointe l'instance originale
- mergeId : renseigné sur l'instance originale après la fusion d'une copie de travail. Il sert dans l'affichage de l'historique des versions pour consulter l'historique de la copie ayant servie à la fusion
- mergeDate : date de la dernière fusion.
Ces 3 champs sont ajoutés aux HBM des DB Content ainsi qu'aux HBM de leur révision.
1.2.3 FriendlyURL pour les DB Content
Les contenus en base disposent dans JPlatform 10 des URLs intuitives (friendly URL) comme pour les contenus stockés dans JStore.
1.2.4 QueryFilter pour les DBPublication
Dans le cas des publications du Store, les QueryFilter s'appliquent sur l'ensemble des résultats. Ce mode de fonctionnement n'est pas adapté aux contenus en base puisqu'il intervient après que la requête ait eu lieu et n'appliquerait donc qu'aux seuls les résultats de la tranche paginée.
A l'instar des RightPolicyFilter, il convient donc d'appliquer le filtrage durant l'itération de recherche (scroll). Ce mode de fonctionnement ayant un coût sur la recherche, il ne doit être enclenché que si des QueryFilter sont susceptibles d'intervenir sur cette recherche.
Pour le savoir, le QueryFilter doit l'indiquer au travers de la méthode callFilterDBResult() de la classe =QueryFilter
. Cette méthode est appellée au début de la recherche en base afin de déterminer si au moins un QueryFilter souhaite participer à la recherche. Ceci imposera une recherche avec scrolling (comme dans le cas des RightPolicyFilter).
En complément, et pour des cas simple, la méthode = callFilterDBResult(Class clazz, Map<String,Object> context)= est fournie lorsque le contrôle se base simplement sur le type de publication.
Enfin, la méthode filterDBResult
est appelée pour chaque résultats remontée de la recherché afin de déterminer si il doit être gardé ou non.
En synthèse, voici donc les méthodes qui ont été ajouté à la classe QueryFilter
:
public abstract class QueryFilter { ... boolean callFilterDBResult (PublicationCriteria); boolean callFilterDBResult(Class clazz, Map<String,Object> context); boolean filterDBResult(Publication pub, Map<String,Objet> context) }
1.3 Détection automatique du type de document
Dans le cadre de la prise en charge de volumétrie de données importantes, l'une des pistes consiste à répartir ces données dans différentes table de JcmsDB. En effet, moins une table contient de données plus les performances sont bonnes.
Traditionnellement, cette répartition en table peut être prise en charge directement par la base de données avec la technique du table partionning. Cependant, JPlatform 10 utilise l'ORM Hibernate pour le stockage des données en base, ce qui rend cette pratique compliquée à mettre en oeuvre.
L'alternative consiste donc à faire la répartition depuis JPlatform. On constate généralement que ce sont les documents qui représentent une grand part de la volumétrie à prendre en charge. Parmi eux, les média (images, video, audio) représentent une part importante. Pouvoir répartir ces média dans une table dédié est donc souhaitable.
Pour répondre à cet objectif, JPlatform 10 introduit la sélection automatique du type de document lors des dépôts ainsi que le type Media dédié au stockage des médias (images, video, audio).
En plus des bénéfices sur les performances, la sélection automatique du type de document aiderai encore d'avantage les utilisateurs qui sont amenés à déposer des documents en ne ce souciant plus du type à utiliser.
La sélection automatique peut s'appliquer à d'autres type que les documents.
1.3.1 Principes
La sélection automatique du type de document prend 3 paramètre :
- Le
loggedMember
- L'espace cible
- le MIME Type du fichier déposé
L'algorithme de sélection du type de document est la suivant :
- On recherche si il existe un type de document associé au type MIME du fichier (eg.
image/jpeg
) - Si c'est le cas et si le
loggedMember
peut publier ce type dans dans l'espace cible alors on retient ce type - Sinon on recherche si il existe un type de document associé au top-level type MIME du fichier (eg.
image
) - Si c'est le cas et si le
loggedMember
peut publier ce type dans dans l'espace cible alors on retient ce type - Sinon si le
loggedMember
peut publier le type de document par défaut dans dans l'espace cible alors on retient ce type - Sinon si le
loggedMember
peut publier le type DBFileDocument par défaut dans dans l'espace cible alors on retient ce type - Sinon si le
loggedMember
peut publier le type FileDocument par défaut dans dans l'espace cible alors on retient ce type - Sinon on recherche le premier sous-type de document que le
loggedMember
peut publier dans l'espace cible
1.3.2 Modes de dépôt concernées
Les modes de dépôts concernés par la sélection automatique du type de documents sont :
- Modal de dépôt de document (docChooserModal.jsp)
- Zone de dépôt de l'explorateur de média
- Zone de dépôt de la portlet Explorateur (docChooserInline.jsp)
- Champ document des types de contenus (champ de type
file
)
1.3.3 Modes de dépôt non concernés
- JDrive :
- Création à partir d'un document : il y a déjà un algorithme de résolution basé sur le type par défaut défini dans les propriété de JDrive
- Dépôt transparent : c'est le type de document défini dans les propriétés de JDrive qui est utilisé
- Dépôt interactif : c'est l'utilisateur qui choisi le type de document
- Add-in Outlook
- Dépôt des pièces jointe
- JCapture
- JCapture dispose déjà d'une mécanique de choix du type selon le modèle de capture
- Import de document
- Les règles d'import permettent déjà de définir le type de document à utiliser selon la source d'import
- Dépôt par le docChooser.jsp
- Dans JPlatform 10, ce mode de dépôt n'est plus disponible pour les premiers dépôts. Il ne sert que pour le dépôt d'une nouvelle version (et dans ce cas, le type de document ne change pas).
- Google Drive
- Lors de la récupération d'un document
- Office 365
- Lors de la récupération d'un document
- CMIS (client)
- Lors de la récupération d'un document
- Momindum
- Lors de la récupération d'une vidéo du Cloud Momindum.
1.3.4 Propriétés de mapping Content-Type/Classe
Le mapping d'un type de fichier avec un type de document de JPlatform se fait par une déclaration de propriété. Ces propriétés commencent par le préfix file-document.upload.class
et sont de la forme :
file-document.upload.class.<top-level/subtype>: <classe du type de document>=
<top-level/subtype>
représente le MIME type. Il peut s'agir d'un MIME type complet (eg. image/jpeg
, video/mp4
, application/pdf
, ...) ou uniquement du top-level (eg. image
, video
, application
, ...)
Exemples :
file-document.upload.class.image: generated.Media file-document.upload.class.video: generated.Media file-document.upload.class.audio: generated.Media file-document.upload.class.application/pdf: generated.MyCustomDocumentType
1.3.5 Propriété du type de document par défaut
Lorsque l'utilisateur dispose de plusieurs type de documents pour son dépôt et qu'il n'existe pas de mapping pour le contentType du fichier déposé, on se rabat sur le type de document par défaut à utiliser.
La définition du type de document à utiliser par défaut sur la plateforme se fait avec la propriété file-document.upload.class.default
Exemple :
file-document.upload.class.default: com.jalios.jcms.DBFileDocument
1.3.6 Type Media
Le type Media dérive de DBFileDocument. Il dispose des champs supplémentaire suivans :
mediaWidth
mediaHeight
mediaDuration
Il est à noter que, bien que destiné au stockage des médias, rien n'empêche un contributeur d'utiliser le type Media pour d'autres types de documents.
1.3.7 Interface de dépôt
L'interface de dépôt avancé ("Plus d'options") a été légèrement revue :
- L'onglet "Méta-données" a été renommé "Informations"
- Le choix du Workspace a été déplacé dans l'onglet Avancé
- Le sélecteur de type est par défaut sur "Sélection automatique du type" si il y a plus que d'un type proposé
- L'onglet Workflow n'apparait que si l'on choisi explicitement un type de document
- Le lien amenant vers l'ancienne interface de dépôt (docChooser.jsp) n'est plus proposé
1.3.8 API
L'API FileDocument proposent de nouvelles méthodes statiques :
getUploadClass(String contentType)
renvoie la classe de dépôt à utiliser pour lecontentType
donné ounull
.getDefaultUploadClass()
renvoie la classe de dépôt à utiliser par défautgetFirstDocumentClassAuthorized(Member, Workspace)
renvoie la première classe deFileDocument
que le membre donné peut utiliser dans leworkspace
donné. Revient à appeler la méthode suivante avec uncontentType
=null=getFirstDocumentClassAuthorized(Member, Workspace, String contentType)
renvoie la première classe deFileDocument
que le membre donné peut utiliser dans leworkspace
donné, en commençant par la classe mappée dans les propriétés pour lecontentType
donné. (Ex: si lecontentType
est"image"
ou"image/png"
, on essaye en premier le typegenerated.Media
).
1.4 Structure de l'organisation et responsables de département / services / employé
De plus en plus de modules participent à la gestion des processus de l'organisation (JLearn, JProcess, Gestion des congés, Recrutement, ...)
Pour cela, ces modules ont besoins de connaitre la structure de l'organisation et la relation hiérarchique entre les membres (qui est responsable de qui). Il est notamment important de pouvoir déterminer les membres qui composent l'équipe d'un responsable.
Jusqu'à présent ces informations étaient portées par le module Organigramme (FlowChart). En conséquence plusieurs modules était donc dépendant de ce module pour pouvoir fonctionner.
JPlatform 10 lève cette contrainte en ré-introduisant dans le coeur une API de gestion de la structure de l'organisation.
L'article JPlatform 10 - API de gestion de l'organisation et des responsables de département présente en détail cette nouvelle API.
1.5 ReplicaMessage
Dans un cluster JSync, seules les données du store (et éventuellement les fichiers associés) sont recopiés sur les différents réplicas du cluster. JcmsDB étant commune aux différents réplica, les données sont accessibles par tous les réplicas.
JPlatform 10 introduit une nouvelle API, les ReplicaMessage, qui permet aux réplicas de communiquer en dehors des échanges JSync. Le protocole utilisé garanti la distribution des messages dans l'ordre d'émission, même si un réplica n'est pas joignable lors de l'envoi.
JPlatform 10 utilise cette API pour propager les changements sur la structure des Workflows entre les réplicas.
Cette API pourrait aussi être utilisée plus tard pour propager les changement sur certaines propriétés de paramétrage.
L'article JPlatform 10 - L'API des ReplicaMessage présente cette API en détail.
1.6 Partage de contenu entre espace
JPlatform 10 permet de partager un contenu entre plusieurs espaces. Le guide JPlatform 10 - Partage de contenu entre espaces illustre cette nouvelle fonctionnalité.
1.6.1 Modèle de données
Le partage de contenu entre espace est matérialisé par le nouveaux champ attachWorkspaceSet
sur la classe Publication. Pour les contenus stockés en base, un deuxième champ, hasAttachWorkspaceSet
, est stocké pour dénormaliser cette information et accélérer les requêtes.
class Publication { Set<Workspace> attachWorkspaceSet; boolean public boolean hasAttachWorkspaceSet() {...} }
Ces évolutions sur le modèle sont transparentes pour les données existantes
1.6.2 Choix du portail d'affichage d'un contenu partagé
Il y a plusieurs modalité d'affichage d'un contenu :
- Soit depuis un lien interne à l'application (PQF, résultat de recherche, historique de navigation, activité)
- Soit depuis l'espace d'origine
- Soit depuis un espace de rattachement
- Soit depuis un autre espace
- Soit depuis un autre site (depuis un lien externes : mail, url friendly (qr code, ...))
L'affichage d'un contenu dépend donc de 2 paramètres : l'endroit d'où le contenu est accédé et qui y accède.
Soit trois espaces E1
, E2
et E3
Soit C
un contenu public de E1
qui est partagé dans E2
et E3
.
Soit M1
un membre appartenant à E1
, E2
et E3
Soit M2
un membre appartenant à E2
mais pas à E1
et E3
Soit M3
un membre appartenant à E3
mais pas à E1
et E2
Soit M2-3
un membre appartenant à E2
et E3
mais pas à E1
Cette matrice indique dans quel espace doit être affiché C
en fonction de qui fait l'accès et du lien avec lequel il est accédé :
Lien dans E1 |
Lien dans E2 |
Lien dans E3 |
Lien dans un autre espace | Lien externe | |
---|---|---|---|---|---|
M1 |
E1 |
E2 |
E3 |
E1 |
E1 |
M2 |
- | E2 |
- | E2 |
E2 |
M3 |
- | - | E3 |
E3 |
E3 |
M2-3 |
- | E2 |
E3 |
E2 ou E3 |
E2 ou E3 |
1.6.3 Modalité de rattachement / détachement de contenu
Soit C
un contenu appartenant à l'espace E1
Le contenu C
peut être partagé vers l'espace E2
par le membre M
si la condition suivante est vrai : M
est admin central OU (M
a accès à C
ET M
est contributeur dans E2
)
Dès qu'un partage a lieu, une alerte est envoyée à l'auteur de C
et à l'ensemble des admin de l'espace de C
indiquant qui a déclenché le partage (M
) et dans quel espace (E2
)
Un membre M
peut arrêter le partage du contenu C
dans l'espace E2
si la condition suivante est vraie : M
est admin central OU M
est l'auteur de C
OU M
est admin de E1
OU M
est admin de E2
OU M
est contributeur dans E2
1.6.4 Désactivation
La propriété publication.attach-ws.enabled
permet de désactiver complètement cette nouvelle fonctionnalité.
Il n'est alors plus possible de rattacher/détacher des publications à des espaces. Si des publications avaient préalablement été attachées, elles n'apparaitront plus dans les espaces de rattachement.
1.6.5 API
Classe Publication
Méthode | Description |
---|---|
canBeAttachedBy(Member) |
Retourne true si ce membre peut rattacher cette publication à un autre espace. |
canBeAttachedTo(Workspace, Member) |
Retourne true si ce membre peut rattacher cette publication à cet espace. |
canBeDetachFrom(Workspace, Member) |
Retourne true si ce membre peut détacher cette publication de cet espace. |
getAttachedWorkspaceSet() |
Retourne l'ensemble des espaces auxquels est rattaché cette publication. |
attachTo(Workspace, Set<Category>, Member mbr) |
Effectue le rattache de la publication dans l'espace donné avec les catégories données et pour le membre donné |
detachFrom(Workspace) |
Effectue le détacment de la publication de l'espace donné. |
Classe Channel
Méthode | Description |
---|---|
isWSAttachmentEnabled() |
Retourne true si le rattachement est autorisé. |
Classe PublicationCriteria
Méthode | Description |
---|---|
setSearchInAttachWS(boolean) |
Permet d'indiquer si la recherche doit porter dans les espaces de rattachement. |
1.7 Export JSON
Les API REST de JPlatform peuvent maintenant exporter leurs données au format JSON.
Pour utiliser cette fonctionnalité, il faut envoyer la requête REST avec un header Accept:application/json
.
Ex.
curl --header "Accept:application/json" https://<jplatform>/rest/WhoAmI
Exemple de retour :
{ "class": "com.jalios.jcms.Member", "id": "jn1_92854", "cdate": "2010-04-30T07:10:01Z", ... "login": "xxxxx", "name": "xxxxx", "firstName": "xxxx", "organization": "Jalios", "department": "R & D", "jobTitle": "Ingénieur R&D", "email": "xxxxxxxxxx@jalios.com", "mobile": "XX XX XX XX XX", ... "declaredGroups": [ { "class": "com.jalios.jcms.Group", "id": "jn1_339640", "name": "xxxxxx" }, { "class": "com.jalios.jcms.Group", "id": "jn1_103636", "name": "XXXXX" } ], "ldapSync": true, "lastLdapSynchro": "2017-10-09T20:00:00Z", "language": "en" }
La fonctionnalité des relateds (décrite dans la documentation Services Web RESTful avec JCMS Open API) est aussi applicable dans ce cas.
Par défaut la librairie d'export json exporte tout le contenu d'un objet et aussi le contenu des champs de l'objet. On peut donc avoir une quantité importante d'information voir une boucle infinie (exemple d'un membre appartenant à un groupe qu'il a créé). Un autre paramètre a donc été ajouté pour éviter ce problème, c'est la notion de profondeur (paramètre depth). L'export se fait en respectant la notion de profondeur n (par défaut 1) et affiche un résumé des éléments de profondeur n+1. Si cette donnée est une data, on affiche la class, l'id et le titre.
Note : Cela ne change pas le format de soumission des données (toujours au format form data)
1.8 Autres nouveautés
1.8.1 DataSelector extends Predicate
Dans JPlatform 10 on peut donc utiliser tous les DataSelector
comme des prédicats Java 8.
L'interface DataSelector
dérive maintenant de Predicate<Data>
. La méthode héritée test()
a été implémentée avec une default method qui appelle la méthode isSelected()
Exemple : Récupération de l'ensemble des publications dont l'auteur est mbr
et dont la date de publication est comprise entre startDate
et endDate
.
Set<Data> set = channel.getDataSet(Publication.class) .stream() .filter( Data.getAuthorSelector(mbr) .and(Publication.getPdateSelector(startDate, endDate)) ) .collect(Collectors.toSet());
1.8.2 Alert : attribut résumé (Summary)
Afin de garantir un affichage court dans le menu des alertes de la topbar, les alertes dispose d'un attribut summary
. Cet attribut est optionnel et sera dans la plupart des cas vide.
Pour les alertes ayant une description avec beaucoup de texte il est recommandé de produire un résumé de quelques lignes.
Les résumé doivent être en HTML.
1.8.3 Alert : afficher l'abstract de la publication
Il est possible de demander à afficher le résumé de la publication lorsqu'une alerte est envoyée via certaines propriétés.
Par exemple pour afficher l'abstract de la publication mentionnée lorsqu'une alerte de nouvelle mention est envoyée, il faut ajouter :
alert.channel.web.content.abstract.mention.notification: true // Pour les alertes web alert.channel.mail.content.abstract.mention.notification: true // Pour les alertes web
Ces deux propriétés correspondent à la déclaration d'alerte alert.name.mention.notification
1.8.4 EditPublicationHandler : setSkipActivity()
Il est possible de forcer la non prise en compte dans l'activité d'une écriture à partir d'un formHandler
en positionnant l'attribut skipActivity
sur le formHandler
. Ceci est notamment mis en oeuvre lors des dépôts depuis le MediaBrowser.
1.8.5 DataController.CTXT_IS_SILENT_WRITE
L'entrée de contexte DataController.CTXT_IS_SILENT_WRITE
permet d'indiquer qu'il s'agit d'une écriture silencieuse. Elle est alors ignorée des PublicationFollower
et l'activité ESN.
1.8.6 WebPageMetaDataExtractor
Cette classe permet de récupérer les méta données d'un site distant en inspectant le code source (Les balises meta "og" sont privilégiées si disponibles).
Vous pouvez l'utiliser via le code suivant :
- WebPageMetaData metaData = WebPageMetaDataExtractorUtils.getWebPageMetaData(url, userAgent)
- url : l'url du site que vous souhaitez requêter
- userAgent : l'userAgent de l'utilisateur actuel, ou, si vous ne le fournissez pas, un userAgent par défaut sera utilisé
L'objet WebPageMetaData contient :
- Le titre de la page : getTitle()
- La description de la page : getDescription()
- L'url de la page (On récupère l'url canonical si elle est exposée via une metadata dans la source du site) : getUrl()
- La main image (L'image mis en avant par la page courante) : getMainImage()
- Les autres images (On privilégie les images des balises <article> et <main> du code source) : getImagesUrl()
Javadoc :
2. Outils
2.1 Générateur de types
Le générateur de type produit désormais des classes Java supportant l'évolution de schéma avec des type primitif sur les publications stockées en base.
Ainsi, si on ajoute un champ entier ou booléen sur un type de publication stocké en base, les anciennes valeurs seront automatiquement rechargées (et réenregistrés) avec la valeur par défaut du champ.
Il n'est donc plus nécessaire de passer des requêtes SQL pour les montées de version lorsqu'un champ primitif a été ajoutée à une type stocké en base.
2.2 Mise à jour des JAR
Une rationalisation des JAR utilisés par la plateforme et ses modules a été effectuée (normalisation des versions de librairies, résolution des conflits entre modules, ...).
Une procédure automatique de recherche de vulnérabilité sur les JAR embarqués par JPlatform (et ses modules) a été mise en oeuvre et de nombreux jars ont été mis à jour avec les versions plus récentes non vulnérables.
2.3 POM
Pour permettre des mises à jour plus fréquentes des librairies Java externes (jar
) et garantir une parfaite cohérence de ces librairies entre le coeur et tous les modules, Maven a été mis en oeuvre dans le système de build de JPlatform 10 (actuellement uniquement pour la gestion des dépendances entre le coeur et les modules).
Pour cela, un pom parent commun au coeur et à tous les modules a été créé, c'est lui qui assure la cohérence de version de toutes les librairies.
Une version publique de ce fichier pom.xml
est mis à disposition des intégrateurs et clients afin qu'ils puissent proposer des modules garantissant leur bonne intégration dans JPlatform (et ses modules) : JPlatform 10.0.0 - pom.xml
2.4 Lucene 6
La librairie Lucene a été mise à jour vers la version 6.4.2.
Des configurations simplifiées et nouveaux hook pour développements spécifiques sont disponibles.
2.4.1 Configuration
Les moteurs de recherche lucene des Publications, des Membres, ou des Catégories, peuvent désormais être personnalisés par simple configuration.
- Des fichiers XML permettent de paramétrer le comportement d'indexation et de recherche de lucene.
- Des propriétés JCMS exposent certains paramétrages spécifiques à l'intégration de lucene dans JPlatform
Configuration XML
L'initialisation de chaque moteur de recherche se fait à partir du premier fichier XML valide identifié, en privilégiant dans l'ordre :
WEB-INF/data/lucene-{Publication|Member|Category}.xml
:
c'est ce fichier que vous créerez pour personnaliser la configuration- Puis les configurations standard fourni par Jalios (à ne pas modifier)
WEB-INF/jalios/lucene/lucene-{Publication|Member|Category}.xml
WEB-INF/jalios/lucene/lucene.xml
Le format de ce fichier XML est proche de celui du fichier schema.xml
de Apache SOLR, sans toutefois proposer les mêmes fonctionnalités.
Il permet de spécifier les classes lucene à utiliser et leur configuration :
- (requis) un
Analyzer
pour les traitements d'analyse lors de l'indexation et de la recherche, comprenant :- zero ou plus
CharFilter
- un
Tokenizer
- zero ou plus
Filter
- zero ou plus
- (optionnel) la classe
Similary
à utiliser pour le comportement de calcul de score lucene
Pour cela, le fichier utilise le format suivant :
<?xml version="1.0" encoding="UTF-8" ?> <lucene> <analyzer> <charFilter name="..." ... attribute1="value1" attribute2="value2"/> <tokenizer name="..." /> <filter name="..." /> </analyzer> <similarity class="..."/> </lucene>
Les CharFilter
, Tokenizer
et Filter
sont chargés grâce à la classe CustomAnalyzer
- ils peuvent être spécifiés
- par leur nom (SPI names), avec l'attribut
name
Quelques exemples (non exhaustifs) disponibles dans lucene :CharFilter
: htmlstrip, mapping, persian, patternreplaceTokenizer
: keyword, letter, lowercase, whitespace, edgengram, ngram, pathhierarchy, pattern, classic, standard, uax29urlemail, wikipediaTokenFilters
: apostrophe, decimaldigit, lowercase, stop, type, uppercase, englishminimalstem, englishpossessive, porterstem, frenchlightstem, frenchminimalstem, asciifolding, capitalization, codepointcount, daterecognizer, fingerprint, hyphenatedwords, keepword, keywordmarker, keywordrepeat, length, limittokencount, limittokenoffset, limittokenposition, removeduplicates, stemmeroverride, trim, truncate, worddelimiter, edgengram, ngram, patternreplace, patterncapturegroup, reversestring, shingle, snowballporter, classic, standard, synonym, elision, suggeststop
- par le nom complet (FQDN) de la
Factory
permettant de les créer, avec l'attributclass
,
- par leur nom (SPI names), avec l'attribut
- les autres attributs XML sont utilisés comme paramètres des factory
- les valeurs de chemins de fichiers spécifiés en attributs sont relatif au répertoire
WEB-INF/
de la webapp
La Similarity
à utiliser peut être renseignée en spécifiant le FQDN de la classe dans l'attribut class
.
Consultez les fichiers WEB-INF/jalios/lucene/lucene.xml
et WEB-INF/jalios/lucene/lucene-Member.xml
fournis en standard pour 2 exemples de configuration.
Notez également l'existence de la classe LoggingFilterFactory pouvant être utilisée pour diagnostiquer le processus d'analyse en activant les logs de niveau TRACE
sur la classe com.jalios.jcms.search.analysis.LoggingFilter
(dans la configuration log4j).
Exemple :
<?xml version="1.0" encoding="UTF-8" ?> <lucene> <analyzer> <tokenizer name="classic" maxTokenLength="255"/> <filter class="com.jalios.jcms.search.analysis.LoggingFilterFactory" prefix="in" /> <filter name="lowercase" /> <filter class="com.jalios.jcms.search.analysis.LoggingFilterFactory" prefix=" after lowercase" /> <filter name="classic" /> <filter class="com.jalios.jcms.search.analysis.LoggingFilterFactory" prefix=" after classic" /> </analyzer> <similarity class="org.apache.lucene.search.similarities.BM25Similarity"/> </lucene>
Propriétés de configuration
Des nouvelles propriétés permettent de configurer le nombre maximum de résultat récupérés par lucene à chaque requete :
query.lucene.mbr.max-results: 2000 query.lucene.cat.max-results: 100 query.lucene.pub.max-results: 100 query.lucene.archive.max-results: 100
2.4.2 Développements
Recherche
Une nouvelle méthode LuceneSearchEnginePolicyFilter#parseQuery(String, ParseOptions, Analyzer, Query)
permet d'intervenir lors de chaque recherche utilisateur pour construire l'objet lucene Query
.
Ce hook remplace custom.LuceneSearchEnginePolicy.parse(String, ParseOptions, Analyzer)
et les méthodes associées.
En l'absence de développement spécifique, le traitement est assuré par la classe com.jalios.jcms.search.queryparser.DefaultQueryParser.parse(String, ParseOptions, Analyzer)
Migration
Les développements précédement effectués dans LuceneSearchEnginePolicy
doivent être adaptés
- Les personnalisations du processus d'analyse, généralement effectuées dans l'ancienne classe
custom.LuceneSearchEnginePolicy.CustomAnalyzer
pour personnaliser lesTokenizer
etTokenFilter
se font désormais par configuration XML comme évoqué ci-dessus
Afin de conserver un comportement isofonctionnel par rapport à JCMS 9, les développements coeur ont été migrés de la façon suivante : ,- L'ancienne TokenFilter
ISOLatin1AccentFilter
a été remplacée par l'utilisation du MappingCharFilter avec le fichier texteWEB-INF/jalios/lucene/mapping-FoldToASCII.txt
fourni en standard - L'ancienne TokenFilter
ApostropheFilter
a été remplacé par l'utilisation du ElisionFilter avec le fichierWEB-INF/jalios/lucene/french-articles.txt
fourni en standard - Les classes
DashFilter
etUnderscoreFilter
ont été remplacé par le développement d'unTokenizer
spécifique à Jcms : le JcmsTokenizer.
Ce Tokenizer est une modification de l'implémentation standard du ClassicTokenizer lucene et de sa grammaire ClassicTokenizerImpl.jflex pour y ajouter des règles de découpage spécifique. - Le nouveau TokenFilter
ContextualStopFilterFactory
permet d'appliquer desStopFilter
en utilisant la langue courante d'analyse (que ça soit pour l'indexation ou la recherche).
- L'ancienne TokenFilter
- Les personnalisations du processus de recherche (précédemment dans
LuceneSearchEnginePolicy.parse
) doivent être migrés vers une LuceneSearchEnginePolicyFilter.parseQuery
2.5 Activation et désactivation de modules à chaud
2.5.1 Cycle de vie d'un module
Jusqu'à JCMS 9 les différents états d'un module étaient :
- Déposé:
- le zip du module est présent mais il n'a pas été déployé
- Arrêté :
- Le module est déployé
- L'une de ces 2 conditions est vérifiée
- Dans plugin.xml init="false"
- Le module a généré des erreurs au démarrage
- Démarré
- Le module est déployé
- Dans plugin.xml init="true"
- Le module n'a pas généré d'erreurs au démarrage
Avec JPlatform 10 les états d'un module sont :
- Déposé:
- idem
- Arrêté :
- idem
- Chargé
- Le module est déployé
- Dans plugin.xml init="true"
- Le module n'a pas généré d'erreurs au démarrage
- Et le module est désactivé
- Actif
Idem chargé mais le module n'est pas désactivé
2.5.2 Propriété d'activation / désactivation de module
L'activation ou la désactivation de module est matérialisée par une propriété de la forme :
plugin.<PLUGIN_NAME>.enabled: true/false
Exemple :
plugin.JReadingPlugin.enabled: false plugin.JTaskPlugin.enabled: true
Si la propriété est absente pour un module, le module est considéré comme activé.
2.5.3 Gestion des composants
Les composants représente l'ensemble des points de débranchement que peut fournir un module :
- StoreListener
- DBListener
- DataController
- ChannelListener
- QueryFilter
- CleanFilter
- AuthenticationHandler
- RightPolicyFilter
- AlarmListener
- JSyncListener
Par extension on inclus aussi dans les composants
- Les resources Open API
- Les templates
Ces composants sont branchés au démarrage de JPlatform pour tous les modules actifs.
Lorsqu'un module est activé à chaud, la méthode ChannelListener.initAfterStoreLoad() est appelé pour chacun de ses ChannelListeners.
Note : les resources Open API ne seront activées/désactivées à chaud qu'à partir de JPlatform 10 SP1 ou avec l'application du patch https://issues.jalios.com/browse/JCMS-6227
2.5.4 Gestion des propriétés du modules
Les propriétés d'un module ne sont chargés que si le module est actif à l'exception des propriétés de langues qui sont chargé même si le module est inactif.
A l'activation et à la désactivation d'un module on appelle donc, comme lors du démarrage, la méthode Channel.reloadProperties(
) qui rejoue l'ensemble des propriétés
2.5.5 Gestion des types
Jusqu'à JCMS 9, les types livrés par un module n'était pas différentié des types du coeur ou de l'application.
A partir de JPlatform 10, pour chaque type on peut connaitre le module qui l'a livré. L'information est accessible par la méthode TypeEntry.getPlugin()
.
Tous les types sont chargés ; même ceux des modules inactifs ou arrêtés. Cependant, seuls les types du coeur, de la webapp ou des modules actifs sont affichés dans les différentes interfaces.
2.5.6 Gestion des workflows
Jusqu'à JCMS 9, les workflows livrés par un module n'était pas différentié de ceux du coeur ou de l'application.
A partir de JPlatform 10, pour chaque workflow on peut connaitre le module qui l'a livré. L'information est accessible par la méthode Workflow.getPlugin()
.
Tous les workflows sont chargés ; même ceux des modules inactifs ou arrêtés. Cependant, seuls les workflows du coeur, de la webapp ou des modules actifs sont affichés dans les différentes interfaces.
2.5.7 Gestion des raccourcis (shortcut)
Les shortcuts sont des contenus qui sont créé au démarrage de JCMS par analyse des propriétés de modules.
La génération des shortcuts se basant sur les propriétés, si un module est inactifs, ses propriétés n'étant pas chargés, les éventuels shortcuts ne seront pas générés.
Lorsqu'on active un module à chaud, le ShortcutManager
est appelé pour générés les éventuels shortcut associés.
Lorsqu'un module est désactivé, le ShortcutManager
est appelé pour supprimer les éventuels shortcut associés.
2.5.8 Gestion des caches
Lors de l'activation ou la désactivation d'un module les données en cache peuvent devenir invalide. Aussi, à chaque activation/désactivation de module on supprime l'ensemble des entrées du CacheManager.
2.5.9 Gestion des dépendances
A partir de JPlatform 10 SP1, la gestion des dépendances est enrichi pour permettre d'avoir des dépendance sur des modules actifs (par défaut) ou désactivé. Pour chaque dépendance il est possible de préciser avec l'attribut active
que l'on dépend d'un module mais sans qu'il soit forcement actif (active="false"). Si l'attribut n'est pas renseigné alors c'est comme si il était à true
.
Exemple :
<dependencies> <dependency name="Plugin1" /> <!-- Same as active="true" --> <dependency name="Plugin2" active="true" /> <dependency name="Plugin3" active="false" /> </dependencies>
2.5.10 Blocage des JSP des modules
Afin d'empêcher l'accès aux JSP d'un module désactivé, on contrôle :
- L'accès aux URL (relatives) commençant par plugin/*.jsp
- Les inclusions de JSP commençant par plugin/ via l'attribut jsp des requêtes
Le contrôle est réalisé par la ServletFilter PluginAccessFilter
avec le mapping =/plugin/*=
Les JSP livré en dehors du répertoire plugin/NomDuPlugin/
ne sont pas contrôlées.
2.5.11 Limites
JSync
L'activation et la désactivation d'un module nécessite de mettre à jour une propriété. Par ailleurs le module durant son activation peu lui aussi générés des propriétés (eg virtual id d'un shortcut ou de données produites par un ChannelListener).
JSync n'offrant pas de support à la réplication des propriétés, si un module est activé sur un noeud il ne le serait pas sur les autres noeuds.
L'activation ou la désactivation d'un module sur un cluster JSync nécessite donc de l'activé sur le leader puis de recopier les propriétés générés sur l'ensemble des noeud du cluster.
ChannelListener::initBeforeStoreLoad()
Lors de l'activation d'un module à chaud la méthode ChannelListener::initBeforeStoreLoad() n'est pas appelée. Si elle doit être appelé alors il faut redémarrer JCMS une fois le module activé.
webapp-files
Si un module livre des webapp-files (p. ex. des patches) alors il ne seront pas désactivés
ServletFilter
L'activation/désactivation des modules ne prend pas en charge la déclaration des Servlet et ServletFilter. De même si un module est désactivé, cela ne désactive pas ses éventuelles ServletFilter. Le cas échéant, c'est au développeur de faire les contrôle d'activité du module dans les ServletFilter.
2.6 Authentification par certificat
Un nouveau mode d'authentification a été ajouté à JPlatform. Il s'agit de l'authentification par certificat SSL client.
Dans le cadre d'une communication SSL, si le client envoit un certificat valide, enfant direct d'une authorité référencé dans JPlatform et contenant le sujet adéquat, il sera alors authentifier sans avoir à fournir de mot de passe.
La description et l'installation de cette fonctionnalité est disponible dans la fiche Authentification par certificat client.
2.7 Compilateur LESS
Le compilateur LESS embarqué dans JPlatform 10 utilise une nouvelle librairie : less4j. Cette librairie gère des syntaxes LESS qui n'étaient pas supportées avec l'ancienne librairie (lesscss-engine).
Une nouvelle propriété a été ajoutée dans jcms.prop
pour permettre la génération des fichiers sourcemap
associés aux fichiers CSS générés : channel.less-compile.sourcemap
. Pour activer la génération des fichiers sourcemap
, il faut passer cette propriété à true
.