f@0
|
1 /*
|
f@0
|
2 CCmI Editor - A Collaborative Cross-Modal Diagram Editing Tool
|
f@0
|
3
|
f@0
|
4 Copyright (C) 2011 Queen Mary University of London (http://ccmi.eecs.qmul.ac.uk/)
|
f@0
|
5
|
f@0
|
6 This program is free software: you can redistribute it and/or modify
|
f@0
|
7 it under the terms of the GNU General Public License as published by
|
f@0
|
8 the Free Software Foundation, either version 3 of the License, or
|
f@0
|
9 (at your option) any later version.
|
f@0
|
10
|
f@0
|
11 This program is distributed in the hope that it will be useful,
|
f@0
|
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
|
f@0
|
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
f@0
|
14 GNU General Public License for more details.
|
f@0
|
15
|
f@0
|
16 You should have received a copy of the GNU General Public License
|
f@0
|
17 along with this program. If not, see <http://www.gnu.org/licenses/>.
|
f@0
|
18 */
|
f@0
|
19
|
f@0
|
20 package uk.ac.qmul.eecs.ccmi.gui.persistence;
|
f@0
|
21
|
f@0
|
22 import java.io.BufferedWriter;
|
f@0
|
23 import java.io.File;
|
f@0
|
24 import java.io.FileWriter;
|
f@0
|
25 import java.io.IOException;
|
f@0
|
26 import java.io.InputStream;
|
f@0
|
27 import java.io.OutputStream;
|
f@0
|
28 import java.text.MessageFormat;
|
f@0
|
29 import java.util.ArrayList;
|
f@0
|
30 import java.util.Collection;
|
f@0
|
31 import java.util.Enumeration;
|
f@0
|
32 import java.util.LinkedHashMap;
|
f@0
|
33 import java.util.List;
|
f@0
|
34 import java.util.Map;
|
f@0
|
35 import java.util.ResourceBundle;
|
f@0
|
36
|
f@0
|
37 import javax.swing.tree.TreeNode;
|
f@0
|
38 import javax.xml.parsers.DocumentBuilder;
|
f@0
|
39 import javax.xml.parsers.DocumentBuilderFactory;
|
f@0
|
40 import javax.xml.parsers.ParserConfigurationException;
|
f@0
|
41 import javax.xml.transform.OutputKeys;
|
f@0
|
42 import javax.xml.transform.Transformer;
|
f@0
|
43 import javax.xml.transform.TransformerConfigurationException;
|
f@0
|
44 import javax.xml.transform.TransformerException;
|
f@0
|
45 import javax.xml.transform.TransformerFactory;
|
f@0
|
46 import javax.xml.transform.dom.DOMSource;
|
f@0
|
47 import javax.xml.transform.stream.StreamResult;
|
f@0
|
48
|
f@0
|
49 import org.w3c.dom.Document;
|
f@0
|
50 import org.w3c.dom.Element;
|
f@0
|
51 import org.w3c.dom.NodeList;
|
f@0
|
52 import org.xml.sax.SAXException;
|
f@0
|
53
|
f@0
|
54 import uk.ac.qmul.eecs.ccmi.diagrammodel.CollectionModel;
|
f@0
|
55 import uk.ac.qmul.eecs.ccmi.diagrammodel.DiagramTreeNode;
|
f@0
|
56 import uk.ac.qmul.eecs.ccmi.diagrammodel.TreeModel;
|
f@0
|
57 import uk.ac.qmul.eecs.ccmi.gui.Diagram;
|
f@0
|
58 import uk.ac.qmul.eecs.ccmi.gui.DiagramEventSource;
|
f@0
|
59 import uk.ac.qmul.eecs.ccmi.gui.Edge;
|
f@0
|
60 import uk.ac.qmul.eecs.ccmi.gui.Node;
|
f@0
|
61 import uk.ac.qmul.eecs.ccmi.utils.CharEscaper;
|
f@0
|
62
|
f@0
|
63 /**
|
f@0
|
64 * The PersistanceManager provides methods for saving and retrieving diagrams from an XML
|
f@0
|
65 * file. Both templates diagrams (prototypes from which actual diagram instances are created
|
f@0
|
66 * through cloning) and diagram instances can be saved to a file. The tag name used in the XML
|
f@0
|
67 * file can be accessed via the static {@code String} variables of this class.
|
f@0
|
68 *
|
f@0
|
69 */
|
f@0
|
70 public abstract class PersistenceManager {
|
f@0
|
71 /**
|
f@0
|
72 * Encodes a diagram template in a file in XML format
|
f@0
|
73 *
|
f@0
|
74 * @param diagram the diagram to be encoded
|
f@0
|
75 * @param file the file where the diagram is going to be encoded
|
f@0
|
76 * @throws IOException if there are any I/O problems with the file
|
f@0
|
77 */
|
f@0
|
78 public static void encodeDiagramTemplate(Diagram diagram, File file) throws IOException{
|
f@0
|
79 ResourceBundle resources = ResourceBundle.getBundle(PersistenceManager.class.getName());
|
f@0
|
80 if(file.createNewFile() == false)
|
f@0
|
81 throw new IOException(resources.getString("dialog.error.file_exists"));
|
f@0
|
82
|
f@0
|
83 DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
|
f@0
|
84 DocumentBuilder docBuilder = null;
|
f@0
|
85 try {
|
f@0
|
86 docBuilder = dbfac.newDocumentBuilder();
|
f@0
|
87 } catch (ParserConfigurationException e) {
|
f@0
|
88 throw new IOException(resources.getString("dialog.error.problem.save"),e);
|
f@0
|
89 }
|
f@0
|
90 Document doc = docBuilder.newDocument();
|
f@0
|
91
|
f@0
|
92 Element root = doc.createElement(DIAGRAM);
|
f@0
|
93 doc.appendChild(root);
|
f@0
|
94 /* diagram name and prototypePersstenceDelegate */
|
f@0
|
95 root.setAttribute(NAME, diagram.getName());
|
f@0
|
96 root.setAttribute(PROTOTYPE_PERSISTENCE_DELEGATE, diagram.getPrototypePersistenceDelegate().getClass().getName());
|
f@0
|
97
|
f@0
|
98 writePrototypes(doc, root, diagram);
|
f@0
|
99
|
f@0
|
100 //set up a transformer
|
f@0
|
101 TransformerFactory transfac = TransformerFactory.newInstance();
|
f@0
|
102 Transformer trans = null;
|
f@0
|
103 try {
|
f@0
|
104 trans = transfac.newTransformer();
|
f@0
|
105 } catch (TransformerConfigurationException tce) {
|
f@0
|
106 throw new IOException(resources.getString("dialog.error.problem.save"),tce);
|
f@0
|
107 }
|
f@0
|
108 trans.setOutputProperty(OutputKeys.INDENT, "yes");
|
f@0
|
109 trans.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", String.valueOf(2));
|
f@0
|
110
|
f@0
|
111 StreamResult result = new StreamResult(new BufferedWriter(new FileWriter(file)));
|
f@0
|
112 DOMSource source = new DOMSource(doc);
|
f@0
|
113 try {
|
f@0
|
114 trans.transform(source, result);
|
f@0
|
115 } catch (TransformerException te) {
|
f@0
|
116 throw new IOException(resources.getString("dialog.error.problem.save"),te);
|
f@0
|
117 }
|
f@0
|
118 }
|
f@0
|
119
|
f@0
|
120 /**
|
f@0
|
121 * Decodes a diagram template from a file in XML format
|
f@0
|
122 *
|
f@0
|
123 * @param XMLFile the file to read the diagram from
|
f@0
|
124 * @throws IOException if there are any I/O problems with the file
|
f@0
|
125 *
|
f@0
|
126 * @return the diagram encoded in {@code XMLFile}
|
f@0
|
127 */
|
f@0
|
128 public static Diagram decodeDiagramTemplate(File XMLFile) throws IOException{
|
f@0
|
129 ResourceBundle resources = ResourceBundle.getBundle(PersistenceManager.class.getName());
|
f@0
|
130 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
|
f@0
|
131 DocumentBuilder dBuilder = null;
|
f@0
|
132 try {
|
f@0
|
133 dBuilder = dbFactory.newDocumentBuilder();
|
f@0
|
134 } catch (ParserConfigurationException pce) {
|
f@0
|
135 throw new IOException(resources.getString("dialog.error.problem.open"),pce);
|
f@0
|
136 }
|
f@0
|
137 Document doc = null;
|
f@0
|
138 try {
|
f@0
|
139 doc = dBuilder.parse(XMLFile);
|
f@0
|
140 } catch (SAXException se) {
|
f@0
|
141 throw new IOException(resources.getString("dialog.error.problem.open"),se);
|
f@0
|
142 }
|
f@0
|
143 doc.getDocumentElement().normalize();
|
f@0
|
144
|
f@0
|
145 if(doc.getElementsByTagName(DIAGRAM).item(0) == null)
|
f@0
|
146 throw new IOException(resources.getString("dialog.error.malformed_file"));
|
f@0
|
147 Element root = (Element)doc.getElementsByTagName(DIAGRAM).item(0);
|
f@0
|
148 String diagramName = root.getAttribute(NAME);
|
f@0
|
149 if(diagramName.isEmpty())
|
f@0
|
150 throw new IOException(resources.getString("dialog.error.malformed_file"));
|
f@0
|
151 String persistenceDelegateClassName = root.getAttribute(PROTOTYPE_PERSISTENCE_DELEGATE);
|
f@0
|
152 PrototypePersistenceDelegate persistenceDelegate = null;
|
f@0
|
153 try{
|
f@0
|
154 Class<? extends PrototypePersistenceDelegate> c = Class.forName(persistenceDelegateClassName).asSubclass(PrototypePersistenceDelegate.class);
|
f@0
|
155 persistenceDelegate = c.newInstance();
|
f@0
|
156 }catch(Exception e){
|
f@0
|
157 throw new IOException(resources.getString("dialog.error.problem.open"),e);
|
f@0
|
158 }
|
f@0
|
159
|
f@0
|
160 final List<Node> nList = readNodePrototypes(doc,persistenceDelegate);
|
f@0
|
161 final List<Edge> eList = readEdgePrototypes(doc,persistenceDelegate);
|
f@0
|
162 Node[] nArray = new Node[nList.size()];
|
f@0
|
163 Edge[] eArray = new Edge[eList.size()];
|
f@0
|
164 return Diagram.newInstance(diagramName,nList.toArray(nArray),eList.toArray(eArray),persistenceDelegate);
|
f@0
|
165 }
|
f@0
|
166
|
f@0
|
167 /**
|
f@0
|
168 * Encodes a diagram instance into the given output stream. Using output stream
|
f@0
|
169 * instead of {@code Writer} as it's advised by the <i>StreamResult API</i>
|
f@0
|
170 * @see http://download.oracle.com/javase/6/docs/api/javax/xml/transform/stream/StreamResult.html
|
f@0
|
171 *
|
f@0
|
172 * @param diagram the diagram to encode
|
f@0
|
173 * @param newName the new name of the diagram to encode. This will also be the name of the file but {@code diagram}
|
f@0
|
174 * will still keep the old name, that is the value returned by {@code getName()} won't be changed to {@code newName}.
|
f@0
|
175 * If a {@code null} value is passed than the value returned by {@code diagram.getName()} will be used.
|
f@0
|
176 *
|
f@0
|
177 * @param out where the diagram will be encoded
|
f@0
|
178 * @throws IOException if there are any I/O problems with the file
|
f@0
|
179 */
|
f@0
|
180 public static void encodeDiagramInstance(Diagram diagram, String newName, OutputStream out) throws IOException{
|
f@0
|
181 ResourceBundle resources = ResourceBundle.getBundle(PersistenceManager.class.getName());
|
f@0
|
182 DocumentBuilderFactory dbfac = DocumentBuilderFactory.newInstance();
|
f@0
|
183 DocumentBuilder docBuilder = null;
|
f@0
|
184 try {
|
f@0
|
185 docBuilder = dbfac.newDocumentBuilder();
|
f@0
|
186 } catch (ParserConfigurationException pce) {
|
f@0
|
187 throw new IOException(resources.getString("dialog.error.problem.save"),pce);
|
f@0
|
188 }
|
f@0
|
189 Document doc = docBuilder.newDocument();
|
f@0
|
190
|
f@0
|
191 Element root = doc.createElement(DIAGRAM);
|
f@0
|
192 root.setAttribute(NAME, (newName != null) ? newName : diagram.getName());
|
f@0
|
193 root.setAttribute(PROTOTYPE_PERSISTENCE_DELEGATE, diagram.getPrototypePersistenceDelegate().getClass().getName());
|
f@0
|
194 doc.appendChild(root);
|
f@0
|
195
|
f@0
|
196 /* store bookmarks */
|
f@0
|
197 Element bookmarksTag = doc.createElement(BOOKMARKS);
|
f@0
|
198 TreeModel<Node,Edge> treeModel = diagram.getTreeModel();
|
f@0
|
199 for(String key : treeModel.getBookmarks()){
|
f@0
|
200 Element bookmarkTag = doc.createElement(BOOKMARK);
|
f@0
|
201 bookmarkTag.setAttribute(KEY, key);
|
f@0
|
202 if(treeModel.getBookmarkedTreeNode(key).isRoot())
|
f@0
|
203 bookmarkTag.setTextContent(ROOT_AS_STRING);
|
f@0
|
204 else
|
f@0
|
205 bookmarkTag.setTextContent(getTreeNodeAsString(treeModel.getBookmarkedTreeNode(key)));
|
f@0
|
206 bookmarksTag.appendChild(bookmarkTag);
|
f@0
|
207 }
|
f@0
|
208 if(bookmarksTag.hasChildNodes())
|
f@0
|
209 root.appendChild(bookmarksTag);
|
f@0
|
210
|
f@0
|
211 /* store notes */
|
f@0
|
212 Element notesTag = doc.createElement(NOTES);
|
f@0
|
213 DiagramTreeNode treeRoot = (DiagramTreeNode)diagram.getTreeModel().getRoot();
|
f@0
|
214 for( @SuppressWarnings("unchecked")
|
f@0
|
215 Enumeration<DiagramTreeNode> enumeration = treeRoot.depthFirstEnumeration(); enumeration.hasMoreElements();){
|
f@0
|
216 DiagramTreeNode treeNode = enumeration.nextElement();
|
f@0
|
217 if(!treeNode.getNotes().isEmpty()){
|
f@0
|
218 Element noteTag = doc.createElement(NOTE);
|
f@0
|
219 Element treeNodeTag = doc.createElement(TREE_NODE);
|
f@0
|
220 if(treeNode.isRoot())
|
f@0
|
221 treeNodeTag.setTextContent(ROOT_AS_STRING);
|
f@0
|
222 else
|
f@0
|
223 treeNodeTag.setTextContent(getTreeNodeAsString(treeNode));
|
f@0
|
224 Element contentTag = doc.createElement(CONTENT);
|
f@0
|
225 contentTag.setTextContent(CharEscaper.replaceNewline(treeNode.getNotes()));
|
f@0
|
226 noteTag.appendChild(treeNodeTag);
|
f@0
|
227 noteTag.appendChild(contentTag);
|
f@0
|
228 notesTag.appendChild(noteTag);
|
f@0
|
229 }
|
f@0
|
230 }
|
f@0
|
231
|
f@0
|
232 if(notesTag.hasChildNodes())
|
f@0
|
233 root.appendChild(notesTag);
|
f@0
|
234
|
f@0
|
235 writePrototypes(doc,root,diagram);
|
f@0
|
236
|
f@0
|
237 Element components = doc.createElement(COMPONENTS);
|
f@0
|
238 root.appendChild(components);
|
f@0
|
239
|
f@0
|
240 synchronized(diagram.getCollectionModel().getMonitor()){
|
f@0
|
241 Collection<Node> nodes = diagram.getCollectionModel().getNodes();
|
f@0
|
242 Collection<Edge> edges = diagram.getCollectionModel().getEdges();
|
f@0
|
243
|
f@0
|
244 /* store nodes */
|
f@0
|
245 Element nodesTag = doc.createElement(NODES);
|
f@0
|
246 components.appendChild(nodesTag);
|
f@0
|
247 List<Node> nList = new ArrayList<Node>(nodes);
|
f@0
|
248 for(Node n : nList){
|
f@0
|
249 Element nodeTag = doc.createElement(NODE);
|
f@0
|
250 nodeTag.setAttribute(ID, String.valueOf(n.getId()));
|
f@0
|
251 nodeTag.setAttribute(TYPE, n.getType());
|
f@0
|
252 nodesTag.appendChild(nodeTag);
|
f@0
|
253 n.encode(doc, nodeTag);
|
f@0
|
254 }
|
f@0
|
255
|
f@0
|
256 Element edgesTag = doc.createElement(EDGES);
|
f@0
|
257 components.appendChild(edgesTag);
|
f@0
|
258 for(Edge e : edges){
|
f@0
|
259 Element edgeTag = doc.createElement(EDGE);
|
f@0
|
260 edgesTag.appendChild(edgeTag);
|
f@0
|
261 e.encode(doc,edgeTag,nList);
|
f@0
|
262 }
|
f@0
|
263 }
|
f@0
|
264 //set up a transformer
|
f@0
|
265 TransformerFactory transfac = TransformerFactory.newInstance();
|
f@0
|
266 Transformer trans = null;
|
f@0
|
267 try {
|
f@0
|
268 trans = transfac.newTransformer();
|
f@0
|
269 } catch (TransformerConfigurationException tec) {
|
f@0
|
270 throw new IOException(resources.getString("dialog.error.problem.save"));
|
f@0
|
271 }
|
f@0
|
272 trans.setOutputProperty(OutputKeys.INDENT, "yes");
|
f@0
|
273 trans.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", String.valueOf(2));
|
f@0
|
274
|
f@0
|
275
|
f@0
|
276 StreamResult result = new StreamResult(out);
|
f@0
|
277 DOMSource source = new DOMSource(doc);
|
f@0
|
278 try {
|
f@0
|
279 trans.transform(source, result);
|
f@0
|
280 } catch (TransformerException te) {
|
f@0
|
281 throw new IOException(resources.getString("dialog.error.problem.save"),te);
|
f@0
|
282 }
|
f@0
|
283 }
|
f@0
|
284
|
f@0
|
285 /**
|
f@0
|
286 * Encodes a diagram instance into the given output stream. Using output stream
|
f@0
|
287 * instead of {@code Writer} as it's advised by the <i>StreamResult API</i>
|
f@0
|
288 * @see http://download.oracle.com/javase/6/docs/api/javax/xml/transform/stream/StreamResult.html
|
f@0
|
289 *
|
f@0
|
290 * @param diagram the diagram to encode
|
f@0
|
291 * @param out an output stram to the file where the diagram will be encoded
|
f@0
|
292 * @throws IOException if there are any I/O problems with the file
|
f@0
|
293 */
|
f@0
|
294 public static void encodeDiagramInstance(Diagram diagram, OutputStream out) throws IOException{
|
f@0
|
295 encodeDiagramInstance(diagram,null,out);
|
f@0
|
296 }
|
f@0
|
297
|
f@0
|
298 /**
|
f@0
|
299 * Decodes a diagram instance from the given input stream. Using input stream
|
f@0
|
300 * instead of {@code Reader} as it's advised by the <i>StreamResult API</i>
|
f@0
|
301 * @see http://download.oracle.com/javase/6/docs/api/javax/xml/transform/stream/StreamResult.html
|
f@0
|
302 *
|
f@0
|
303 * @param in an input stream to the file the diagram is decoded from
|
f@0
|
304 * @throws IOException if there are any I/O problems with the file
|
f@0
|
305 *
|
f@0
|
306 * @return the diagram encoded in the file
|
f@0
|
307 */
|
f@0
|
308 public static Diagram decodeDiagramInstance(InputStream in) throws IOException {
|
f@0
|
309 ResourceBundle resources = ResourceBundle.getBundle(PersistenceManager.class.getName());
|
f@0
|
310 DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance();
|
f@0
|
311 DocumentBuilder dBuilder = null;
|
f@0
|
312 try {
|
f@0
|
313 dBuilder = dbFactory.newDocumentBuilder();
|
f@0
|
314 } catch (ParserConfigurationException pce) {
|
f@0
|
315 throw new IOException(resources.getString("dialog.error.problem.open"),pce);
|
f@0
|
316 }
|
f@0
|
317 Document doc = null;
|
f@0
|
318 try {
|
f@0
|
319 doc = dBuilder.parse(in);
|
f@0
|
320 } catch (SAXException se) {
|
f@0
|
321 throw new IOException(resources.getString("dialog.error.problem.open"),se);
|
f@0
|
322 }
|
f@0
|
323 doc.getDocumentElement().normalize();
|
f@0
|
324
|
f@0
|
325 if(doc.getElementsByTagName(DIAGRAM).item(0) == null)
|
f@0
|
326 throw new IOException(resources.getString("dialog.error.malformed_file"));
|
f@0
|
327 Element root = (Element)doc.getElementsByTagName(DIAGRAM).item(0);
|
f@0
|
328 String diagramName = root.getAttribute(NAME);
|
f@0
|
329 if(diagramName.isEmpty())
|
f@0
|
330 throw new IOException(resources.getString("dialog.error.malformed_file"));
|
f@0
|
331 String persistenceDelegateClassName = root.getAttribute(PROTOTYPE_PERSISTENCE_DELEGATE);
|
f@0
|
332 PrototypePersistenceDelegate persistenceDelegate = null;
|
f@0
|
333 try{
|
f@0
|
334 Class<? extends PrototypePersistenceDelegate> c = Class.forName(persistenceDelegateClassName).asSubclass(PrototypePersistenceDelegate.class);
|
f@0
|
335 persistenceDelegate = c.newInstance();
|
f@0
|
336 }catch(Exception e){
|
f@0
|
337 throw new IOException(resources.getString("dialog.error.problem.open"),e);
|
f@0
|
338 }
|
f@0
|
339
|
f@0
|
340 final List<Node> nList = readNodePrototypes(doc,persistenceDelegate);
|
f@0
|
341 final List<Edge> eList = readEdgePrototypes(doc,persistenceDelegate);
|
f@0
|
342
|
f@0
|
343 final Node[] nodes = nList.toArray(new Node[nList.size()]);
|
f@0
|
344 final Edge[] edges = eList.toArray(new Edge[eList.size()]);
|
f@0
|
345
|
f@0
|
346 Diagram diagram = Diagram.newInstance(diagramName, nodes,edges,persistenceDelegate);
|
f@0
|
347 CollectionModel<Node,Edge> collectionModel = diagram.getCollectionModel();
|
f@0
|
348 TreeModel<Node,Edge> treeModel = diagram.getTreeModel();
|
f@0
|
349
|
f@0
|
350 /* a map linking node ids in the XML file to the actual Node object they represent */
|
f@0
|
351 Map<String,Node> nodesId = new LinkedHashMap<String,Node>();
|
f@0
|
352
|
f@0
|
353 if(doc.getElementsByTagName(COMPONENTS).item(0) == null)
|
f@0
|
354 throw new IOException(resources.getString("dialog.error.malformed_file"));
|
f@0
|
355 Element componentsTag = (Element)doc.getElementsByTagName(COMPONENTS).item(0);
|
f@0
|
356 NodeList componentsChildren = componentsTag.getChildNodes();
|
f@0
|
357 Element nodesTag = null;
|
f@0
|
358 for(int i=0;i<componentsChildren.getLength();i++){
|
f@0
|
359 if(NODES.equals(componentsChildren.item(i).getNodeName()))
|
f@0
|
360 nodesTag = (Element)componentsChildren.item(i);
|
f@0
|
361 }
|
f@0
|
362
|
f@0
|
363 NodeList elemList = nodesTag.getElementsByTagName(NODE);
|
f@0
|
364 for(int i=0; i<elemList.getLength();i++){
|
f@0
|
365 Element nodeTag = (Element)elemList.item(i);
|
f@0
|
366 String idAsString = nodeTag.getAttribute(ID);
|
f@0
|
367 String type = nodeTag.getAttribute(TYPE);
|
f@0
|
368 Node prototype = null;
|
f@0
|
369 for(Node n : nList)
|
f@0
|
370 if(n.getType().equals(type)){
|
f@0
|
371 prototype = n;
|
f@0
|
372 break;
|
f@0
|
373 }
|
f@0
|
374 if(prototype == null)
|
f@0
|
375 throw new IOException(
|
f@0
|
376 MessageFormat.format(
|
f@0
|
377 resources.getString("dialog.error.node_type_not_present"),
|
f@0
|
378 type));
|
f@0
|
379 Node node = (Node)prototype.clone();
|
f@0
|
380
|
f@0
|
381 nodesId.put(idAsString, node);
|
f@0
|
382
|
f@0
|
383 try {
|
f@0
|
384 Long id = Long.valueOf(idAsString);
|
f@0
|
385 node.setId(id);
|
f@0
|
386 }catch(NumberFormatException nfe){
|
f@0
|
387 throw new IOException(resources.getString("dialog.error.malformed_file"),nfe);
|
f@0
|
388 }
|
f@0
|
389 collectionModel.insert(node,DiagramEventSource.PERS);
|
f@0
|
390 try{
|
f@0
|
391 node.decode(doc, nodeTag);
|
f@0
|
392 }catch(IOException ioe){ // just give a message to the exception
|
f@0
|
393 throw new IOException(resources.getString("dialog.error.malformed_file"),ioe);
|
f@0
|
394 }
|
f@0
|
395 }
|
f@0
|
396
|
f@0
|
397 Element edgesTag = null;
|
f@0
|
398 for(int i=0;i<componentsChildren.getLength();i++)
|
f@0
|
399 if(EDGES.equals(componentsChildren.item(i).getNodeName()))
|
f@0
|
400 edgesTag = (Element)componentsChildren.item(i);
|
f@0
|
401
|
f@0
|
402 elemList = edgesTag.getElementsByTagName(EDGE);
|
f@0
|
403 for(int i=0; i<elemList.getLength();i++){
|
f@0
|
404 Element edgeTag = (Element)elemList.item(i);
|
f@0
|
405 String type = edgeTag.getAttribute(TYPE);
|
f@0
|
406
|
f@0
|
407 Edge prototype = null;
|
f@0
|
408 for(Edge e : eList)
|
f@0
|
409 if(e.getType().equals(type)){
|
f@0
|
410 prototype = e;
|
f@0
|
411 break;
|
f@0
|
412 }
|
f@0
|
413 if(prototype == null)
|
f@0
|
414 throw new IOException(MessageFormat.format(
|
f@0
|
415 resources.getString("dialog.error.edge_type_not_present"),
|
f@0
|
416 type
|
f@0
|
417 ));
|
f@0
|
418
|
f@0
|
419 Edge edge = (Edge)prototype.clone();
|
f@0
|
420
|
f@0
|
421 try{
|
f@0
|
422 edge.decode(doc, edgeTag, nodesId);
|
f@0
|
423 }catch(IOException ioe){
|
f@0
|
424 throw new IOException(resources.getString("dialog.error.malformed_file"),ioe);
|
f@0
|
425 }
|
f@0
|
426 collectionModel.insert(edge,DiagramEventSource.PERS);
|
f@0
|
427 }
|
f@0
|
428
|
f@0
|
429 /* retrieve bookmarks */
|
f@0
|
430 NodeList bookmarkList = root.getElementsByTagName(BOOKMARK);
|
f@0
|
431 for(int i=0;i<bookmarkList.getLength();i++){
|
f@0
|
432 Element bookmarkTag = (Element)bookmarkList.item(i);
|
f@0
|
433 String key = bookmarkTag.getAttribute(KEY);
|
f@0
|
434 if(key.isEmpty())
|
f@0
|
435 throw new IOException(resources.getString("dialog.error.malformed_file"));
|
f@0
|
436 String path = bookmarkTag.getTextContent();
|
f@0
|
437 DiagramTreeNode treeNode = getTreeNodeFromString(treeModel,path);
|
f@0
|
438 treeModel.putBookmark(key, treeNode,DiagramEventSource.PERS);
|
f@0
|
439 }
|
f@0
|
440
|
f@0
|
441 /* retrieve notes */
|
f@0
|
442 NodeList noteList = root.getElementsByTagName(NOTE);
|
f@0
|
443 for(int i=0;i<noteList.getLength();i++){
|
f@0
|
444 Element noteTag = (Element)noteList.item(i);
|
f@0
|
445 if(noteTag.getElementsByTagName(TREE_NODE).item(0) == null )
|
f@0
|
446 throw new IOException(resources.getString("dialog.error.malformed_file"));
|
f@0
|
447 Element pathTag = (Element)noteTag.getElementsByTagName(TREE_NODE).item(0);
|
f@0
|
448 String path = pathTag.getTextContent();
|
f@0
|
449 if(noteTag.getElementsByTagName(CONTENT).item(0) == null)
|
f@0
|
450 throw new IOException(resources.getString("dialog.error.malformed_file"));
|
f@0
|
451 Element contentTag = (Element)noteTag.getElementsByTagName(CONTENT).item(0);
|
f@0
|
452 String content = CharEscaper.restoreNewline(contentTag.getTextContent());
|
f@0
|
453 DiagramTreeNode treeNode = getTreeNodeFromString(treeModel,path);
|
f@0
|
454 treeModel.setNotes(treeNode,content,DiagramEventSource.PERS);
|
f@0
|
455 }
|
f@0
|
456
|
f@0
|
457 /* normally nodes and edges should be saved in order, this is to prevent *
|
f@0
|
458 * a manual editing of the xml to affect the program logic */
|
f@0
|
459 collectionModel.sort();
|
f@0
|
460 /* we have to do this has the insertion in the model made it modified */
|
f@0
|
461 collectionModel.setUnmodified();
|
f@0
|
462 return diagram;
|
f@0
|
463 }
|
f@0
|
464
|
f@0
|
465 private static void writePrototypes(Document doc, Element root, Diagram diagram){
|
f@0
|
466 Node[] nodes = diagram.getNodePrototypes();
|
f@0
|
467 Edge[] edges = diagram.getEdgePrototypes();
|
f@0
|
468 Element components = doc.createElement(PROTOTYPES);
|
f@0
|
469 root.appendChild(components);
|
f@0
|
470
|
f@0
|
471 PrototypePersistenceDelegate delegate = diagram.getPrototypePersistenceDelegate();
|
f@0
|
472 for(Node n : nodes){
|
f@0
|
473 Element nodeTag = doc.createElement(NODE);
|
f@0
|
474 components.appendChild(nodeTag);
|
f@0
|
475 delegate.encodeNodePrototype(doc, nodeTag, n);
|
f@0
|
476 }
|
f@0
|
477
|
f@0
|
478 for(Edge e : edges){
|
f@0
|
479 Element edgeTag = doc.createElement(EDGE);
|
f@0
|
480 components.appendChild(edgeTag);
|
f@0
|
481 delegate.encodeEdgePrototype(doc, edgeTag, e);
|
f@0
|
482 }
|
f@0
|
483 }
|
f@0
|
484
|
f@0
|
485 private static List<Node> readNodePrototypes(Document doc, PrototypePersistenceDelegate delegate) throws IOException{
|
f@0
|
486 if(doc.getElementsByTagName(PROTOTYPES).item(0) == null)
|
f@0
|
487 throw new IOException(ResourceBundle.getBundle(PersistenceManager.class.getName()).getString("dialog.error.malformed_file"));
|
f@0
|
488 Element prototypesTag = (Element)doc.getElementsByTagName(PROTOTYPES).item(0);
|
f@0
|
489 NodeList elemList = prototypesTag.getElementsByTagName(NODE);
|
f@0
|
490 final List<Node> nList = new ArrayList<Node>(elemList.getLength());
|
f@0
|
491 for(int i=0; i<elemList.getLength();i++){
|
f@0
|
492 Element element = (Element)elemList.item(i);
|
f@0
|
493 try{
|
f@0
|
494 Node n = delegate.decodeNodePrototype(element);
|
f@0
|
495 nList.add(n);
|
f@0
|
496 }catch(IOException ioe){ // just set the message for the exception
|
f@0
|
497 throw new IOException(ResourceBundle.getBundle(PersistenceManager.class.getName()).getString("dialog.error.malformed_file"),ioe);
|
f@0
|
498 }
|
f@0
|
499 }
|
f@0
|
500 return nList;
|
f@0
|
501 }
|
f@0
|
502
|
f@0
|
503 private static List<Edge> readEdgePrototypes(Document doc, PrototypePersistenceDelegate delegate) throws IOException{
|
f@0
|
504 if(doc.getElementsByTagName(PROTOTYPES).item(0) == null)
|
f@0
|
505 throw new IOException(ResourceBundle.getBundle(PersistenceManager.class.getName()).getString("dialog.error.malformed_file"));
|
f@0
|
506 Element prototypesTag = (Element)doc.getElementsByTagName(PROTOTYPES).item(0);
|
f@0
|
507 NodeList elemList = prototypesTag.getElementsByTagName(EDGE);
|
f@0
|
508 final List<Edge> eList = new ArrayList<Edge>(elemList.getLength());
|
f@0
|
509 for(int i=0; i<elemList.getLength();i++){
|
f@0
|
510 Element element = (Element)elemList.item(i);
|
f@0
|
511 try{
|
f@0
|
512 Edge e = delegate.decodeEdgePrototype(element);
|
f@0
|
513 eList.add(e);
|
f@0
|
514 }catch(IOException ioe){
|
f@0
|
515 throw new IOException(ResourceBundle.getBundle(PersistenceManager.class.getName()).getString("dialog.error.malformed_file"),ioe);
|
f@0
|
516 }
|
f@0
|
517 }
|
f@0
|
518 return eList;
|
f@0
|
519 }
|
f@0
|
520
|
f@0
|
521 private static String getTreeNodeAsString(DiagramTreeNode treeNode){
|
f@0
|
522 TreeNode[] path = treeNode.getPath();
|
f@0
|
523 StringBuilder builder = new StringBuilder();
|
f@0
|
524 for(int i=0;i<path.length-1; i++)
|
f@0
|
525 builder.append(String.valueOf(path[i].getIndex(path[i+1]))).append(' ');
|
f@0
|
526 if(builder.toString().endsWith(" "))
|
f@0
|
527 builder.deleteCharAt(builder.length()-1);
|
f@0
|
528 return builder.toString();
|
f@0
|
529
|
f@0
|
530 }
|
f@0
|
531
|
f@0
|
532 private static DiagramTreeNode getTreeNodeFromString(TreeModel<Node,Edge> model, String path) throws IOException{
|
f@0
|
533 DiagramTreeNode treeNode = (DiagramTreeNode)model.getRoot();
|
f@0
|
534 if(ROOT_AS_STRING.equals(path))
|
f@0
|
535 return treeNode;
|
f@0
|
536 String[] nodesAsString = path.split(" ");
|
f@0
|
537
|
f@0
|
538 try {
|
f@0
|
539 for(String nodeAsString : nodesAsString)
|
f@0
|
540 treeNode = (DiagramTreeNode) treeNode.getChildAt(Integer.parseInt(nodeAsString));
|
f@0
|
541 }catch(Exception e){
|
f@0
|
542 throw new IOException(e);
|
f@0
|
543 }
|
f@0
|
544 return treeNode;
|
f@0
|
545 }
|
f@0
|
546
|
f@0
|
547 public final static String NAME = "Name";
|
f@0
|
548 public final static String DIAGRAM = "Diagram";
|
f@0
|
549 public final static String PROTOTYPE_PERSISTENCE_DELEGATE = "PrototypeDelegate";
|
f@0
|
550 public final static String COMPONENTS = "Components";
|
f@0
|
551 public final static String PROTOTYPES = "Prototypes";
|
f@0
|
552 public final static String NODE = "Node";
|
f@0
|
553 public final static String NODES = "Nodes";
|
f@0
|
554 public final static String EDGE = "Edge";
|
f@0
|
555 public final static String EDGES = "Edges";
|
f@0
|
556 public final static String POSITION = "Position";
|
f@0
|
557 public final static String PROPERTIES = "Properties";
|
f@0
|
558 public final static String PROPERTY = "Property";
|
f@0
|
559 public final static String TYPE = "Type";
|
f@0
|
560 public final static String VALUE = "Value";
|
f@0
|
561 public final static String ELEMENT = "Element";
|
f@0
|
562 public static final String LABEL = "Label";
|
f@0
|
563 public final static String POINTS = "Points";
|
f@0
|
564 public final static String POINT = "Point";
|
f@0
|
565 public final static String ID = "id";
|
f@0
|
566 public final static String NEIGHBOURS = "Neighbours";
|
f@0
|
567 public static final String MODIFIER = "Modifier";
|
f@0
|
568 public static final String MODIFIERS = "Modifiers";
|
f@0
|
569 public static final String X = "x";
|
f@0
|
570 public static final String Y = "y";
|
f@0
|
571 public static final String BOOKMARKS = "Bookmarks";
|
f@0
|
572 public static final String BOOKMARK = "Bookmark";
|
f@0
|
573 public static final String KEY = "Key";
|
f@0
|
574 public static final String NOTES = "Notes";
|
f@0
|
575 public static final String NOTE = "Note";
|
f@0
|
576 public static final String CONTENT = "Content";
|
f@0
|
577 public static final String TREE_NODE = "TreeNode";
|
f@0
|
578 private static final String ROOT_AS_STRING = "-1";
|
f@0
|
579 }
|