Author: bpoussin Date: 2016-11-04 16:05:55 +0100 (Fri, 04 Nov 2016) New Revision: 4369 Url: http://forge.codelutin.com/projects/isis-fish/repository/revisions/4369 Log: debut d'implantation de l'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. Added: trunk/src/main/java/fr/ifremer/isisfish/entities/RegionExportJson.java trunk/src/main/java/fr/ifremer/isisfish/entities/RegionImportJson.java trunk/src/main/java/fr/ifremer/isisfish/util/EntitySemanticsDecorator.java trunk/src/main/java/fr/ifremer/isisfish/util/MatrixCSVHelper.java Modified: trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultMappedStorage.java trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultStorageAbstract.java trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultStorageCSV.java trunk/src/main/java/fr/ifremer/isisfish/ui/input/InputHandler.java trunk/src/main/java/fr/ifremer/isisfish/ui/input/InputUI.jaxx trunk/src/main/resources/i18n/isis-fish_en_GB.properties trunk/src/main/resources/i18n/isis-fish_fr_FR.properties Modified: trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultMappedStorage.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultMappedStorage.java 2016-11-04 14:16:08 UTC (rev 4368) +++ trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultMappedStorage.java 2016-11-04 15:05:55 UTC (rev 4369) @@ -26,6 +26,7 @@ package fr.ifremer.isisfish.datastore; +import fr.ifremer.isisfish.util.EntitySemanticsDecorator; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; @@ -292,7 +293,9 @@ public MatrixND getMatrix(TopiaContext tx) { // on met la matrice dans un decorateur pour convertir automatiquement les semantiques - MatrixND result = new MatrixSemanticsDecorator(matrix, new EntitySemanticsDecorator(tx)); + MatrixND result = new MatrixSemanticsDecorator(matrix, + new EntitySemanticsDecorator( + new EntitySemanticsDecorator.EntityTxProvider(tx))); return result; } } Modified: trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultStorageAbstract.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultStorageAbstract.java 2016-11-04 14:16:08 UTC (rev 4368) +++ trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultStorageAbstract.java 2016-11-04 15:05:55 UTC (rev 4369) @@ -25,6 +25,8 @@ package fr.ifremer.isisfish.datastore; +import fr.ifremer.isisfish.util.EntitySemanticsDecorator; + import static org.nuiton.i18n.I18n.t; import java.util.ArrayList; @@ -33,18 +35,13 @@ import java.util.Map; import java.util.Set; -import org.apache.commons.collections4.BidiMap; -import org.apache.commons.collections4.bidimap.DualHashBidiMap; -import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.nuiton.math.matrix.MatrixIterator; import org.nuiton.math.matrix.MatrixND; import org.nuiton.math.matrix.MatrixSemanticsDecorator; -import org.nuiton.math.matrix.SemanticsDecorator; import org.nuiton.topia.TopiaContext; import org.nuiton.topia.TopiaException; -import org.nuiton.topia.persistence.TopiaEntity; import org.nuiton.util.ArrayUtil; import org.nuiton.util.HashList; @@ -62,7 +59,6 @@ import fr.ifremer.isisfish.simulator.SimulationPlan; import fr.ifremer.isisfish.simulator.SimulationResultGetter; import fr.ifremer.isisfish.simulator.SimulationResultListener; -import fr.ifremer.isisfish.types.Month; import fr.ifremer.isisfish.types.TimeStep; import java.util.LinkedHashMap; import org.nuiton.math.matrix.MatrixFactory; @@ -92,87 +88,7 @@ /** result enabled */ transient protected Set<String> enabledResult = null; - /** - * Convertie une entite, month, timestep en string et inversement. - * Entity = "TopiaId:Entity.toString" - */ - static protected class EntitySemanticsDecorator implements SemanticsDecorator<Object, String> { - static final private String SEP = ":"; - protected TopiaContext tx; - /** en cle les representation interne (get) en valeur les valeurs decoree (getKey) */ - protected BidiMap<String, Object> cache = new DualHashBidiMap<>(); - - public EntitySemanticsDecorator() { - } - - public EntitySemanticsDecorator(TopiaContext tx) { - this.tx = tx; - } - - @Override - public Object decorate(String internalValue) { - Object result = cache.get(internalValue); - if (result == null && internalValue != null) { - // on retrouve souvent les memes semantiques dans les matrices - // pour minimiser les chaines en memoire, on prend la representation - // interne avant de l'utiliser comme cle. - internalValue = internalValue.intern(); - result = internalValue; - if (StringUtils.startsWith(internalValue, "Month")) { - String val = StringUtils.substringAfter(internalValue, SEP); - int monthNumber = Integer.parseInt(val); - result = Month.MONTH[monthNumber]; - } else if (StringUtils.startsWith(internalValue, "TimeStep")) { - String val = StringUtils.substringAfter(internalValue, SEP); - int stepNumber = Integer.parseInt(val); - result = new TimeStep(stepNumber); - } else if (StringUtils.startsWith(internalValue, "fr.ifremer.isisfish.entities.")) { - if (tx == null) { - result = StringUtils.substringAfter(internalValue, SEP); - } else { - try { - String id = StringUtils.substringBefore(internalValue, SEP); - result = tx.findByTopiaId(id); - } catch (TopiaException eee) { - log.info("Fallback use string representation because" - + " i can't decorate (String->Entity): " - + internalValue, eee); - // si on arrive pas a convertir cette fois-ci, on - // renvoi internalValue pour que le undecorate est toutes les infos - // et donc que la prochaine fois on y arrive peut etre - } - } - } - cache.put(internalValue, result); - } - return result; - } - - @Override - public String undecorate(Object decoratedValue) { - String result = cache.getKey(decoratedValue); - if (result == null && decoratedValue != null) { - if (decoratedValue instanceof Month) { - result = "Month" + SEP + ((Month)decoratedValue).getMonthNumber(); - } else if (decoratedValue instanceof TimeStep) { - result = "TimeStep" + SEP + ((TimeStep)decoratedValue).getStep(); - } else if (decoratedValue instanceof TopiaEntity) { - result = ((TopiaEntity)decoratedValue).getTopiaId() + SEP + decoratedValue; - } else { - result = String.valueOf(decoratedValue); - } - // on retrouve souvent les memes semantiques dans les matrices - // pour minimiser les chaines en memoire, on prend la representation - // interne avant de l'utiliser comme cle. - result = result.intern(); - cache.put(result, decoratedValue); - } - return result; - } - - } - /** * Return one result for step and name. Matrix returned must be undecorated * (semantics must be string representation of object) @@ -245,7 +161,9 @@ // on decore la matrice resultat au dernier moment, tous les calcules // ce font avec les strings tx = getTx(tx); - result = new MatrixSemanticsDecorator(mat, new EntitySemanticsDecorator(tx)); + result = new MatrixSemanticsDecorator(mat, + new EntitySemanticsDecorator( + new EntitySemanticsDecorator.EntityTxProvider(tx))); } return result; } Modified: trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultStorageCSV.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultStorageCSV.java 2016-11-04 14:16:08 UTC (rev 4368) +++ trunk/src/main/java/fr/ifremer/isisfish/datastore/ResultStorageCSV.java 2016-11-04 15:05:55 UTC (rev 4369) @@ -29,17 +29,15 @@ import fr.ifremer.isisfish.simulator.SimulationContext; import fr.ifremer.isisfish.simulator.SimulationControl; import fr.ifremer.isisfish.types.TimeStep; -import fr.ifremer.isisfish.util.SimpleParser; -import java.io.BufferedWriter; +import fr.ifremer.isisfish.util.MatrixCSVHelper; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStreamReader; -import java.io.LineNumberReader; import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.util.ArrayList; +import java.io.Reader; +import java.io.Writer; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -55,7 +53,6 @@ import org.apache.commons.lang3.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; -import org.nuiton.math.matrix.MatrixIterator; import org.nuiton.math.matrix.MatrixND; import org.nuiton.util.StringUtil; @@ -132,6 +129,8 @@ */ protected int maxGapWithCurrentStepReadOnDisk = 0; + protected MatrixCSVHelper matrixCSVHelper; + LinkedHashMap<TimeStep, Map<String, MatrixND>> cache = new LinkedHashMap<TimeStep, Map<String, MatrixND>>() { private static final long serialVersionUID = 1L; @@ -146,8 +145,17 @@ storeOnDiskStep = IsisFish.config.getSimulationStoreResultOnDisk(); cacheStep = IsisFish.config.getSimulationStoreResultCacheStep(); + } + protected MatrixCSVHelper getMatrixCSVHelper() { + if (matrixCSVHelper == null) { + matrixCSVHelper = new MatrixCSVHelper(decorator); + } + return matrixCSVHelper; + } + + @Override public String getInfo() { String oldest = ""; @@ -222,51 +230,13 @@ protected MatrixND readMatrix(String file) throws IOException { MatrixND result = null; - LineNumberReader in = null; + Reader in = null; try { - in = new LineNumberReader(new InputStreamReader( - new GZIPInputStream(new FileInputStream(file)), IsisConfig.charset)); + in = new InputStreamReader( + new GZIPInputStream(new FileInputStream(file)), IsisConfig.charset); - SimpleParser sp = new SimpleParser(in, true); + result = getMatrixCSVHelper().readMatrix(in); - // lecture du nom de la matrice - String name = sp.readString('\n'); - - - // lecture du nom des dimensions et des semantics - List<String> dimNames = new ArrayList<String>(); - List<List<String>> semantics = new ArrayList<List<String>>(); - - String dimName = sp.readString(':'); - while (!sp.isEOL() || StringUtils.isNotBlank(dimName)) { - dimNames.add(dimName); - List<String> sems = new ArrayList<String>(); - semantics.add(sems); - while (!sp.isEOL()) { - String sem = sp.readString(';'); - sems.add(sem); - } - dimName = sp.readString(':'); - } - - // creation de la matrice resultat avec les infos collectes - result = getMatrixFactory().create(name, - semantics.toArray(new List[semantics.size()]), - dimNames.toArray(new String[dimNames.size()])); - - - // lecture des data - int nbDim = dimNames.size(); - int[] coord = new int[nbDim]; - - while (!sp.isEOF()) { - for (int i=0; i<nbDim; i++) { - coord[i] = sp.readInt(';'); - } - double v = sp.readDouble(';'); - result.setValue(coord, v); - } - } finally { IOUtils.closeQuietly(in); } @@ -382,47 +352,16 @@ File file = getMatrixFile(step, name); file.getParentFile().mkdirs(); - PrintWriter out = null; + Writer out = null; CountingOutputStream counter = null; try { - out = new PrintWriter(new BufferedWriter(new OutputStreamWriter( + out = new OutputStreamWriter( new GZIPOutputStream(counter = new CountingOutputStream(new FileOutputStream(file))), IsisConfig.charset - ))); + ); - out.print(name); - out.println(); + getMatrixCSVHelper().writeMatrix(out, name, mat); - List[] sems = mat.getSemantics(); - for (int i=0, maxi=sems.length; i<maxi; i++) { - String dimName = mat.getDimensionName(i); - out.print(dimName); - - List l = sems[i]; - char sep = ':'; - for (Object o : l) { - out.print(sep); - out.print(o); - sep = ';'; - } - out.println(); - } - - // blank line to separate header and data - out.println(); - - for (MatrixIterator i = mat.iteratorNotZero(); i.hasNext();) { - i.next(); - int[] pos = i.getCoordinates(); - double value = i.getValue(); - for (int p : pos) { - out.print(p); - out.print(';'); - } - out.print(value); - out.println(); - } - // result file is writen without error, add it to fileExistCache addFileExist(file); } catch (Exception eee) { Added: trunk/src/main/java/fr/ifremer/isisfish/entities/RegionExportJson.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/entities/RegionExportJson.java (rev 0) +++ trunk/src/main/java/fr/ifremer/isisfish/entities/RegionExportJson.java 2016-11-04 15:05:55 UTC (rev 4369) @@ -0,0 +1,396 @@ +package fr.ifremer.isisfish.entities; + + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.ObjectMapper; +import fr.ifremer.isisfish.IsisConfig; +import fr.ifremer.isisfish.types.Month; +import fr.ifremer.isisfish.types.RangeOfValues; +import fr.ifremer.isisfish.types.TimeUnit; +import fr.ifremer.isisfish.util.EntitySemanticsDecorator; +import fr.ifremer.isisfish.util.MatrixCSVHelper; +import java.io.IOException; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.math.matrix.MatrixND; +import org.nuiton.topia.persistence.EntityVisitor; +import org.nuiton.topia.persistence.TopiaEntity; + +/** + * Classe permettant d'exporter en Json une region + * + * Format du JSON: + * + * { + * "#info": { + * "formatVersion": int + * "isisVersion": String + * "region": boolean if true contains one region, if false contains one Entity + * "root": toString representation of root entity + * "rootId": id of root entity + * }, + * "#entities": { + * " <id>": {<entity field>}, + * ... + * }, + * "FisheryRegion" : [<id>], + * "Cell": [<id>, ...], + * "Zone": [<id>, ...], + * ... + * } + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +public class RegionExportJson implements EntityVisitor { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(RegionExportJson.class); + + final static public int FORMAT_VERSION = 1; + + protected LinkedList<TopiaEntity> toVisit; + protected Set<String> visited; + protected LinkedHashMap<String, List<String>> isisEntities; + protected boolean doVisit = false; + protected MatrixCSVHelper matrixCSVHelper; + protected EntitySemanticsDecorator decorator; + protected JsonGenerator g; + + public RegionExportJson(Writer w) { + try { + JsonFactory f = new JsonFactory(); + g = f.createGenerator(w); + + toVisit = new LinkedList<TopiaEntity>(); + visited = new HashSet<String>(); + matrixCSVHelper = new MatrixCSVHelper( + decorator = new EntitySemanticsDecorator()); + + isisEntities = new LinkedHashMap<String, List<String>>(); + isisEntities.put("FisheryRegion", new ArrayList<String>()); + isisEntities.put("Cell", new ArrayList<String>()); + isisEntities.put("Zone", new ArrayList<String>()); + isisEntities.put("Port", new ArrayList<String>()); + isisEntities.put("Species", new ArrayList<String>()); + isisEntities.put("Population", new ArrayList<String>()); + isisEntities.put("Gear", new ArrayList<String>()); + isisEntities.put("Metier", new ArrayList<String>()); + isisEntities.put("TripType", new ArrayList<String>()); + isisEntities.put("VesselType", new ArrayList<String>()); + isisEntities.put("SetOfVessels", new ArrayList<String>()); + isisEntities.put("Strategy", new ArrayList<String>()); + isisEntities.put("Observation", new ArrayList<String>()); + } catch (IOException eee) { + throw new RuntimeException(eee); + } + } + + /** + * Export la region et tous les elements de la region. + * @param fisheryRegion + */ + public void export(FisheryRegion fisheryRegion) { + toVisit.addAll(fisheryRegion.getCell()); + toVisit.addAll(fisheryRegion.getZone()); + toVisit.addAll(fisheryRegion.getPort()); + toVisit.addAll(fisheryRegion.getSpecies()); + toVisit.addAll(fisheryRegion.getGear()); + toVisit.addAll(fisheryRegion.getMetier()); + toVisit.addAll(fisheryRegion.getTripType()); + toVisit.addAll(fisheryRegion.getVesselType()) ; + toVisit.addAll(fisheryRegion.getSetOfVessels()); + toVisit.addAll(fisheryRegion.getStrategy()); + toVisit.addAll(fisheryRegion.getObservations()); + + export(fisheryRegion, true); + } + + /** + * Export seulement l'entity et ses dépendances. + * @param entity + */ + public void export(TopiaEntity entity) { + if (entity instanceof FisheryRegion) { + export((FisheryRegion)entity); + } else { + export(entity, false); + } + } + + protected void export(TopiaEntity entity, boolean isRegion) { + try { + this.start(); + g.writeObjectFieldStart("#info"); + g.writeNumberField("formatVersion", FORMAT_VERSION); + g.writeStringField("isisVersion", IsisConfig.getVersion()); + g.writeBooleanField("region", isRegion); + g.writeStringField("root", entity.toString()); + g.writeStringField("rootId", entity.getTopiaId()); + g.writeEndObject(); + + g.writeObjectFieldStart("#entities"); + + toVisit.push(entity); + + TopiaEntity e; + while(toVisit.peek() != null) { + while((e = toVisit.poll()) != null) { + e.accept(this); + } + + // add all TopiaEntity in matrix semantics + Collection<Object> decoratedObject = decorator.getDecoratedObject(); + for (Object o : decoratedObject) { + if (o instanceof TopiaEntity && !visited.contains(((TopiaEntity)o).getTopiaId())) { + toVisit.add((TopiaEntity)o); + } + } + } + + g.writeEndObject(); + this.end(); + } catch (IOException eee) { + throw new RuntimeException(eee); + } + } + + protected void writeValue(Class<?> type, Object value) { + try { + if (value == null) { + g.writeNull(); + } else if (TopiaEntity.class.isAssignableFrom(type)) { + g.writeString(((TopiaEntity)value).getTopiaId()); + toVisit.add((TopiaEntity)value); + } else if (MatrixND.class.isAssignableFrom(type)) { + MatrixND m = (MatrixND)value; + String s = matrixCSVHelper.writeMatrix(m.getName(), m); + g.writeString(s); + } else if (TimeUnit.class.isAssignableFrom(type)) { + g.writeNumber(((TimeUnit)value).getTime()); + } else if (RangeOfValues.class.isAssignableFrom(type)) { + g.writeString(((RangeOfValues)value).getAsString()); + } else if (Month.class.isAssignableFrom(type)) { + g.writeNumber(((Month)value).getMonthNumber()); + } else if (Number.class.isAssignableFrom(type) || value instanceof Number) { + g.writeNumber(((Number)value).doubleValue()); + } else if (String.class.isAssignableFrom(type)) { + g.writeString(((String)value)); + } else if (Boolean.class.isAssignableFrom(type) || value instanceof Boolean) { + g.writeBoolean(((Boolean)value)); + } else if (Class.class.isAssignableFrom(type)) { + g.writeString(((Class)value).getName()); + } else { + String message = String.format("Unsupported type: '%s' value class '%s' value '%s'", type, value.getClass().getName(), value); + log.error(message); + g.writeString(message); +// throw new RuntimeException(message); + } + } catch (IOException eee) { + throw new RuntimeException(eee); + } + } + + public void start() { + try { + g.writeStartObject(); + ObjectMapper m = new ObjectMapper(); + } catch (IOException eee) { + throw new RuntimeException(eee); + } + } + + public void end() { + try { + for (Map.Entry<String, List<String>> e : isisEntities.entrySet()) { + g.writeArrayFieldStart(e.getKey()); + for (String id : e.getValue()) { + g.writeString(id); + } + g.writeEndArray(); + } + g.writeEndObject(); + g.close(); + } catch (IOException eee) { + throw new RuntimeException(eee); + } + } + + /** + * Start the visit of the given entity. + * + * @param entity the visited entity + */ + @Override + public void start(TopiaEntity entity) { + try { + String id = entity.getTopiaId(); + doVisit = !visited.contains(id); + if (doVisit) { + visited.add(id); + g.writeObjectFieldStart(id); + String className = entity.getClass().getName(); + String name = StringUtils.removeEnd(entity.getClass().getSimpleName(), "Impl"); + List<String> list = isisEntities.get(name); + if (list != null) { + list.add(id); + } + + g.writeStringField("#class", className); + g.writeStringField("#id", id); + g.writeStringField("#toString", entity.toString()); + } + } catch (IOException eee) { + throw new RuntimeException(eee); + } + } + + /** + * Ends the visit of the given entity. + * + * @param entity the visited entity + */ + @Override + public void end(TopiaEntity entity) { + try { + if (doVisit) { + g.writeEndObject(); + } + } catch (IOException eee) { + throw new RuntimeException(eee); + } + } + + /** + * Visit a none indexed property for the given entity. + * + * The property visited is defined by the other parameters. + * + * @param entity the visited entity + * @param propertyName the name of the visited property + * @param type the type of the visited property + * @param value the value of the visited property + */ + @Override + public void visit(TopiaEntity entity, String propertyName, Class<?> type, Object value) { + try { + if (doVisit) { + g.writeFieldName(propertyName); + writeValue(type, value); + } + } catch (IOException eee) { + throw new RuntimeException(eee); + } + } + + /** + * Visit a collection property for the given entity. + * + * The property visited is defined by the other parameters. + * + * @param entity the visited entity + * @param propertyName the name of the visited property + * @param collectionType the type of the visited collection + * @param type the type of the visited property + * @param value the value of the visited property + */ + @Override + public void visit(TopiaEntity entity, String propertyName, + Class<?> collectionType, Class<?> type, Object value) { + try { + if (doVisit) { + g.writeFieldName(propertyName); + g.writeStartArray(); + if (value != null) { + for (Object currentValue : (Collection<?>)value) { + writeValue(type, currentValue); + } + } + g.writeEndArray(); + } + } catch (IOException eee) { + throw new RuntimeException(eee); + } + } + + /** + * Visit a indexed value from a collection property for the given entity. + * + * The property visited is defined by the other parameters. + * + * @param entity the visited entity + * @param propertyName the name of the visited property + * @param collectionType the type of the container of the visited property + * @param type the type of the visited property + * @param index the index of the visited property in his container + * @param value the value of the visited property + */ + @Override + public void visit(TopiaEntity entity, String propertyName, + Class<?> collectionType, Class<?> type, int index, Object value) { + if (doVisit) { + throw new UnsupportedOperationException("FIXME a faire, implantation des properties array"); + } + } + + /** + * Reset all states of the visitor. + * + * If you use internal states inside the visitor, this method should clean + * all of them. + * + * This method should be invoked after usage of the visitor. + */ + @Override + public void clear() { + toVisit = null; + visited = null; + isisEntities = null; + matrixCSVHelper = null; + decorator = null; + } + + +// abstract public void visit(Cell v); +// abstract public void visit(EffortDescription v); +// abstract public void visit(FisheryRegion region); +// abstract public void visit(Gear v); +// abstract public void visit(Metier v); +// abstract public void visit(MetierSeasonInfo v); +// abstract public void visit(PopulationGroup v); +// abstract public void visit(Population v); +// abstract public void visit(PopulationSeasonInfo v); +// abstract public void visit(Port v); +// abstract public void visit(Season v); +// abstract public void visit(Selectivity v); +// abstract public void visit(SetOfVessels v); +// abstract public void visit(Species v); +// abstract public void visit(Strategy v); +// abstract public void visit(StrategyMonthInfo v); +// abstract public void visit(TargetSpecies v); +// abstract public void visit(TripType v); +// abstract public void visit(Variable v); +// abstract public void visit(VariableType v); +// abstract public void visit(VesselType v); +// abstract public void visit(Zone v); +// abstract public void visit(Equation v); +// abstract public void visit(MatrixND v); +// abstract public void visit(String v); +// abstract public void visit(int v); +// abstract public void visit(float v); + +} Property changes on: trunk/src/main/java/fr/ifremer/isisfish/entities/RegionExportJson.java ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision HeadURL \ No newline at end of property Added: trunk/src/main/java/fr/ifremer/isisfish/entities/RegionImportJson.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/entities/RegionImportJson.java (rev 0) +++ trunk/src/main/java/fr/ifremer/isisfish/entities/RegionImportJson.java 2016-11-04 15:05:55 UTC (rev 4369) @@ -0,0 +1,428 @@ +package fr.ifremer.isisfish.entities; + + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.ObjectCodec; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.module.SimpleModule; +import fr.ifremer.isisfish.IsisFishDAOHelper; +import fr.ifremer.isisfish.types.Month; +import fr.ifremer.isisfish.types.RangeOfValues; +import fr.ifremer.isisfish.types.TimeUnit; +import fr.ifremer.isisfish.util.EntitySemanticsDecorator; +import fr.ifremer.isisfish.util.MatrixCSVHelper; +import java.io.IOException; +import java.io.Reader; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.Map.Entry; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.math.matrix.MatrixND; +import org.nuiton.topia.TopiaContext; +import org.nuiton.topia.persistence.TopiaEntity; + +/** + * Classe permettant d'importer des données dans une region a partir d'un + * export Json. + * L'import se fait le plus possible de façon automatique, s'il y a des + * choix a faire durant la fusion, les questions sont posées au travers de + * l'objet passé en paramètre + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + */ +public class RegionImportJson { + + static public interface RegionMerge { + public TopiaEntity choice(TopiaEntity e); + } + + static public class RegionMergeDatabase implements RegionMerge { + protected TopiaContext tx; + + public RegionMergeDatabase(TopiaContext tx) { + this.tx = tx; + } + + @Override + public TopiaEntity choice(TopiaEntity e) { + TopiaEntity result; + + if (e instanceof FisheryRegion) { + result = choice((FisheryRegion)e); + } else if (e instanceof Cell) { + result = choice((Cell)e); + } else if (e instanceof Zone) { + result = choice((Zone)e); + } else if (e instanceof Port) { + result = choice((Port)e); + } else if (e instanceof Species) { + result = choice((Species)e); + } else if (e instanceof Population) { + result = choice((Population)e); + } else if (e instanceof Gear) { + result = choice((Gear)e); + } else if (e instanceof Metier) { + result = choice((Metier)e); + } else if (e instanceof TripType) { + result = choice((TripType)e); + } else if (e instanceof VesselType) { + result = choice((VesselType)e); + } else if (e instanceof SetOfVessels) { + result = choice((SetOfVessels)e); + } else if (e instanceof Strategy) { + result = choice((Strategy)e); + } else if (e instanceof Observation) { + result = choice((Observation)e); + } else { + log.info("Not supported entity type: " + e.getClass().getSimpleName()); + result = genericChoice(e); + } + + return result; + } + + protected TopiaEntity ask(TopiaEntity e, Collection<TopiaEntity> possible) { + System.out.println("Choice between:" + e + " and " + possible); + return e; // FIXME + } + + protected TopiaEntity genericChoice(TopiaEntity e) { + LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); + + possible.add(tx.findByTopiaId(e.getTopiaId())); + + TopiaEntity result = ask(e, possible); + return result; + } + + protected TopiaEntity choice(FisheryRegion e) { + FisheryRegionDAO dao = IsisFishDAOHelper.getFisheryRegionDAO(tx); + LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); + + possible.add(dao.findByTopiaId(e.getTopiaId())); + possible.addAll(dao.findAllByName(e.getName())); + + TopiaEntity result = ask(e, possible); + return result; + } + + protected TopiaEntity choice(Cell e) { + CellDAO dao = IsisFishDAOHelper.getCellDAO(tx); + LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); + + possible.add(dao.findByTopiaId(e.getTopiaId())); + possible.addAll(dao.findAllByName(e.getName())); + + TopiaEntity result = ask(e, possible); + return result; + } + + protected TopiaEntity choice(Zone e) { + ZoneDAO dao = IsisFishDAOHelper.getZoneDAO(tx); + LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); + + possible.add(dao.findByTopiaId(e.getTopiaId())); + possible.addAll(dao.findAllByName(e.getName())); + + TopiaEntity result = ask(e, possible); + return result; + } + + protected TopiaEntity choice(Port e) { + PortDAO dao = IsisFishDAOHelper.getPortDAO(tx); + LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); + + possible.add(dao.findByTopiaId(e.getTopiaId())); + possible.addAll(dao.findAllByName(e.getName())); + + TopiaEntity result = ask(e, possible); + return result; + } + + protected TopiaEntity choice(Species e) { + SpeciesDAO dao = IsisFishDAOHelper.getSpeciesDAO(tx); + LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); + + possible.add(dao.findByTopiaId(e.getTopiaId())); + possible.addAll(dao.findAllByName(e.getName())); + + TopiaEntity result = ask(e, possible); + return result; + } + + protected TopiaEntity choice(Population e) { + PopulationDAO dao = IsisFishDAOHelper.getPopulationDAO(tx); + LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); + + possible.add(dao.findByTopiaId(e.getTopiaId())); + possible.addAll(dao.findAllByName(e.getName())); + + TopiaEntity result = ask(e, possible); + return result; + } + + protected TopiaEntity choice(Gear e) { + GearDAO dao = IsisFishDAOHelper.getGearDAO(tx); + LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); + + possible.add(dao.findByTopiaId(e.getTopiaId())); + possible.addAll(dao.findAllByName(e.getName())); + + TopiaEntity result = ask(e, possible); + return result; + } + + protected TopiaEntity choice(Metier e) { + MetierDAO dao = IsisFishDAOHelper.getMetierDAO(tx); + LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); + + possible.add(dao.findByTopiaId(e.getTopiaId())); + possible.addAll(dao.findAllByName(e.getName())); + + TopiaEntity result = ask(e, possible); + return result; + } + + protected TopiaEntity choice(TripType e) { + TripTypeDAO dao = IsisFishDAOHelper.getTripTypeDAO(tx); + LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); + + possible.add(dao.findByTopiaId(e.getTopiaId())); + possible.addAll(dao.findAllByName(e.getName())); + + TopiaEntity result = ask(e, possible); + return result; + } + + protected TopiaEntity choice(VesselType e) { + VesselTypeDAO dao = IsisFishDAOHelper.getVesselTypeDAO(tx); + LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); + + possible.add(dao.findByTopiaId(e.getTopiaId())); + possible.addAll(dao.findAllByName(e.getName())); + + TopiaEntity result = ask(e, possible); + return result; + } + + protected TopiaEntity choice(SetOfVessels e) { + SetOfVesselsDAO dao = IsisFishDAOHelper.getSetOfVesselsDAO(tx); + LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); + + possible.add(dao.findByTopiaId(e.getTopiaId())); + possible.addAll(dao.findAllByName(e.getName())); + + TopiaEntity result = ask(e, possible); + return result; + } + + protected TopiaEntity choice(Strategy e) { + StrategyDAO dao = IsisFishDAOHelper.getStrategyDAO(tx); + LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); + + possible.add(dao.findByTopiaId(e.getTopiaId())); + possible.addAll(dao.findAllByName(e.getName())); + + TopiaEntity result = ask(e, possible); + return result; + } + + protected TopiaEntity choice(Observation e) { + ObservationDAO dao = IsisFishDAOHelper.getObservationDAO(tx); + LinkedHashSet<TopiaEntity> possible = new LinkedHashSet<TopiaEntity>(); + + possible.add(dao.findByTopiaId(e.getTopiaId())); + possible.addAll(dao.findAllByName(e.getName())); + + TopiaEntity result = ask(e, possible); + return result; + } + } + + static public class RegionMergeNoMerge implements RegionMerge { + @Override + public TopiaEntity choice(TopiaEntity e) { + return e; + } + } + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(RegionImportJson.class); + + protected RegionMerge merge; + protected JsonNode json; + protected LinkedHashMap<String, TopiaEntity> entities; + protected JsonNode jsonEntities; + protected ObjectMapper mapper; + + /** + * + * @param r reader contains json + * @param merge use to choice entity in Json or entity in current region + */ + public RegionImportJson(Reader r, RegionMerge merge) { + try { + this.merge = merge != null ? merge : new RegionMergeNoMerge(); + entities = new LinkedHashMap<String, TopiaEntity>(); + + mapper = new ObjectMapper(); + SimpleModule isisModule = new SimpleModule("IsisModule") + .addDeserializer(Month.class, new MonthJsonDeserializer()) + .addDeserializer(TimeUnit.class, new TimeUnitJsonDeserializer()) + .addDeserializer(RangeOfValues.class, new RangeOfValuesJsonDeserializer()) + .addDeserializer(MatrixND.class, new MatrixNDJsonDeserializer(this)) + .addDeserializer(TopiaEntity.class, new TopiaEntityJsonDeserializer(this)); + mapper.registerModule(isisModule); + + ObjectMapper m = new ObjectMapper(); + json = m.readTree(r); + jsonEntities = json.get("#entities"); + } catch (IOException eee) { + throw new RuntimeException(eee); + } + } + + /** + * Return all entities available in Json reader + * @return + */ + public Collection<TopiaEntity> getEntity() { + try { + JsonNode info = json.with("#info"); + boolean isRegion = info.get("region").asBoolean(false); + if (!isRegion) { + // il n'y a qu'un objet dans le json, on le deserialize + String rootId = info.get("rootId").asText(); + getEntity(rootId); + } else { + // il y a toute une region, on lit les listes d'id des objets + // principaux (cell, zone, port, ...) + for (Iterator<Entry<String, JsonNode>> i = json.fields(); i.hasNext();) { + Entry<String, JsonNode> field = i.next(); + // les champs commencant par des # sont #info et #entities + if (!field.getKey().startsWith("#")) { + for (JsonNode id : field.getValue()) { + getEntity(id.asText()); + } + } + } + } + + return entities.values(); + } catch (Exception eee) { + throw new RuntimeException(eee); + } + } + + /** + * Return entity with given id. If not already converted, convert it and + * add it in global entities converted pool + * @param id + * @return + */ + public TopiaEntity getEntity(String id) { + try { + TopiaEntity result = entities.get(id); + if (result == null) { + JsonNode node = jsonEntities.get(id); + Class clazz = Class.forName(node.get("#class").asText()); + TopiaEntity o = (TopiaEntity)mapper.convertValue(node, clazz); + o = merge.choice(o); + entities.put(id, o); + } + return result; + } catch (Exception eee) { + throw new RuntimeException(eee); + } + } + + private static class MatrixNDJsonDeserializer extends JsonDeserializer<MatrixND> { + + protected MatrixCSVHelper matrixCSVHelper; + + public MatrixNDJsonDeserializer(final RegionImportJson importer) { + matrixCSVHelper = new MatrixCSVHelper(new EntitySemanticsDecorator( + new EntitySemanticsDecorator.EntityProvider() { + @Override + public Object findById(String id) { + Object result = importer.getEntity(id); + return result; + } + })); + } + + @Override + public MatrixND deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { + ObjectCodec oc = p.getCodec(); + JsonNode node = oc.readTree(p); + String mat = node.asText(); + MatrixND result = matrixCSVHelper.readMatrix(mat); + return result; + } + + } + + private static class TopiaEntityJsonDeserializer extends JsonDeserializer<TopiaEntity> { + + protected RegionImportJson importer; + + public TopiaEntityJsonDeserializer(RegionImportJson importer) { + this.importer = importer; + } + + @Override + public TopiaEntity deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { + ObjectCodec oc = p.getCodec(); + JsonNode node = oc.readTree(p); + String id = node.asText(); + TopiaEntity result = importer.getEntity(id); + return result; + } + + } + + private static class MonthJsonDeserializer extends JsonDeserializer<Month> { + @Override + public Month deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { + ObjectCodec oc = p.getCodec(); + JsonNode node = oc.readTree(p); + int m = node.asInt(); + Month result = Month.MONTH[m]; + return result; + } + } + + private static class TimeUnitJsonDeserializer extends JsonDeserializer<TimeUnit> { + @Override + public TimeUnit deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { + ObjectCodec oc = p.getCodec(); + JsonNode node = oc.readTree(p); + int v = node.asInt(); + TimeUnit result = new TimeUnit(v); + return result; + } + } + + private static class RangeOfValuesJsonDeserializer extends JsonDeserializer<RangeOfValues> { + @Override + public RangeOfValues deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException { + ObjectCodec oc = p.getCodec(); + JsonNode node = oc.readTree(p); + String v = node.asText(); + RangeOfValues result = new RangeOfValues(v); + return result; + } + } + +} Property changes on: trunk/src/main/java/fr/ifremer/isisfish/entities/RegionImportJson.java ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision HeadURL \ No newline at end of property 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-04 14:16:08 UTC (rev 4368) +++ trunk/src/main/java/fr/ifremer/isisfish/ui/input/InputHandler.java 2016-11-04 15:05:55 UTC (rev 4369) @@ -23,6 +23,9 @@ package fr.ifremer.isisfish.ui.input; + +import cern.colt.Arrays; + import static org.nuiton.i18n.I18n.n; import static org.nuiton.i18n.I18n.t; @@ -57,6 +60,8 @@ import fr.ifremer.isisfish.datastore.StorageException; import fr.ifremer.isisfish.entities.FisheryRegion; import fr.ifremer.isisfish.entities.Population; +import fr.ifremer.isisfish.entities.RegionExportJson; +import fr.ifremer.isisfish.entities.RegionImportJson; import fr.ifremer.isisfish.entities.Species; import fr.ifremer.isisfish.entities.SpeciesDAO; import fr.ifremer.isisfish.mexico.export.RegionExplorer; @@ -71,6 +76,19 @@ import fr.ifremer.isisfish.ui.input.tree.loadors.PopulationsNodeLoador; import fr.ifremer.isisfish.ui.models.common.GenericComboModel; import fr.ifremer.isisfish.vcs.VCSException; +import java.awt.Component; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.util.Collection; +import java.util.zip.GZIPInputStream; +import java.util.zip.GZIPOutputStream; +import org.nuiton.topia.persistence.TopiaEntity; /** * Main handler for fishery edition action. @@ -362,6 +380,81 @@ } } + /** + * Exporter une entite json gzip + */ + protected void exportJson(TopiaEntity e) { + try { + File file = FileUtil.getFile(".*.isonz$", + t("isisfish.message.import.region.zipped")); + + if (file != null) { + // add .isonz extension is not set + if (!file.getAbsolutePath().endsWith(".isonz")) { + file = new File(file.getAbsolutePath() + ".isonz"); + } + + int resp = JOptionPane.YES_OPTION; + if (file.exists()) { + resp = JOptionPane.showConfirmDialog(inputUI, + t("isisfish.message.file.overwrite")); + } + if (resp == JOptionPane.YES_OPTION) { + try (OutputStream out = new BufferedOutputStream( + new GZIPOutputStream(new FileOutputStream(file)))) { + RegionExportJson json = new RegionExportJson(new OutputStreamWriter(out, "UTF-8")); + json.export(e); + } + } + } + } catch (Exception eee) { + throw new IsisFishRuntimeException("Can't export region", eee); + } + } + + public void exportEntityJson() { + Component[] cs = inputUI.getInputPane().getComponents(); + if (cs != null && cs.length == 1 && cs[0] instanceof InputContentUI) { + InputContentUI inputContentUI = (InputContentUI)cs[0]; + TopiaEntityContextable e = inputContentUI.getBean(); + if (e != null) { + log.info("try to export json version of: " + e); + exportJson(e); + } else { + log.error("Can't find entity in : " + inputContentUI); + } + } else { + log.error("Can't find InputContentUI in : " + Arrays.toString(cs)); + } + } + + public void importEntityJson() { + setStatusMessage(inputUI, t("isisfish.message.import.zip"), true); + try { + File file = FileUtil.getFile(".*\\.isonz$", + t("isisfish.message.import.region.zipped")); + if (file != null) { + FisheryRegion fisheryRegion = inputUI.getContextValue(FisheryRegion.class); + TopiaContext tx = fisheryRegion.getTopiaContext(); + try (InputStream in = new BufferedInputStream( + new GZIPInputStream(new FileInputStream(file)))) { + RegionImportJson json = new RegionImportJson(new InputStreamReader(in, "UTF-8"), + new RegionImportJson.RegionMergeDatabase(tx)); + Collection<TopiaEntity> entities = json.getEntity(); + log.info("Entities to importe: " + entities.size()); + for (TopiaEntity e : entities) { + tx.add(e); + } + tx.commitTransaction(); + } + } + } catch (Exception eee) { + throw new IsisFishRuntimeException("Can't import region", eee); + } + + setStatusMessage(inputUI, t("isisfish.message.import.finished")); + } + /** * Remove region. * Modified: trunk/src/main/java/fr/ifremer/isisfish/ui/input/InputUI.jaxx =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/ui/input/InputUI.jaxx 2016-11-04 14:16:08 UTC (rev 4368) +++ trunk/src/main/java/fr/ifremer/isisfish/ui/input/InputUI.jaxx 2016-11-04 15:05:55 UTC (rev 4369) @@ -40,6 +40,8 @@ <JMenuItem id="menuRegionImportRename" text="isisfish.input.menu.importRenameRegion" onActionPerformed="handler.importRegionAndRename()" /> <JMenuItem text="isisfish.input.menu.importRegionSimulation" onActionPerformed="handler.importRegionFromSimulation()" enabled="false"/> <JMenuItem id="menuRegionExport" text="isisfish.input.menu.exportRegion" enabled='{isRegionLoaded()}' onActionPerformed="handler.exportRegion()" /> + <JMenuItem id="menuExportJson" text="isisfish.input.menu.exportJson" enabled='{isRegionLoaded()}' onActionPerformed="handler.exportEntityJson()" /> + <JMenuItem id="menuImportJson" text="isisfish.input.menu.importJson" enabled='{isRegionLoaded()}' onActionPerformed="handler.importEntityJson()" /> <JMenuItem id="menuRegionCopy" text="isisfish.input.menu.copyRegion" enabled='{isRegionLoaded()}' onActionPerformed="handler.copyRegion()" /> <JSeparator/> <JMenuItem text="isisfish.input.menu.removeLocaly" enabled='{isRegionLoaded()}' onActionPerformed="handler.removeRegion(false)" /> Added: trunk/src/main/java/fr/ifremer/isisfish/util/EntitySemanticsDecorator.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/util/EntitySemanticsDecorator.java (rev 0) +++ trunk/src/main/java/fr/ifremer/isisfish/util/EntitySemanticsDecorator.java 2016-11-04 15:05:55 UTC (rev 4369) @@ -0,0 +1,151 @@ +package fr.ifremer.isisfish.util; + + +import fr.ifremer.isisfish.IsisFishRuntimeException; +import fr.ifremer.isisfish.types.Month; +import fr.ifremer.isisfish.types.TimeStep; +import java.util.Collection; +import java.util.Map; +import org.apache.commons.collections4.BidiMap; +import org.apache.commons.collections4.bidimap.DualHashBidiMap; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.math.matrix.SemanticsDecorator; +import org.nuiton.topia.TopiaContext; +import org.nuiton.topia.persistence.TopiaEntity; + +/** + * Convertie une entite, month, timestep en string et inversement. + * Entity = "TopiaId:Entity.toString" + */ +public class EntitySemanticsDecorator implements SemanticsDecorator<Object, String> { + + static private Log log = LogFactory.getLog(EntitySemanticsDecorator.class); + + public static interface EntityProvider { + + public Object findById(String id); + } + + public static class EntityTxProvider implements EntityProvider { + + protected TopiaContext tx; + + public EntityTxProvider(TopiaContext tx) { + this.tx = tx; + } + + @Override + public Object findById(String id) { + Object result = tx.findByTopiaId(id); + return result; + } + } + + public static class EntityMapProvider implements EntityProvider { + + protected Map<String, TopiaEntity> map; + + public EntityMapProvider(Map<String, TopiaEntity> map) { + this.map = map; + } + + @Override + public Object findById(String id) { + Object result = map.get(id); + if (result == null) { + throw new IsisFishRuntimeException("Can't find entity in map: " + id); + } + return result; + } + } + + + private static final String SEP = ":"; + protected EntityProvider provider; + /** en cle les representation interne (get) en valeur les valeurs decoree (getKey) */ + protected BidiMap<String, Object> cache = new DualHashBidiMap<>(); + + public EntitySemanticsDecorator() { + } + + public EntitySemanticsDecorator(EntityProvider provider) { + this.provider = provider; + } + + /** + * return all currently cached object decorated. Can be used to transforme + * matrix and work on object found in semantics. + * If returned collection is cleared, all object in cache are removed too + * @return + */ + public Collection<Object> getDecoratedObject() { + Collection<Object> result = cache.values(); + return result; + } + + @Override + public Object decorate(String internalValue) { + Object result = cache.get(internalValue); + if (result == null && internalValue != null) { + // on retrouve souvent les memes semantiques dans les matrices + // pour minimiser les chaines en memoire, on prend la representation + // interne avant de l'utiliser comme cle. + internalValue = internalValue.intern(); + result = internalValue; + if (StringUtils.startsWith(internalValue, "Month")) { + String val = StringUtils.substringAfter(internalValue, SEP); + int monthNumber = Integer.parseInt(val); + result = Month.MONTH[monthNumber]; + } else if (StringUtils.startsWith(internalValue, "TimeStep")) { + String val = StringUtils.substringAfter(internalValue, SEP); + int stepNumber = Integer.parseInt(val); + result = new TimeStep(stepNumber); + } else if (StringUtils.startsWith(internalValue, "fr.ifremer.isisfish.entities.")) { + if (provider == null) { + result = StringUtils.substringAfter(internalValue, SEP); + } else { + try { + String id = StringUtils.substringBefore(internalValue, SEP); + result = provider.findById(id); + } catch (Exception eee) { + log.info("Fallback use string representation because" + " i can't decorate (String->Entity): " + internalValue, eee); + // si on arrive pas a convertir cette fois-ci, on + // renvoi internalValue pour que le undecorate est toutes les infos + // et donc que la prochaine fois on y arrive peut etre + } + } + } + cache.put(internalValue, result); + } + return result; + } + + @Override + public String undecorate(Object decoratedValue) { + if (decoratedValue instanceof String) { + return (String)decoratedValue; + } + + String result = cache.getKey(decoratedValue); + if (result == null && decoratedValue != null) { + if (decoratedValue instanceof Month) { + result = "Month" + SEP + ((Month) decoratedValue).getMonthNumber(); + } else if (decoratedValue instanceof TimeStep) { + result = "TimeStep" + SEP + ((TimeStep) decoratedValue).getStep(); + } else if (decoratedValue instanceof TopiaEntity) { + result = ((TopiaEntity) decoratedValue).getTopiaId() + SEP + decoratedValue; + } else { + result = String.valueOf(decoratedValue); + } + // on retrouve souvent les memes semantiques dans les matrices + // pour minimiser les chaines en memoire, on prend la representation + // interne avant de l'utiliser comme cle. + result = result.intern(); + cache.put(result, decoratedValue); + } + return result; + } + +} Property changes on: trunk/src/main/java/fr/ifremer/isisfish/util/EntitySemanticsDecorator.java ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision HeadURL \ No newline at end of property Added: trunk/src/main/java/fr/ifremer/isisfish/util/MatrixCSVHelper.java =================================================================== --- trunk/src/main/java/fr/ifremer/isisfish/util/MatrixCSVHelper.java (rev 0) +++ trunk/src/main/java/fr/ifremer/isisfish/util/MatrixCSVHelper.java 2016-11-04 15:05:55 UTC (rev 4369) @@ -0,0 +1,197 @@ +package fr.ifremer.isisfish.util; + + +import java.io.BufferedWriter; +import java.io.IOException; +import java.io.LineNumberReader; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.StringReader; +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.nuiton.math.matrix.MatrixFactory; +import org.nuiton.math.matrix.MatrixIterator; +import org.nuiton.math.matrix.MatrixND; + +/** + * Classe permettant de convertir une matrice en String et inversement en + * prenant en compte la conversion des semantiques via l'utilisation + * d'un decorator ({@link EntitySemanticsDecorator}). + * + * Ce format est utilise comme format de sauvegarde des resultats dans les + * simulation. Il remplace le stockage en base et les fichiers mapper. + * + * Format d'une matrice: + * <pre> + * # commentaire + * [nom] + * [nom dimension1]:[semantique1];[semantique2];... + * [nom dimension2]:[semantique1];[semantique2];... + * ... + * [ligne blanche] + * [coordonnee1];[coordonnee2];...;[valeur] + * [coordonnee1];[coordonnee2];...;[valeur] + * [coordonnee1];[coordonnee2];...;[valeur] + * ... + * </pre> + * + * Exemple + * <pre> + * MaMatrice + * Mois:Janvier;Fevrier;Mars + * Ville:Nantes;Paris;Nice + * + * 1;1;2;13.5 + * 0;2;1;4.2 + * </pre> + * + * @author poussin + * @version $Revision$ + * + * Last update: $Date$ + * by : $Author$ + * + * @since 4.4.1.0 + */ +public class MatrixCSVHelper { + + /** to use log facility, just put in your code: log.info(\"...\"); */ + static private Log log = LogFactory.getLog(MatrixCSVHelper.class); + + protected EntitySemanticsDecorator decorator; + + public MatrixCSVHelper() { + this(new EntitySemanticsDecorator()); + } + + public MatrixCSVHelper(EntitySemanticsDecorator decorator) { + this.decorator = decorator; + } + + protected MatrixFactory getMatrixFactory() { + return MatrixFactory.getInstance(); + } + + /** + * return new list with undecorate item + * @param l + * @return new list + */ + protected List<String> undecorate(List l) { + ArrayList<String> result = new ArrayList<String>(l.size()); + for (Object o : l) { + result.add(undecorate(o)); + } + return result; + } + + protected String undecorate(Object o) { + return decorator.undecorate(o); + } + + public MatrixND readMatrix(String mat) throws IOException { + try (Reader in = new StringReader(mat)) { + MatrixND result = this.readMatrix(in); + return result; + } + } + + public String writeMatrix(String name, MatrixND mat) throws IOException { + try (StringWriter out = new StringWriter()) { + writeMatrix(out, name, mat); + String result = out.toString(); + return result; + } + } + + public MatrixND readMatrix(Reader reader) throws IOException { + LineNumberReader in = new LineNumberReader(reader); + + SimpleParser sp = new SimpleParser(in, true); + + // lecture du nom de la matrice + String name = sp.readString('\n'); + + + // lecture du nom des dimensions et des semantics + List<String> dimNames = new ArrayList<String>(); + List<List<String>> semantics = new ArrayList<List<String>>(); + + String dimName = sp.readString(':'); + while (!sp.isEOL() || StringUtils.isNotBlank(dimName)) { + dimNames.add(dimName); + List<String> sems = new ArrayList<String>(); + semantics.add(sems); + while (!sp.isEOL()) { + String sem = sp.readString(';'); + sems.add(sem); + } + dimName = sp.readString(':'); + } + + // creation de la matrice resultat avec les infos collectes + MatrixND result = getMatrixFactory().create(name, + semantics.toArray(new List[semantics.size()]), + dimNames.toArray(new String[dimNames.size()])); + + + // lecture des data + int nbDim = dimNames.size(); + int[] coord = new int[nbDim]; + + while (!sp.isEOF()) { + for (int i=0; i<nbDim; i++) { + coord[i] = sp.readInt(';'); + } + double v = sp.readDouble(';'); + result.setValue(coord, v); + } + + return result; + } + + public void writeMatrix(Writer writer, String name, MatrixND mat) { + PrintWriter out = new PrintWriter(new BufferedWriter(writer)); + + out.print(name); + out.println(); + + List[] sems = mat.getSemantics(); + for (int i=0, maxi=sems.length; i<maxi; i++) { + String dimName = mat.getDimensionName(i); + out.print(dimName); + + List l = undecorate(sems[i]); + char sep = ':'; + for (Object o : l) { + out.print(sep); + out.print(o); + sep = ';'; + } + out.println(); + } + + // blank line to separate header and data + out.println(); + + for (MatrixIterator i = mat.iteratorNotZero(); i.hasNext();) { + i.next(); + int[] pos = i.getCoordinates(); + double value = i.getValue(); + for (int p : pos) { + out.print(p); + out.print(';'); + } + out.print(value); + out.println(); + } + + out.flush(); + } + +} Property changes on: trunk/src/main/java/fr/ifremer/isisfish/util/MatrixCSVHelper.java ___________________________________________________________________ Added: svn:keywords ## -0,0 +1 ## +Author Date Id Revision HeadURL \ No newline at end of property Modified: trunk/src/main/resources/i18n/isis-fish_en_GB.properties =================================================================== --- trunk/src/main/resources/i18n/isis-fish_en_GB.properties 2016-11-04 14:16:08 UTC (rev 4368) +++ trunk/src/main/resources/i18n/isis-fish_en_GB.properties 2016-11-04 15:05:55 UTC (rev 4369) @@ -458,7 +458,9 @@ isisfish.input.menu.addRegion=Add region isisfish.input.menu.commit=Commit change isisfish.input.menu.copyRegion=Copy region +isisfish.input.menu.exportJson=Export current object in JSON isisfish.input.menu.exportRegion=Export region +isisfish.input.menu.importJson=Import objets from JSON isisfish.input.menu.importRegion=Import region isisfish.input.menu.importRegionSimulation=Import region from simulation isisfish.input.menu.importRenameRegion=Import region and rename Modified: trunk/src/main/resources/i18n/isis-fish_fr_FR.properties =================================================================== --- trunk/src/main/resources/i18n/isis-fish_fr_FR.properties 2016-11-04 14:16:08 UTC (rev 4368) +++ trunk/src/main/resources/i18n/isis-fish_fr_FR.properties 2016-11-04 15:05:55 UTC (rev 4369) @@ -458,7 +458,9 @@ isisfish.input.menu.addRegion=Ajouter une région isisfish.input.menu.commit=Sauvegarder les changements isisfish.input.menu.copyRegion=Copier région +isisfish.input.menu.exportJson=Exporter l'object courant en JSON isisfish.input.menu.exportRegion=Exporter la région +isisfish.input.menu.importJson=Importer des objets JSON isisfish.input.menu.importRegion=Importer une région isisfish.input.menu.importRegionSimulation=Importer la région d'une simulation isisfish.input.menu.importRenameRegion=Importer une région et la renommer