r1442 - in trunk: src/site/rst/user wikitty-api/src/main/java/org/nuiton/wikitty wikitty-api/src/main/java/org/nuiton/wikitty/entities wikitty-api/src/test/java/org/nuiton/wikitty wikitty-generators/src/main/java/org/nuiton/wikitty/generator
Author: bpoussin Date: 2012-03-05 20:01:08 +0100 (Mon, 05 Mar 2012) New Revision: 1442 Url: http://nuiton.org/repositories/revision/wikitty/1442 Log: Evolution #1988: Wikitty pre-loading field methode preload dans le client implantee et testee. Il faut maintenant pouvoir passer en paramettre des restore les patterns de restauration et utilise la methode preload dans le store et restore. Et ajouter dans les Entity metier genere et les Wikitty les methodes d'acces Modified: trunk/src/site/rst/user/generation.rst.vm trunk/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyClient.java trunk/wikitty-api/src/main/java/org/nuiton/wikitty/entities/Wikitty.java trunk/wikitty-api/src/main/java/org/nuiton/wikitty/entities/WikittyCopyOnWrite.java trunk/wikitty-api/src/main/java/org/nuiton/wikitty/entities/WikittyImpl.java trunk/wikitty-api/src/test/java/org/nuiton/wikitty/WikittyClientTest.java trunk/wikitty-generators/src/main/java/org/nuiton/wikitty/generator/WikittyTagValue.java Modified: trunk/src/site/rst/user/generation.rst.vm =================================================================== --- trunk/src/site/rst/user/generation.rst.vm 2012-03-05 18:57:02 UTC (rev 1441) +++ trunk/src/site/rst/user/generation.rst.vm 2012-03-05 19:01:08 UTC (rev 1442) @@ -181,3 +181,8 @@ Person,Employee;Company Ici il faut que l'objet ait les extensions Person et Employee ou l'extension Company + +:preload: s'applique au extension et indique les champs de type Wikitty qui + doivent etre preloade lors du chargement de cette extension. Par exemple:: + + preload="Company.employee,Employee.person;Company.address" Modified: trunk/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyClient.java =================================================================== --- trunk/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyClient.java 2012-03-05 18:57:02 UTC (rev 1441) +++ trunk/wikitty-api/src/main/java/org/nuiton/wikitty/WikittyClient.java 2012-03-05 19:01:08 UTC (rev 1442) @@ -35,24 +35,27 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; - +import java.util.regex.Pattern; import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang.StringUtils; +import org.apache.commons.lang3.StringUtils; import org.nuiton.util.ApplicationConfig; import org.nuiton.util.TimeLog; import org.nuiton.wikitty.entities.BusinessEntity; import org.nuiton.wikitty.entities.BusinessEntityImpl; import org.nuiton.wikitty.entities.ElementField; +import org.nuiton.wikitty.entities.FieldType; import org.nuiton.wikitty.entities.Wikitty; import org.nuiton.wikitty.entities.WikittyExtension; import org.nuiton.wikitty.entities.WikittyField; import org.nuiton.wikitty.entities.WikittyGroup; import org.nuiton.wikitty.entities.WikittyTokenHelper; +import org.nuiton.wikitty.entities.WikittyTypes; import org.nuiton.wikitty.entities.WikittyUser; import org.nuiton.wikitty.query.WikittyQuery; import org.nuiton.wikitty.query.WikittyQueryMaker; @@ -287,14 +290,8 @@ } } - // call the service with Wikitty - WikittyEvent resp = wikittyService.store(securityToken, wikitties); + storeWikitty(wikitties); - // update object - for (Wikitty w : wikitties) { - resp.update(w); - } - timeLog.log(start, "store<list>"); return objets; } @@ -320,7 +317,136 @@ // //////////////////////////////////////////////////////////////////////////// + protected Set<Wikitty> getWikittyForPreload(Map<String, Wikitty> available, + Wikitty w, FieldType type, String fqField) { + + Set<Wikitty> result = new HashSet<Wikitty>(); + + // contient tous les ids a recuperer + Set<String> ids = new HashSet<String>(); + if (type.isCollection()) { + ids.addAll((Collection)w.getFqField(fqField)); + } else { + ids.add((String)w.getFqField(fqField)); + } + + // on prend tout ce que l'on peut depuis available + Collection<String> availableIds = CollectionUtils.intersection(ids, available.keySet()); + for (String id : availableIds) { + result.add(available.get(id)); + } + + // et on on fait un restore sur les reste + ids.removeAll(availableIds); + Set<Wikitty> restored = restore(ids); + // on met les objets restore dans available pour la prochaine fois + for (Wikitty wikitty : restored) { + if (wikitty != null) { + available.put(wikitty.getId(), wikitty); + } + } + result.addAll(restored); + + return result; + } + /** + * Load one wikitty with specified preloadPattern (with only ','). + * + * @param w current wikitty to load + * @param available available wikitty (restored) + * @param loaded already loaded wikitties + field couple + * @param preloadPattern pattern used to load + * @return return w with preloaded link + */ + protected void preload(Wikitty w, Map<String, Wikitty> available, + Set<String> loaded, String preloadPattern) { + // s'il reste encore des champs a precharger + String pattern = StringUtils.substringBefore(preloadPattern, ","); + if (StringUtils.isNotBlank(pattern)) { + pattern = pattern.trim(); + // on enleve la tete qui va etre traitee maintenant, et le reste + // par recursion (nextPattern) + String nextPattern = StringUtils.substringAfter(preloadPattern, ","); + + String wid = w.getId(); + for (String fqField : w.fieldNames()) { + // si le couple wid + fqField n'a pas encore ete traite on le fait + if (!loaded.contains(wid + "+" + fqField)) { + FieldType type = w.getFieldType(fqField); + // si le champs est bien de type Wikitty et qu'il respecte + // le pattern demande, on le traite + if (type.getType() == WikittyTypes.WIKITTY + && Pattern.matches(pattern, fqField)) { + // on marque le champs comme ayant ete traite, vu qu'on + // est en cours (pour eviter les boucles infinies + // qui peuvent arriver si une extension declare un champs + // pointant sur lui meme + loaded.add(wid + "+" + fqField); + // on recupere le(s) wikitty(ies) du lien + Set<Wikitty> links = getWikittyForPreload(available, w, type, fqField); + for (Wikitty link : links) { + if (link != null) { + // on ajoute ce wikitty dans le preload du wikitty pere + w.addPreloaded(link); + // si le wikitty a pu etre recupere on fait la suite + // sur lui (nextPattern) + preload(link, available, loaded, nextPattern); + // et on preload aussi pour ses extensions + preload(link, available, loaded); + } + } + } + } + } + } + } + + /** + * Preload recursivement le wikitty, en fonction de sa chaine preloadPattern + * et des tags values des extensions qu'il a.. + * @param w le wikitty a precharger + * @param available la liste des wikitty deja disponible sans restore explicite + * @param loaded la liste de couple wid + fqfield deja traite + */ + protected void preload(Wikitty w, Map<String, Wikitty> available, + Set<String> loaded) { + for (String p : w.getAllPreloadPattern()) { + preload(w, available, loaded, p); + } + } + + /** + * Ajoute le preloadPattern comme chaine de preload dans chaque wikitty + * et fait le prechargement sur chaque wikitty. En sortie de methode les + * wikitty sont tous precharge comme souhaite. + * + * @param wikitties la liste des wikitties a precharger + * @param preloadPattern la liste des patterns de prechargement a faire + */ + public void preload(List<Wikitty> wikitties, String ... preloadPattern) { + String patterns = StringUtils.join(preloadPattern, ";"); + Map<String, Wikitty> available = new HashMap<String, Wikitty>(); + for (Wikitty w : wikitties) { + if (w != null) { + available.put(w.getId(), w); + if (StringUtils.isNotBlank(patterns)) { + // lorsqu'on apelle la methode pour le store, le preloadPattern + // est vide mais il ne faut pas perdre ce qu'il y avait avant + // dans le wikitty. Donc on ne fait le set que si patterns + // n'est pas vide + w.setPreloadPattern(patterns); + } + } + } + Set<String> loaded = new HashSet<String>(); + + for (Wikitty w : wikitties) { + preload(w, available, loaded); + } + } + + /** * Restore wikitty entity with specified id or {@code null} if entity can't be be found. * * @param id entity ids if null return is empty list @@ -375,7 +501,7 @@ List<E> result = new ArrayList<E>(); if (id != null) { - List<Wikitty> wikitties = wikittyService.restore(securityToken, id); + List<Wikitty> wikitties = restore(id); Collection<String> businessExtension = null; if (checkExtension) { Modified: trunk/wikitty-api/src/main/java/org/nuiton/wikitty/entities/Wikitty.java =================================================================== --- trunk/wikitty-api/src/main/java/org/nuiton/wikitty/entities/Wikitty.java 2012-03-05 18:57:02 UTC (rev 1441) +++ trunk/wikitty-api/src/main/java/org/nuiton/wikitty/entities/Wikitty.java 2012-03-05 19:01:08 UTC (rev 1442) @@ -29,9 +29,12 @@ import java.math.BigDecimal; import java.util.Collection; import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import org.nuiton.wikitty.generator.WikittyTagValue; /** * Wikitty object, containing data as map. @@ -77,6 +80,48 @@ PropertyChangeListener listener); /** + * Retourne le pattern de preload demande lors du restore ou null si aucun + * preload n'a ete demande. + * @return + */ + String getPreloadPattern(); + + /** + * Modifie le pattern de preload + * @param preloadPattern un nouveau pattern ou null + */ + void setPreloadPattern(String preloadPattern); + + /** + * Retourne tous les patterns de preload, celui demande lors du restore et + * tout ceux defini par le tag value 'preload' sur les extensions. La + * Collection contient une liste de chaine qui n'ont comme separateur que + * des ','. Car chaque separateur ';' donne une entre differente dans la + * collection. + * @return Collection with pattern or empty collection if no pattern + */ + Set<String> getAllPreloadPattern(); + + /** + * Retourne la map des wikitties precharges, si aucun objet n'est precharge + * alors retourne une map vide. La collection retournee est non modifiable. + * @return Retourne toujours une map au pire elle est vide + */ + Map<String, Wikitty> getPreloaded(); + + /** + * Modifie la liste des wikitties prechargee + * @param preloaded + */ + void setPreloaded(Map<String, Wikitty> preloaded); + + /** + * Ajoute un wikitty comme preloaded dans la liste des wikitties prechargee. + * @param w le wikitty a ajouter + */ + void addPreloaded(Wikitty w); + + /** * Replace all field of current wikitty with field found in w. * This two wikitty must have same id. * Modified: trunk/wikitty-api/src/main/java/org/nuiton/wikitty/entities/WikittyCopyOnWrite.java =================================================================== --- trunk/wikitty-api/src/main/java/org/nuiton/wikitty/entities/WikittyCopyOnWrite.java 2012-03-05 18:57:02 UTC (rev 1441) +++ trunk/wikitty-api/src/main/java/org/nuiton/wikitty/entities/WikittyCopyOnWrite.java 2012-03-05 19:01:08 UTC (rev 1442) @@ -27,7 +27,10 @@ import java.beans.PropertyChangeListener; import java.math.BigDecimal; import java.util.Collection; +import java.util.Collections; import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -36,6 +39,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuiton.wikitty.WikittyException; +import org.nuiton.wikitty.generator.WikittyTagValue; /** this class wrap a wikitty in a proxy that copy the wikitty before applying any change * @@ -66,6 +70,45 @@ } @Override + public String getPreloadPattern() { + return target.getPreloadPattern(); + } + + @Override + public void setPreloadPattern(String preloadPattern) { + if (!ObjectUtils.equals(preloadPattern, getPreloadPattern())) { + substituteTargetWithCopy(); + target.setPreloadPattern(preloadPattern); + } + } + + @Override + public Set<String> getAllPreloadPattern() { + return target.getAllPreloadPattern(); + } + + @Override + public Map<String, Wikitty> getPreloaded() { + return target.getPreloaded(); + } + + @Override + public void setPreloaded(Map<String, Wikitty> preloaded) { + substituteTargetWithCopy(); + target.setPreloaded(preloaded); + } + + @Override + public void addPreloaded(Wikitty w) { + if (w != null) { + if (!getPreloaded().containsKey(w.getId())) { + substituteTargetWithCopy(); + target.addPreloaded(w); + } + } + } + + @Override public void replaceWith(Wikitty w) { replaceWith(w, false); } Modified: trunk/wikitty-api/src/main/java/org/nuiton/wikitty/entities/WikittyImpl.java =================================================================== --- trunk/wikitty-api/src/main/java/org/nuiton/wikitty/entities/WikittyImpl.java 2012-03-05 18:57:02 UTC (rev 1441) +++ trunk/wikitty-api/src/main/java/org/nuiton/wikitty/entities/WikittyImpl.java 2012-03-05 19:01:08 UTC (rev 1442) @@ -31,6 +31,7 @@ import java.util.AbstractList; import java.util.AbstractSet; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -102,8 +103,22 @@ */ protected Map<String, WikittyExtension> extensions = new LinkedHashMap<String, WikittyExtension>(); - + + /** + * Pattern de prechargement demande par l'utilisateur lors de la restauration + * du wikitty. Peut-etre null si aucun prechargement n'est demande. + */ + protected String preloadPattern; + /** + * Ensemble des liens vers des Wikitty precharge. Cette map peut-etre null + * si aucun prechargement n'existe. + * <li> key: wikitty id + * <li> value: wikitty + */ + // poussin 20120305 peut-etre mettre transient le champs ? a voir a l'usage + protected Map<String, Wikitty> preloaded; + public WikittyImpl() { this(null); } @@ -116,6 +131,63 @@ } } + @Override + public String getPreloadPattern() { + return preloadPattern; + } + + @Override + public void setPreloadPattern(String preloadPattern) { + this.preloadPattern = preloadPattern; + } + + @Override + public Set<String> getAllPreloadPattern() { + Set<String> result = new HashSet<String>(); + String[] preloadPatterns = StringUtils.split(getPreloadPattern(), ";"); + if (preloadPatterns != null) { + result.addAll(Arrays.asList(preloadPatterns)); + } + + for (WikittyExtension ext : getExtensions()) { + preloadPatterns = StringUtils.split( + ext.getTagValue(WikittyTagValue.TAG_PRELOAD), ";"); + if (preloadPatterns != null) { + result.addAll(Arrays.asList(preloadPatterns)); + } + } + result.remove(null); + return result; + } + + @Override + public Map<String, Wikitty> getPreloaded() { + if (preloaded == null) { + preloaded = new HashMap<String, Wikitty>(); + } + return Collections.unmodifiableMap(preloaded); + } + + @Override + public void setPreloaded(Map<String, Wikitty> preloaded) { + // on fait une copie et on la rend non modifiable. + Map<String, Wikitty> map = new HashMap<String, Wikitty>(); + if (preloaded != null) { + map.putAll(preloaded); + } + this.preloaded = map; + } + + @Override + public void addPreloaded(Wikitty w) { + if (w != null) { + if (preloaded == null) { + preloaded = new HashMap<String, Wikitty>(); + } + this.preloaded.put(w.getId(), w); + } + } + /** * Replace all field of current wikitty with field found in w. * This two wikitty must have same id. @@ -149,6 +221,17 @@ replaceWith(((WikittyCopyOnWrite)w).getTarget(), force); } if (force || this.getId().equals(w.getId())) { + // poussin 20120305 quid des listeners ? ne faudrait-il pas les copier aussi ? + // mais si on les copie, comment l'utilisateur sera-t-il qu'il faut les supprimer + // ne risque t-il pas d'y avoir des listeners recevant trop de notification. + // le plus simple est donc pour l'instant de ne pas copier les listeners, a la + // charge du developpeur d'appli, lorsqu'il fait un clone de remettre les listeners + // qu'il souhaite + + // copy preload (not in deep copy mode) + this.setPreloaded(w.getPreloaded()); + this.setPreloadPattern(w.getPreloadPattern()); + this.extensions.clear(); this.fieldValue.clear(); for (WikittyExtension ext : w.getExtensions()) { Modified: trunk/wikitty-api/src/test/java/org/nuiton/wikitty/WikittyClientTest.java =================================================================== --- trunk/wikitty-api/src/test/java/org/nuiton/wikitty/WikittyClientTest.java 2012-03-05 18:57:02 UTC (rev 1441) +++ trunk/wikitty-api/src/test/java/org/nuiton/wikitty/WikittyClientTest.java 2012-03-05 19:01:08 UTC (rev 1442) @@ -49,6 +49,7 @@ import org.nuiton.wikitty.entities.ElementField; import org.nuiton.wikitty.entities.ExtensionFactory; import org.nuiton.wikitty.entities.Wikitty; +import org.nuiton.wikitty.entities.WikittyAuthorisationImpl; import org.nuiton.wikitty.entities.WikittyExtension; import org.nuiton.wikitty.entities.WikittyGroup; import org.nuiton.wikitty.entities.WikittyGroupImpl; @@ -2414,4 +2415,69 @@ Assert.assertTrue(true); } } + + @Test + public void testPreloadSimple() throws Exception { + WikittyUserImpl user = new WikittyUserImpl(); + user.setLogin("moi"); + + WikittyAuthorisationImpl auth = new WikittyAuthorisationImpl(); + auth.setOwner(user.getWikittyId()); + wikittyClient.store(user, auth); + + Wikitty authRestored = wikittyClient.restore(auth.getWikittyId()); + Assert.assertNull(authRestored.getPreloaded().get(user.getWikittyId())); + + wikittyClient.preload(Arrays.asList(authRestored), "WikittyAuthorisation.owner"); + Assert.assertNotNull(authRestored.getPreloaded().get(user.getWikittyId())); + } + + @Test + public void testPreloadBoucle() throws Exception { + WikittyUserImpl user = new WikittyUserImpl(); + user.setLogin("moi"); + + WikittyAuthorisationImpl auth = new WikittyAuthorisationImpl(); + auth.setOwner(user.getWikittyId()); + auth.setParent(auth.getWikittyId()); + + wikittyClient.store(auth, user); + + Wikitty authRestored = wikittyClient.restore(auth.getWikittyId()); + Assert.assertNull(authRestored.getPreloaded().get(user.getWikittyId())); + + wikittyClient.preload(Arrays.asList(authRestored), "WikittyAuthorisation.parent,WikittyAuthorisation.parent,WikittyAuthorisation.owner"); + // parent doit avoir ete restorer + Assert.assertNotNull(authRestored.getPreloaded().get(auth.getWikittyId())); + // mais owner non, car on le demande apres deux fois parent et vu que + // parent a deja ete traiter vu qu'on boucle sur nous meme, owner ne + // sera pas preloade (comportement normale) + Assert.assertNull(authRestored.getPreloaded().get(user.getWikittyId())); + } + + @Test + public void testPreloadCollection() throws Exception { + WikittyLabelImpl l1 = new WikittyLabelImpl(); + l1.addLabels("l1"); + WikittyLabelImpl l2 = new WikittyLabelImpl(); + l2.addLabels("l2"); + WikittyLabelImpl l3 = new WikittyLabelImpl(); + l3.addLabels("l3"); + + WikittyGroupImpl group = new WikittyGroupImpl(); + group.addMembers(l1.getWikittyId(), l2.getWikittyId(), l3.getWikittyId()); + + wikittyClient.store(group, l1, l2, l3); + + Wikitty groupRestored = wikittyClient.restore(group.getWikittyId()); + Assert.assertNull(groupRestored.getPreloaded().get(l1.getWikittyId())); + Assert.assertNull(groupRestored.getPreloaded().get(l2.getWikittyId())); + Assert.assertNull(groupRestored.getPreloaded().get(l3.getWikittyId())); + + wikittyClient.preload(Arrays.asList(groupRestored), "WikittyGroup.members"); + Assert.assertNotNull(groupRestored.getPreloaded().get(l1.getWikittyId())); + Assert.assertNotNull(groupRestored.getPreloaded().get(l2.getWikittyId())); + Assert.assertNotNull(groupRestored.getPreloaded().get(l3.getWikittyId())); + + } } Modified: trunk/wikitty-generators/src/main/java/org/nuiton/wikitty/generator/WikittyTagValue.java =================================================================== --- trunk/wikitty-generators/src/main/java/org/nuiton/wikitty/generator/WikittyTagValue.java 2012-03-05 18:57:02 UTC (rev 1441) +++ trunk/wikitty-generators/src/main/java/org/nuiton/wikitty/generator/WikittyTagValue.java 2012-03-05 19:01:08 UTC (rev 1442) @@ -123,4 +123,13 @@ */ public static final String TAG_EXTENSION_ALLOWED = "extensionAllowed"; + /** + * preload: indique les champs de type Wikitty qui doivent etre preloade + * lors du chargement de cette extension. + * exemple: + * <li> preload="Company.employee,Employee.person;Company.address" + * <p> + * <li> target: extension + */ + public static final String TAG_PRELOAD = "preload"; }
participants (1)
-
bpoussin@users.nuiton.org