JaliosXperience
fr en
Path > Home > Forums > French Forum
Link

Problème de clone, de temps en temps

Michel Remacle - on 1/17/12 at 11:10 AM

Bonjour,

Nous avons constaté un bug un peu bizarre dans jcms.

Explication : On a un type perso "document offre". Ce type contient titre, description et un file document. Le but? Ce document offre est accessible à certains groupes de travail uniquement et lorsqu'ils sauvent ce document offre, le file document référencé est automatiquement classé dans une catégorie et il se voit assigné des droits d'accès spécifiques (en l'occurence pour etre visible par tout le monde, sinon par défaut les file document nécessitent de s'identifier)

Bref, j'ai fait un datacontroller sur le type DocumentOffre qui fait ceci :

if (oData instanceof DocumentOffre){

DocumentOffre obj = (DocumentOffre)oData;

FileDocument clone = obj.getDocument();

clone = (FileDocument) clone.clone();

clone.addCategory(channel.getCategory("n5006"));_

clone.addAuthorizedGroup(channel.getGroup("c54552"));_

clone.performUpdate(channel.getDefaultAdmin());

}

Problème : Lorsqu'on veut créer un nouveau contenu de type document offre, on rempli le titre, la description, puis on doit choisir ou uploader un file document. Pour ce faire, JCMS génère un bouton "parcourir" ainsi qu'une icone avec une flèche verte vers le haut "déposer un document".

Selon qu'on clique sur "parcourir" ou "déposer un document", le résultat n'est pas le même! En effet, lorsqu'on clique sur "parcourir, les droits d'accès du document ne sont pas sauvé dans le store! Alors que si on clique sur "déposer un document" tout se passe comme attendu.

D'où vient cette différence?

Pour contourner le problème, on a du faire ceci dans le data controller :

if (oData instanceof DocumentOffre) {

DocumentOffre obj = (DocumentOffre)oData;

FileDocument clone = obj.getDocument();

clone = (FileDocument) clone.clone();

clone.addCategory(channel.getCategory("n5006"));_

TreeSet groups = new TreeSet();

groups.add(channel.getGroup("c54552"));_

clone.setAuthorizedGroupSet(groups);

clone.performUpdate(channel.getDefaultAdmin());

}

Merci de regarder,

Michel

Ronan Kerdudou - on 1/26/12 at 12:07 PM

Bonjour,

avec quelle version de JCMS travaillez vous ?

Cordialement, Ronan

Rudi Verwimp - on 1/26/12 at 12:26 PM

Bonjour, Nous travaillons en JCMS 7.0.1.

Bien à vous.

Rudi

Ronan Kerdudou - on 1/26/12 at 3:46 PM

Le code de votre contournement force le remplacement du treeSet, donc s'il corrige le problème c'est qu'un objet garde une référence au treeSet avant et le vide après ??? c'est étonnant...

dans votre datacontroler vous vous positionnez en before ou en after write ?

pour la différence entre le "parcourir" et le "déposer" je suppose que c'est lié au moment de création des objets fileDocument... (bien avant avec "déposer" et en même temps pour "parcourir")

J'ai créé un ticket 3234 pour le suivi au support. Si vous pouvez nous fournir un war de reproduction du bug sur le site private.jalios.com, nous pourrons l'étudier plus rapidement.

Ronan Kerdudou - on 1/26/12 at 3:54 PM

Au passage je me permet de vous recommander une structure :

Publication clone = (Publication) pub.getUpdateInstance();
//do something to the clone
ControllerStatus status = clone.checkUpdate(loggedMember);
if (!status.hasFailed()){
  clone.performUpdate(loggedMember);
} else {
  //treat publication failure
  logger.info(status.getMessage(channel.getLanguage()));
}

Rudi Verwimp - on 1/26/12 at 4:53 PM

C'est dans l'AfterWrite dans le fichier dans WEB-INF/classes/PluginCHU/DataControllerDocumentOffre.java

la webapp CHU est déposée sur sur mon compte private.

Ronan Kerdudou - on 1/27/12 at 4:17 PM

J'ai pu reproduire votre problème.

Vous avez sans doute remarqué qu'en mémoire il était correct, seule l'écriture dans le store "oubliait" ce paramètre, et donc le problème n'était constatable fonctionnellement qu'au redémarrage du serveur. Ce point est important dans la détection du problème.

Comme je l'avait pré-senti, la différence entre "parcourir" et "déposer un document" est liée à la session d'écriture.
En effet, lorsque vous utilisez "parcourir" la création du document et la modification lors de l'after-write de votre objet sont réalisée dans une même session. Ainsi l'objet Java TreeSet "AuthorizedGroup" est enregistré lors de la création et détecté comme non-modifié lors de la mise à jour puisque l'instance "avant" et l'instance "après" sont identique (même objet java). Le fait de remplacer le TreeSet résous donc ce cas.

Le champ "Category" a l'avantage d'être un tableau et donc il change d'instance à chaque modification, c'est pourquoi il ne pose pas de problème.

De manière générale faire un "deep clone" d'un objet avant sa modification éviterai ce genre de problème, Afin de ne pas pénaliser les performances on ne clone que les objets qu'on modifie, en l’occurrence le TreeSet doit être cloné même si dans la plupart des cas le problème ne se pose pas.

En l'absence de clonage du treeSet, si jamais l'enregistrement était annulé, la modification persisterait en mémoire.

Dans le cas de l'utilisation du "déposer un document", lors de la modification du TreeSet, l'instance "avant" contient 'null' et l'appel à addAuthorizedGroup instancie un TreeSet, la modification du champ est donc détectée. Si à la place je sélectionne un document existant ayant déjà un AuthorizedGroup, on se retrouve à modifier le TreeSet initial et donc aucune modif ne sera enregistrée dans le store mais l'information persistera en mémoire.

Ce problème est justement la raison pour laquelle toute modification d'un objet du store doit toujours passer par un clone.
Pour conclure ici le cas particulier c'était quand ça marchait alors que le code était incorrect, votre contournement était le plus proche du code correct, il faut juste prévoir de récupérer le TreeSet pour le cas où il existerait.

le code correct est donc :

  if (oData instanceof DocumentOffre) {
    FileDocument cloneDocument = (FileDocument)((DocumentOffre)oData).getDocument().getUpdateInstance();
    
    cloneDocument.addCategory(channel.getCategory("n_5006"));
    
    TreeSet<Group> authorizedGroup = new TreeSet<Group>(cloneDocument.getAuthorizedGroupSet());
    authorizedGroup.add(channel.getGroup("c_54552"));
    cloneDocument.setAuthorizedGroupSet(authorizedGroup);
    
    ControllerStatus status = cloneDocument.checkUpdate(channel.getDefaultAdmin());
    if (!status.hasFailed()){  
      cloneDocument.performUpdate(channel.getDefaultAdmin());
    } else {
      logger.info(status.getMessage(channel.getLanguage()));  
    }
  }

J'espère que mes explication sont claire, n'hésitez pas si vous souhaitez plus de précision.

cordialement, Kerdudou Ronan.

Rudi Verwimp - on 2/1/12 at 3:27 PM

Merci pour votre réponse. Effectivement, à force de chercher, nous avions oublié de considérer le cas des groupes déjà choisis.

A bientôt.

Rudi

Login   Home   fr en
JALIOS SA - SIREN 440 126 035