From 1a06692f024aff60c273d2cfd729c4e2db7928cd Mon Sep 17 00:00:00 2001 From: Giacomo Bertolazzi <20015159@studenti.uniupo.it> Date: Fri, 14 Jun 2019 21:36:31 +0200 Subject: [PATCH] Save/Load * implemented saving/loading of graphical graph * fixed save/load graph * fixed and improved tests --- src/berack96/sim/util/graph/Graph.java | 113 ++++++++++-------- .../util/graph/models/EdgeSaveStructure.java | 20 ++++ .../util/graph/models/GraphSaveStructure.java | 41 +++++++ .../util/graph/models/MarkSaveStructure.java | 18 +++ .../sim/util/graph/view/GraphInfo.java | 2 - .../sim/util/graph/view/GraphPanel.java | 48 ++++++-- .../sim/util/graph/view/GraphWindow.java | 2 +- .../sim/util/graph/view/GraphicalView.java | 5 +- test/berack96/test/sim/TestGraph.java | 56 +++++++-- test/resources/test.json | 2 +- test/resources/test.json.fail | 1 + 11 files changed, 231 insertions(+), 77 deletions(-) create mode 100644 src/berack96/sim/util/graph/models/EdgeSaveStructure.java create mode 100644 src/berack96/sim/util/graph/models/GraphSaveStructure.java create mode 100644 src/berack96/sim/util/graph/models/MarkSaveStructure.java create mode 100644 test/resources/test.json.fail diff --git a/src/berack96/sim/util/graph/Graph.java b/src/berack96/sim/util/graph/Graph.java index 98d285a..673c026 100644 --- a/src/berack96/sim/util/graph/Graph.java +++ b/src/berack96/sim/util/graph/Graph.java @@ -1,16 +1,18 @@ package berack96.sim.util.graph; +import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Collection; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.function.Consumer; import com.google.gson.Gson; +import com.google.gson.JsonSyntaxException; +import berack96.sim.util.graph.models.GraphSaveStructure; import berack96.sim.util.graph.visit.VisitInfo; import berack96.sim.util.graph.visit.VisitStrategy; @@ -548,22 +550,65 @@ public interface Graph extends Iterable { */ Map>> distance(V source) throws NullPointerException, IllegalArgumentException; + /** + * Save the Graph passed as input to a file inserted as parameter.
+ * The resulting file is a Json string representing all the graph.
+ * If the directory for getting through the file do not exist,
+ * then it is created. + * + * @param graph the graph to save + * @param file the name of the file + * @throws IOException for various reason that appear in the message, but the most common is that the file is not found. + */ static void save(Graph graph, String file) throws IOException { save(graph, "", file); } - static void save(Graph graph, String other, String file) throws IOException { - GraphSaveStructure save = new GraphSaveStructure<>(graph, other); + /** + * Save the Graph passed as input to a file inserted as parameter.
+ * The resulting file is a Json string representing all the graph.
+ * If the directory for getting through the file do not exist,
+ * then it is created.
+ * The additional parameter is used if you want to save other as well as the graph. + * + * @param graph the graph to save + * @param other other things to save + * @param file the name of the file + * @throws IOException for various reason that appear in the message, but the most common is that the file is not found. + */ + static void save(Graph graph, String other, String file) throws IOException { + GraphSaveStructure save = new GraphSaveStructure(graph, other); + int slash = file.lastIndexOf("\\"); + if(slash == -1) + slash = file.lastIndexOf("/"); + if(slash != -1) { + String dir = file.substring(0, slash); + File fDir = new File(dir); + fDir.mkdirs(); + } + FileWriter writer = new FileWriter(file); GSON.toJson(save, writer); writer.close(); } - @SuppressWarnings("unchecked") - static String load(Graph graph, String file, Class classV, Class classW) throws IOException { - graph.removeAllVertex(); - + /** + * Load an already saved graph in an instance of a graph. + * Before loading the graph, it is emptied. + * + * @param the parameter needed for the vertex + * @param the parameter needed for the weight + * @param graph the graph to load with + * @param file the file where the graph is saved + * @param classV the class used for the Vertex + * @param classW the class used for the Weight + * @return the string saved in other, if any + * @throws IOException for any possible reason, the most common: the file doesn't exist + * @throws NullPointerException if the graph is null + * @throws JsonSyntaxException if the file is malformed or corrupted + */ + static String load(Graph graph, String file, Class classV, Class classW) throws IOException, NullPointerException, JsonSyntaxException { FileReader reader = new FileReader(file); StringBuilder fileContent = new StringBuilder(); int c; @@ -571,55 +616,23 @@ public interface Graph extends Iterable { while((c = reader.read()) != -1) fileContent.append((char)c); reader.close(); - GraphSaveStructure save = GSON.fromJson(fileContent.toString(), GraphSaveStructure.class); + GraphSaveStructure save = GSON.fromJson(fileContent.toString(), GraphSaveStructure.class); + graph.removeAllVertex(); for(String str : save.vertices) graph.addVertex(GSON.fromJson(str, classV)); - for(int i = 0; i { - public GraphSaveStructure() {} - protected GraphSaveStructure(Graph graph, String other) { - vertices = new LinkedList<>(); - - for(V v: graph.vertices()) - vertices.add(GSON.toJson(v)); - edges = new EdgeSaveStructure<>(graph.edges()); - this.other = other; - } - - public List vertices; - public EdgeSaveStructure edges; - public String other; - } - - class EdgeSaveStructure { - public EdgeSaveStructure() {} - protected EdgeSaveStructure(Collection> edges) { - src = new LinkedList<>(); - dest = new LinkedList<>(); - weight = new LinkedList<>(); - - for(Edge ed : edges) { - src.add(GSON.toJson(ed.getSource())); - dest.add(GSON.toJson(ed.getDestination())); - weight.add(GSON.toJson(ed.getWeight())); - } - } - - public List src; - public List dest; - public List weight; - } - - // TODO maybe -> STATIC saveOnFile(orString) INSTANCE loadFromFile(orString), but need JSON parser // TODO maybe, but i don't think so... STATIC DISTANCE V* -> V* } diff --git a/src/berack96/sim/util/graph/models/EdgeSaveStructure.java b/src/berack96/sim/util/graph/models/EdgeSaveStructure.java new file mode 100644 index 0000000..5213a14 --- /dev/null +++ b/src/berack96/sim/util/graph/models/EdgeSaveStructure.java @@ -0,0 +1,20 @@ +package berack96.sim.util.graph.models; + +/** + * Support class used for saving a Graph in a file. + * + * @author Berack96 + * + */ +public class EdgeSaveStructure { + public EdgeSaveStructure() {} + protected EdgeSaveStructure(String s, String d, String w) { + this.src = s; + this.dest = d; + this.weight = w; + } + + public String src; + public String dest; + public String weight; +} \ No newline at end of file diff --git a/src/berack96/sim/util/graph/models/GraphSaveStructure.java b/src/berack96/sim/util/graph/models/GraphSaveStructure.java new file mode 100644 index 0000000..0cf8db4 --- /dev/null +++ b/src/berack96/sim/util/graph/models/GraphSaveStructure.java @@ -0,0 +1,41 @@ +package berack96.sim.util.graph.models; + +import berack96.sim.util.graph.Edge; +import berack96.sim.util.graph.Graph; + +/** + * Support class used for saving a Graph in a file. + * + * @author Berack96 + * + */ +public class GraphSaveStructure { + public GraphSaveStructure() {} + public GraphSaveStructure(Graph graph, String other) { + this.vertices = new String[graph.numberOfVertices()]; + int i = 0; + for(Object o: graph.vertices()) { + this.vertices[i] = Graph.GSON.toJson(o); + i++; + } + + this.edges = new EdgeSaveStructure[graph.numberOfEdges()]; + i = 0; + for (Edge edge : graph.edges()) { + this.edges[i] = new EdgeSaveStructure( + Graph.GSON.toJson(edge.getSource()), + Graph.GSON.toJson(edge.getDestination()), + Graph.GSON.toJson(edge.getWeight()) + ); + i++; + } + + + this.other = other; + } + + public String[] vertices; + public EdgeSaveStructure[] edges; + //public MarkSaveStructure[] marks; + public String other; +} \ No newline at end of file diff --git a/src/berack96/sim/util/graph/models/MarkSaveStructure.java b/src/berack96/sim/util/graph/models/MarkSaveStructure.java new file mode 100644 index 0000000..0f7517b --- /dev/null +++ b/src/berack96/sim/util/graph/models/MarkSaveStructure.java @@ -0,0 +1,18 @@ +package berack96.sim.util.graph.models; + +/** + * Support class used for saving a Graph in a file. + * + * @author Berack96 + * + */ +public class MarkSaveStructure { + public MarkSaveStructure() {} + protected MarkSaveStructure(String v, Object m) { + this.vert = v; + this.mark = m; + } + + public String vert; + public Object mark; +} diff --git a/src/berack96/sim/util/graph/view/GraphInfo.java b/src/berack96/sim/util/graph/view/GraphInfo.java index f599f5e..0df08a8 100644 --- a/src/berack96/sim/util/graph/view/GraphInfo.java +++ b/src/berack96/sim/util/graph/view/GraphInfo.java @@ -153,7 +153,6 @@ public class GraphInfo extends JPanel { graphPanel.save(fileText.getText()); textResult.setText(""); } catch (IOException e1) { - e1.printStackTrace(); textResult.setText(e1.getMessage()); } }); @@ -163,7 +162,6 @@ public class GraphInfo extends JPanel { graphPanel.load(fileText.getText()); textResult.setText(""); } catch (IOException e1) { - e1.printStackTrace(); textResult.setText(e1.getMessage()); } }); diff --git a/src/berack96/sim/util/graph/view/GraphPanel.java b/src/berack96/sim/util/graph/view/GraphPanel.java index c15c7ee..88e0a38 100644 --- a/src/berack96/sim/util/graph/view/GraphPanel.java +++ b/src/berack96/sim/util/graph/view/GraphPanel.java @@ -31,6 +31,8 @@ public class GraphPanel extends Component { private static final long serialVersionUID = 1L; private final GraphicalView> vertexRender; private final GraphicalView> edgeRender; + private final Class classV; + private final Class classW; private final Container vertices = new Container(); private final Container edges = new Container(); @@ -40,9 +42,11 @@ public class GraphPanel extends Component { private GraphListener old = null; - public GraphPanel(GraphicalView> vertexRender, GraphicalView> edgeRender) { + public GraphPanel(GraphicalView> vertexRender, GraphicalView> edgeRender, Class classV, Class classW) { this.vertexRender = vertexRender; this.edgeRender = edgeRender; + this.classV = classV; + this.classW = classW; } public Graph getGraph() { @@ -166,17 +170,19 @@ public class GraphPanel extends Component { } public void load(String fileName) throws IOException { - String saveContent = Graph.load(graph, fileName); + String saveContent = Graph.load(graph, fileName, classV, classW); GraphGraphicalSave save = Graph.GSON.fromJson(saveContent, GraphGraphicalSave.class); vertices.removeAll(); edges.removeAll(); - for(int i = 0; i graph.getEdgesOut(v).forEach(e -> addEdge(e))); + + for(String v : save.vertices) + graph.getEdgesOut(Graph.GSON.fromJson(v, classV)).forEach(e -> addEdge(e)); repaint(); } @@ -226,16 +232,34 @@ public class GraphPanel extends Component { class GraphGraphicalSave { public GraphGraphicalSave() {} protected GraphGraphicalSave(Container vertices) { - this.vertices = new LinkedList<>(); - this.points = new LinkedList<>(); + List v = new LinkedList<>(); + List p = new LinkedList<>(); for(Component vertex : vertices.getComponents()) { - this.points.add(new Point(vertex.getX(), vertex.getY())); - this.vertices.add(((VertexComponent) vertex).vertex.getValue()); + Point temp = new Point(vertex.getX(), vertex.getY()); + temp.x += vertex.getWidth() / 2; + temp.y += vertex.getHeight() / 2; + + p.add(temp); + v.add(Graph.GSON.toJson(((VertexComponent) vertex).vertex.getValue())); + } + + int i = 0; + this.vertices = new String[v.size()]; + for(String s : v) { + this.vertices[i] = s; + i++; + } + + i = 0; + this.points = new Point[p.size()]; + for(Point pt : p) { + this.points[i] = pt; + i++; } } - public List vertices; - public List points; + public String[] vertices; + public Point[] points; } } diff --git a/src/berack96/sim/util/graph/view/GraphWindow.java b/src/berack96/sim/util/graph/view/GraphWindow.java index 10bfb29..8015a3f 100644 --- a/src/berack96/sim/util/graph/view/GraphWindow.java +++ b/src/berack96/sim/util/graph/view/GraphWindow.java @@ -23,7 +23,7 @@ public class GraphWindow extends JFrame { private static final long serialVersionUID = 1L; public static void main(String[] args) { - GraphPanel panel = new GraphPanel<>(new VertexView<>(), new EdgeView<>()); + GraphPanel panel = new GraphPanel<>(new VertexView<>(), new EdgeView<>(), Integer.class, Integer.class); GraphWindow win = new GraphWindow<>(panel, new VertexIntListener(panel), new EdgeIntListener<>(panel)); Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); // full screen dim.setSize(dim.width / 2, dim.height / 2); diff --git a/src/berack96/sim/util/graph/view/GraphicalView.java b/src/berack96/sim/util/graph/view/GraphicalView.java index 9d29e2f..6a5061f 100644 --- a/src/berack96/sim/util/graph/view/GraphicalView.java +++ b/src/berack96/sim/util/graph/view/GraphicalView.java @@ -9,7 +9,8 @@ import java.awt.*; * @author Berack96 */ public interface GraphicalView { - /** + + /** * Box where the object is sensible at listeners (like Hitbox) * * @param obj the object to draw @@ -17,7 +18,7 @@ public interface GraphicalView { * @return a rectangle where the object is sensible to the listeners */ Rectangle getBox(O obj, Point center); - + /** * The paint function, aka the part where you can draw things (like Mesh) * diff --git a/test/berack96/test/sim/TestGraph.java b/test/berack96/test/sim/TestGraph.java index 03313ee..aaef118 100644 --- a/test/berack96/test/sim/TestGraph.java +++ b/test/berack96/test/sim/TestGraph.java @@ -13,6 +13,7 @@ import java.io.UnsupportedEncodingException; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; @@ -24,6 +25,8 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; +import com.google.gson.JsonSyntaxException; + import berack96.sim.util.graph.Edge; import berack96.sim.util.graph.Graph; import berack96.sim.util.graph.MapGraph; @@ -1332,6 +1335,8 @@ public class TestGraph { String fileName = "test/resources/test.json"; Set vertices = new HashSet<>(); Set> edges = new HashSet<>(); + Map> marks = new HashMap<>(); + Set temp = new HashSet<>(); vertices.add("1"); vertices.add("2"); @@ -1351,30 +1356,63 @@ public class TestGraph { edges.add(new Edge<>("6", "2", 2)); edges.add(new Edge<>("8", "7", 9)); + temp.add(1); + marks.put("2", new HashSet<>(temp)); + temp.add("blue"); + marks.put("1", new HashSet<>(temp)); + marks.put("7", new HashSet<>(temp)); + temp.remove(1); + temp.add(4.0); + marks.put("4", new HashSet<>(temp)); + marks.put("8", new HashSet<>(temp)); + temp.remove(4.0); + temp.add("red"); + marks.put("5", new HashSet<>(temp)); + temp.remove("blue"); + marks.put("6", new HashSet<>(temp)); + temp.clear(); + graph.addAllVertices(vertices); graph.addAllEdges(edges); - - /* because GSON convert to double */ - /* - Set> edgesD = new HashSet<>(); - edges.forEach((e) -> edgesD.add(new Edge(e.getSource(), e.getDestination(), e.getWeight().doubleValue()))); - */ - Set> edgesD = edges; + marks.forEach((v, m) -> m.forEach(mk -> graph.mark(v, mk))); try { Graph.save(graph, fileName); Graph.load(graph, fileName, String.class, Integer.class); shouldContain(graph.vertices(), vertices.toArray()); - shouldContain(graph.edges(), edgesD.toArray()); + shouldContain(graph.edges(), edges.toArray()); + //marks.forEach((v, m) -> shouldContain(graph.getMarks(v), m.toArray())); graph.removeAllVertex(); Graph.load(graph, fileName, String.class, Integer.class); shouldContain(graph.vertices(), vertices.toArray()); - shouldContain(graph.edges(), edgesD.toArray()); + shouldContain(graph.edges(), edges.toArray()); + //marks.forEach((v, m) -> shouldContain(graph.getMarks(v), m.toArray())); } catch (Exception e) { fail(e.getMessage()); } + + try { + Graph.load(graph, "sadadafacensi", String.class, Integer.class); + fail("Should have been thrown IOException"); + } catch (Exception ignore) { + if (!(ignore instanceof IOException)) + fail("Should have been thrown IOException " + ignore.getMessage()); + } + + shouldContain(graph.vertices(), vertices.toArray()); + shouldContain(graph.edges(), edges.toArray()); + //marks.forEach((v, m) -> shouldContain(graph.getMarks(v), m.toArray())); + + try { + Graph.load(graph, fileName + ".fail", String.class, Integer.class); + fail("Should have been thrown JsonSyntaxException"); + } catch (Exception ignore) { + if (!(ignore instanceof JsonSyntaxException)) + fail("Should have been thrown JsonSyntaxException " + ignore.getMessage()); + } + graph = null; shouldThrow(new NullPointerException(), () -> { try { Graph.load(graph, fileName, String.class, Integer.class); diff --git a/test/resources/test.json b/test/resources/test.json index a35f98b..adb59a0 100644 --- a/test/resources/test.json +++ b/test/resources/test.json @@ -1 +1 @@ -{"vertices":["1","2","3","4","5","6","7","8"],"edges":[{"source":"1","destination":"2","weight":1},{"source":"1","destination":"3","weight":1},{"source":"5","destination":"4","weight":5},{"source":"6","destination":"2","weight":2},{"source":"5","destination":"3","weight":2},{"source":"8","destination":"7","weight":9},{"source":"4","destination":"6","weight":6},{"source":"2","destination":"5","weight":4}],"other":""} \ No newline at end of file +{"vertices":["\"1\"","\"2\"","\"3\"","\"4\"","\"5\"","\"6\"","\"7\"","\"8\""],"edges":[{"src":"\"1\"","dest":"\"2\"","weight":"1"},{"src":"\"1\"","dest":"\"3\"","weight":"1"},{"src":"\"5\"","dest":"\"4\"","weight":"5"},{"src":"\"6\"","dest":"\"2\"","weight":"2"},{"src":"\"5\"","dest":"\"3\"","weight":"2"},{"src":"\"8\"","dest":"\"7\"","weight":"9"},{"src":"\"4\"","dest":"\"6\"","weight":"6"},{"src":"\"2\"","dest":"\"5\"","weight":"4"}],"other":""} \ No newline at end of file diff --git a/test/resources/test.json.fail b/test/resources/test.json.fail new file mode 100644 index 0000000..65924c5 --- /dev/null +++ b/test/resources/test.json.fail @@ -0,0 +1 @@ +{"vertices":["\"1\"","\"2\"","\"3\"","\"4\"","\"5\"","gfadad\"6\"","\"7\"","\"8\""],"edges":{"src":["\"1\"","\"1\"","\"5\"","\"6\"","\"5\"","\"8\"","\"4\"","\"2\""],"dest":["\"2\"","\"3\"","\"4\"","\"2\"","\"3\"","\"7\"","\"6ads\"","\"5\""],ad"wedight":["1","1","5","2","2","9","6","4"]},"other":""dsada} \ No newline at end of file