Author: bpoussin Date: 2016-11-10 14:08:37 +0100 (Thu, 10 Nov 2016) New Revision: 4373 Url: http://forge.codelutin.com/projects/isis-fish/repository/revisions/4373 Log: enhance evolution #8737: Export / Import des ?\195?\169l?\195?\169ments d'une r?\195?\169gion, soit pour import dans une autre r?\195?\169gion, soit pour fusion de deux r?\195?\169gions. Modified: trunk/src/main/java/fr/ifremer/isisfish/entities/RegionImportJson.java trunk/src/main/java/fr/ifremer/isisfish/ui/input/InputHandler.java Modified: trunk/src/main/java/fr/ifremer/isisfish/entities/RegionImportJson.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/entities/RegionImportJson.java 2016-11-09 18:44:50 UTC (rev 4372) +++ trunk/src/main/java/fr/ifremer/isisfish/entities/RegionImportJson.java 2016-11-10 13:08:37 UTC (rev 4373) @@ -50,21 +50,71 @@ */ public class RegionImportJson { + /** + * Use during import to merge imported data in existing Region + */ static public interface RegionMerge { - static public enum AnwserType { - NONE, - REUSE, REUSE_ONE_TYPE, REUSE_ONE, - IMPORT, IMPORT_ALL_TYPE, IMPORT_ALL, + static public enum AnswerType { + NONE, REUSE, IMPORT, ABORT + }; + + static public class Answer { + public AnswerType type; + public TopiaEntity entity; + + public Answer(AnswerType type, TopiaEntity entity) { + this.type = type; + this.entity = entity; + } + + public boolean isAbort() { + return type == AnswerType.ABORT; + } + } + + /** + * Get last answer return by choice + * @return last answer return by previous call to choice + */ + public Answer getLastAnswer(); + + /** + * Ask how to merge entity + * @param id + * @param toString + * @param details + * @return + */ + public Answer choice(String id, String toString, Map<String, Object> details); + + /** + * If exist return entity in existing Region with id in parameter + * @param id + * @return null or TopiaEntity + */ + public TopiaEntity getEntity(String id); + } + + static public class RegionMergeDatabase implements RegionMerge { + static public enum ComplexeAnswerType { + NONE, NONE_THIS_TYPE, NONE_ALL, + REUSE, REUSE_THIS_TYPE, REUSE_ALL, + IMPORT, IMPORT_THIS_TYPE, IMPORT_ALL, ABORT }; + /** + * Object used to keep recurent answer (abort, import All, reuse All, ...) + */ static public class RegionMergeContext { protected boolean abort = false; - protected boolean reuseOne = false; - protected Set<Class> reuseOneType = new HashSet<Class>(); + protected boolean noneAll = false; + protected Set<Class> noneType = new HashSet<Class>(); + protected boolean reuseAll = false; + protected Set<Class> reuseType = new HashSet<Class>(); protected boolean importAll = false; - protected Set<Class> importAllType = new HashSet<Class>(); - protected AnwserType lastAnswer = null; + protected Set<Class> importType = new HashSet<Class>(); + protected AnswerType lastAnswer = null; protected TopiaEntity reuseEntity; protected Class currentType; @@ -75,66 +125,83 @@ this.importAll = importAll; } + public RegionMerge.Answer getAnswer() { + RegionMerge.Answer result = null; + if (lastAnswer != null) { + result = new RegionMerge.Answer(lastAnswer, reuseEntity); + } + return result; + } + public Class getCurrentType() { return currentType; } - public TopiaEntity getReuseEntity() { - return reuseEntity; - } - - public AnwserType getLastAnswer() { - return lastAnswer; - } - - protected void setLastAnswer(AnwserType lastAnswer) { + protected void setLastAnswer(ComplexeAnswerType lastAnswer) { this.setLastAnswer(lastAnswer, null); } - protected void setLastAnswer(AnwserType lastAnswer, TopiaEntity e) { - this.lastAnswer = lastAnswer; + protected void setLastAnswer(ComplexeAnswerType lastAnswer, TopiaEntity e) { this.reuseEntity = e; switch (lastAnswer) { + case NONE: + this.lastAnswer = AnswerType.NONE; + break; + case NONE_THIS_TYPE: + noneType.add(currentType); + this.lastAnswer = AnswerType.NONE; + break; + case NONE_ALL: + noneAll = true; + this.lastAnswer = AnswerType.NONE; + break; case ABORT: abort = true; + this.lastAnswer = AnswerType.ABORT; break; - case IMPORT_ALL_TYPE: - importAllType.add(currentType); - this.lastAnswer = AnwserType.IMPORT; + case IMPORT: + this.lastAnswer = AnswerType.IMPORT; break; + case IMPORT_THIS_TYPE: + importType.add(currentType); + this.lastAnswer = AnswerType.IMPORT; + break; case IMPORT_ALL: importAll = true; - this.lastAnswer = AnwserType.IMPORT; + this.lastAnswer = AnswerType.IMPORT; break; - case REUSE_ONE_TYPE: - reuseOneType.add(currentType); - this.lastAnswer = AnwserType.REUSE; + case REUSE: + this.lastAnswer = AnswerType.REUSE; break; - case REUSE_ONE: - reuseOne = true; - this.lastAnswer = AnwserType.REUSE; + case REUSE_THIS_TYPE: + reuseType.add(currentType); + this.lastAnswer = AnswerType.REUSE; break; - default: + case REUSE_ALL: + reuseAll = true; + this.lastAnswer = AnswerType.REUSE; break; } } - public AnwserType initAnswer(Class type) { + public AnswerType initAnswer(Class type) { lastAnswer = null; currentType = type; if (abort) { - lastAnswer = AnwserType.ABORT; - } else if (importAll || importAllType.contains(type)) { - lastAnswer = AnwserType.IMPORT; + lastAnswer = AnswerType.ABORT; + } else if (noneAll || noneType.contains(type)) { + lastAnswer = AnswerType.NONE; + } else if (importAll || importType.contains(type)) { + lastAnswer = AnswerType.IMPORT; } return lastAnswer; } - public AnwserType initAnswer(Class type, Set<TopiaEntity> possible) { + public AnswerType initAnswer(Class type, Set<TopiaEntity> possible) { lastAnswer = null; currentType = type; - if (possible != null && possible.size() == 1 && (reuseOne || reuseOneType.contains(type))) { - lastAnswer = AnwserType.REUSE; + if (possible != null && possible.size() == 1 && (reuseAll || reuseType.contains(type))) { + lastAnswer = AnswerType.REUSE; this.reuseEntity = possible.iterator().next(); } return lastAnswer; @@ -141,25 +208,10 @@ } } - /** - * Ask how to merge entity - * @param context - * @param id - * @param toString - * @param details - * @return - */ - public RegionMergeContext choice(RegionMergeContext context, String id, String toString, Map<String, Object> details); - /** - * If exist return entity with id in parameter - * @param id - * @return null or TopiaEntity - */ - public TopiaEntity getEntity(String id); - } - static public class RegionMergeDatabase implements RegionMerge { protected TopiaContext tx; + protected RegionMergeContext context; + protected Answer lastAnswer; public RegionMergeDatabase(TopiaContext tx) { this.tx = tx; @@ -166,6 +218,11 @@ } @Override + public Answer getLastAnswer() { + return lastAnswer; + } + + @Override public TopiaEntity getEntity(String id) { TopiaEntity result = tx.findByTopiaId(id); return result; @@ -172,65 +229,58 @@ } @Override - public RegionMergeContext choice(RegionMergeContext context, String id, String toString, Map<String, Object> details) { + public Answer choice(String id, String toString, Map<String, Object> details) { Class type = TopiaId.getClassName(id); if (context == null) { context = new RegionMergeContext(); - } else { - context.initAnswer(type); } - if (context.lastAnswer != null) { - return context; - } + if (context.initAnswer(type) == null) { + TopiaDAO<TopiaEntity> dao = IsisFishDAOHelper.getDAO(tx, type); - TopiaDAO<TopiaEntity> dao = IsisFishDAOHelper.getDAO(tx, type); + LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); - LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); - - possible.add(dao.findByTopiaId(id)); - if (Equation.class.isAssignableFrom(context.getCurrentType())) { - if (details.containsKey("name") && details.containsKey("category")) { - possible.addAll(dao.findAllByProperties("name", details.get("name"), "category", details.get("category"))); + possible.add(dao.findByTopiaId(id)); + if (Equation.class.isAssignableFrom(context.getCurrentType())) { + if (details.containsKey("name") && details.containsKey("category")) { + possible.addAll(dao.findAllByProperties("name", details.get("name"), "category", details.get("category"))); + } + } else { + if (details.containsKey("name")) { + possible.addAll(dao.findAllByProperty("name", details.get("name"))); + } } - } else { - if (details.containsKey("name")) { - possible.addAll(dao.findAllByProperty("name", details.get("name"))); - } - } - context.initAnswer(type, possible); - - if (context.lastAnswer != null) { - return context; - } + if (context.initAnswer(type, possible) == null) { + if (Equation.class.isAssignableFrom(context.getCurrentType())) { + if (details.containsKey("category")) { + possible.addAll(dao.findAllByProperty("category", details.get("category"))); + } + } else { + possible.addAll(dao.findAll()); + } - if (Equation.class.isAssignableFrom(context.getCurrentType())) { - if (details.containsKey("category")) { - possible.addAll(dao.findAllByProperty("category", details.get("category"))); + ask(context, toString, details, possible); } - } else { - possible.addAll(dao.findAll()); } - ask(context, toString, details, possible); - - return context; + return lastAnswer = context.getAnswer(); } protected void ask(RegionMergeContext context, String toString, Map<String, Object> details, Collection<TopiaEntity> possible) { - System.out.println("Choice between:" + toString + " and " + possible); JComboBox select = new JComboBox(possible.toArray()); Object[] options = new Object[] { "None", // for null + "None same type", // for null + "None all", // for null "Reuse selected object", - "Reuse if only one (same type)", - "Reuse if only one (all type)", + "Reuse same type", + "Reuse all", "Import", - "Import All this type", + "Import same type", "Import All", "Abort" }; @@ -242,15 +292,17 @@ ClassUtils.getShortClassName(context.getCurrentType())), "", "Possible answer are:", - "None: don't import nor reuse object", + "None: don't import nor reuse an object.", + "None same type: auto response None for this answer and all next answer for same object type.", + "None all: auto response None for this answer and all next answer for all object type.", "Reuse: use object already in current Region (make your choice in next combobox).", select, - "Reuse if only one (same type): Answer Reuse and for next time use object found in current Region if only one match 'id' or 'name' for this type", - "Reuse if only one (all type): Answer Reuse and for next time use object found in current Region if only one match 'id' or 'name' for all object", + "Reuse same type: auto response Reuse for this answer and all next answer if only one object found ('id' or 'name') in current Region for this type.", + "Reuse all: auto response Reuse for this answer and all next answer if only one object found ('id' or 'name') in current Region for all object.", "Import: import object from file.", - "Import All this type: auto answer Import for this question and all next question for same object type", - "Import All: auto answer Import for this question and all next question.", - "Abort: Cancel this import (import nothing)" + "Import same type: auto response Import for this answer and all next answer for same object type.", + "Import All: auto response Import for this answer and all next answer for all object.", + "Abort: Cancel this import (import nothing)." }, "Make a choice", JOptionPane.DEFAULT_OPTION, @@ -262,29 +314,35 @@ TopiaEntity selectEntity = (TopiaEntity)select.getSelectedItem(); switch (result) { case 0: - context.setLastAnswer(AnwserType.NONE); + context.setLastAnswer(ComplexeAnswerType.NONE); break; case 1: - context.setLastAnswer(AnwserType.REUSE, selectEntity); + context.setLastAnswer(ComplexeAnswerType.NONE_THIS_TYPE); break; case 2: - context.setLastAnswer(AnwserType.REUSE_ONE_TYPE, selectEntity); + context.setLastAnswer(ComplexeAnswerType.NONE_ALL); break; case 3: - context.setLastAnswer(AnwserType.REUSE_ONE, selectEntity); + context.setLastAnswer(ComplexeAnswerType.REUSE, selectEntity); break; case 4: - context.setLastAnswer(AnwserType.IMPORT); + context.setLastAnswer(ComplexeAnswerType.REUSE_THIS_TYPE, selectEntity); break; case 5: - context.setLastAnswer(AnwserType.IMPORT_ALL_TYPE); + context.setLastAnswer(ComplexeAnswerType.REUSE_ALL, selectEntity); break; case 6: - context.setLastAnswer(AnwserType.IMPORT_ALL); + context.setLastAnswer(ComplexeAnswerType.IMPORT); break; case 7: - context.setLastAnswer(AnwserType.ABORT); + context.setLastAnswer(ComplexeAnswerType.IMPORT_THIS_TYPE); break; + case 8: + context.setLastAnswer(ComplexeAnswerType.IMPORT_ALL); + break; + case 9: + context.setLastAnswer(ComplexeAnswerType.ABORT); + break; default: ask(context, toString, details, possible); break; @@ -293,18 +351,22 @@ } static public class RegionMergeImportAll implements RegionMerge { + protected Answer lastAnswer; + @Override + public Answer getLastAnswer() { + return lastAnswer; + } + + + @Override public TopiaEntity getEntity(String id) { return null; } @Override - public RegionMergeContext choice(RegionMergeContext context, String id, String toString, Map<String, Object> details) { - if (context == null) { - context = new RegionMergeContext(); - } - context.setLastAnswer(AnwserType.IMPORT); - return context; + public Answer choice(String id, String toString, Map<String, Object> details) { + return lastAnswer = new Answer(AnswerType.IMPORT, null); } } @@ -313,7 +375,6 @@ static private Log log = LogFactory.getLog(RegionImportJson.class); protected RegionMerge merge; - protected RegionMerge.RegionMergeContext mergeContext; protected JsonNode json; protected LinkedHashMap<String, TopiaEntity> entities; protected JsonNode jsonEntities; @@ -328,7 +389,6 @@ public RegionImportJson(Reader r, RegionMerge merge) { try { this.merge = merge != null ? merge : new RegionMergeImportAll(); - this.mergeContext = new RegionMerge.RegionMergeContext(); entities = new LinkedHashMap<String, TopiaEntity>(); @@ -351,7 +411,7 @@ if (!isRegion) { // il n'y a qu'un objet dans le json, on le deserialize String rootId = info.get("rootId").asText(); - RegionVisitor v = new RegionVisitor(merge, mergeContext, rootId, entities, jsonEntities); + RegionVisitor v = new RegionVisitor(merge, rootId, entities, jsonEntities); // no assigment, collect of entities is done during deserialize v.loadEntity(); } else { @@ -362,7 +422,7 @@ // les champs commencant par des # sont #info et #entities if (!field.getKey().startsWith("#")) { for (JsonNode id : field.getValue()) { - RegionVisitor v = new RegionVisitor(merge, mergeContext, id.asText(), entities, jsonEntities); + RegionVisitor v = new RegionVisitor(merge, id.asText(), entities, jsonEntities); // no assigment, collect of entities is done during deserialize v.loadEntity(); } @@ -379,17 +439,14 @@ static protected class RegionVisitor implements EntityVisitor { protected RegionMerge merge; - protected RegionMerge.RegionMergeContext mergeContext; protected JsonNode nodeEntity; protected TopiaEntity currentEntity; protected LinkedHashMap<String, TopiaEntity> entities; protected JsonNode jsonEntities; - public RegionVisitor(RegionMerge merge, RegionMerge.RegionMergeContext mergeContext, - String idEntity, + public RegionVisitor(RegionMerge merge, String idEntity, LinkedHashMap<String, TopiaEntity> entities, JsonNode jsonEntities) { this.merge = merge; - this.mergeContext = mergeContext; this.nodeEntity = jsonEntities.get(idEntity); this.entities = entities; this.jsonEntities = jsonEntities; @@ -440,8 +497,8 @@ TopiaEntity result; String toString = node.get("#toString").asText(); - merge.choice(mergeContext, id, toString, details); - switch (mergeContext.lastAnswer) { + RegionMerge.Answer answer = merge.choice(id, toString, details); + switch (answer.type) { case ABORT: throw new IsisFishRuntimeException("Import aborted by user"); case NONE: @@ -448,7 +505,7 @@ result = null; break; case REUSE: - result = mergeContext.getReuseEntity(); + result = answer.entity; break; default: result = convertJsonToEntity(node); @@ -464,7 +521,7 @@ result = null; } else if (TopiaEntity.class.isAssignableFrom(type)) { String id = value.asText(); - RegionVisitor child = new RegionVisitor(merge, mergeContext, id, entities, jsonEntities); + RegionVisitor child = new RegionVisitor(merge, id, entities, jsonEntities); result = child.loadEntity(); } else if (MatrixND.class.isAssignableFrom(type)) { String mat = value.asText(); @@ -473,7 +530,7 @@ new EntitySemanticsDecorator.EntityProvider() { @Override public Object findById(String id) { - RegionVisitor child = new RegionVisitor(merge, mergeContext, id, entities, jsonEntities); + RegionVisitor child = new RegionVisitor(merge, id, entities, jsonEntities); Object result = child.loadEntity(); return result; } @@ -542,7 +599,9 @@ } for (JsonNode currentValue : jsonValue) { Object v = readValue(type, currentValue); - c.add(v); + if (v != null) { + c.add(v); + } } BeanUtils.setProperty(entity, propertyName, c); } Modified: trunk/src/main/java/fr/ifremer/isisfish/ui/input/InputHandler.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/ui/input/InputHandler.java 2016-11-09 18:44:50 UTC (rev 4372) +++ trunk/src/main/java/fr/ifremer/isisfish/ui/input/InputHandler.java 2016-11-10 13:08:37 UTC (rev 4373) @@ -436,10 +436,12 @@ if (file != null) { FisheryRegion fisheryRegion = inputUI.getContextValue(FisheryRegion.class); TopiaContext tx = fisheryRegion.getTopiaContext(); + RegionImportJson.RegionMergeDatabase merge = + new RegionImportJson.RegionMergeDatabase(tx); try (InputStream in = new BufferedInputStream( new GZIPInputStream(new FileInputStream(file)))) { RegionImportJson json = new RegionImportJson(new InputStreamReader(in, "UTF-8"), - new RegionImportJson.RegionMergeDatabase(tx)); + merge); Collection<TopiaEntity> entities = json.getEntities(); log.info("Entities to importe: " + entities.size()); for (TopiaEntity e : entities) { @@ -448,7 +450,9 @@ tx.commitTransaction(); } catch (Exception eee) { tx.rollbackTransaction(); - throw eee; + if (!merge.getLastAnswer().isAbort()) { + throw eee; + } } } } catch (Exception eee) {