]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.graphfile/src/org/simantics/graphfile/util/GraphFileUtil.java
d106f474663d0de50b2fbef0916238f1da162d81
[simantics/platform.git] / bundles / org.simantics.graphfile / src / org / simantics / graphfile / util / GraphFileUtil.java
1 /*******************************************************************************\r
2  * Copyright (c) 2013 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.graphfile.util;\r
13 \r
14 import java.io.File;\r
15 import java.io.FileInputStream;\r
16 import java.io.FileOutputStream;\r
17 import java.io.IOException;\r
18 import java.nio.ByteBuffer;\r
19 import java.nio.channels.FileChannel;\r
20 import java.util.Collection;\r
21 import java.util.HashMap;\r
22 import java.util.Map;\r
23 \r
24 import org.simantics.Simantics;\r
25 import org.simantics.databoard.Bindings;\r
26 import org.simantics.databoard.util.binary.RandomAccessBinary;\r
27 import org.simantics.db.ReadGraph;\r
28 import org.simantics.db.Resource;\r
29 import org.simantics.db.WriteGraph;\r
30 import org.simantics.db.common.request.ReadRequest;\r
31 import org.simantics.db.common.request.WriteRequest;\r
32 import org.simantics.db.common.utils.LiteralFileUtil;\r
33 import org.simantics.db.exception.DatabaseException;\r
34 import org.simantics.db.exception.DoesNotContainValueException;\r
35 import org.simantics.db.exception.ManyObjectsForFunctionalRelationException;\r
36 import org.simantics.db.exception.NoSingleResultException;\r
37 import org.simantics.db.exception.ServiceException;\r
38 import org.simantics.db.request.Read;\r
39 import org.simantics.db.service.ClusteringSupport;\r
40 import org.simantics.graphfile.ontology.GraphFileResource;\r
41 import org.simantics.layer0.Layer0;\r
42 \r
43 /**\r
44  * @author Marko Luukkainen\r
45  */\r
46 public class GraphFileUtil {\r
47         \r
48         \r
49         public static boolean USE_RANDOM_ACCESS_BINARY = true;\r
50         /**\r
51          * Creates a temp file of a graphFile.\r
52          * @param res\r
53          * @return\r
54          * @throws DatabaseException\r
55          */\r
56         public static File toTempFile(final Resource res)throws DatabaseException {\r
57                 return Simantics.getSession().syncRequest(new Read<File>() {\r
58                         @Override\r
59                         public File perform(ReadGraph graph) throws DatabaseException {\r
60                                 return toTempFile(graph, res);\r
61                         }\r
62                 });\r
63         }\r
64 \r
65         /**\r
66          * Creates a temp file of a graphFile.\r
67          * @param graph\r
68          * @param res\r
69          * @return\r
70          * @throws DatabaseException\r
71          */\r
72         public static File toTempFile(ReadGraph graph, Resource res)throws DatabaseException {\r
73 \r
74                 GraphFileResource gf = GraphFileResource.getInstance(graph);\r
75                 String filename = graph.getRelatedValue(res, gf.HasResourceName);\r
76                 \r
77                 int index = filename.lastIndexOf(".");\r
78                 String name = "";\r
79                 String ext = "";\r
80                 if (index > 0) {\r
81                         name = filename.substring(0,index);\r
82                         ext = filename.substring(index+1);\r
83                 } else {\r
84                         name = filename;\r
85                 }\r
86                 if (name.length() < 3) {\r
87                         for (int i = name.length(); i < 3; i++)\r
88                                 name += "_";\r
89                 }\r
90                 try {\r
91                         File file = File.createTempFile(name, "."+ ext);\r
92                         writeDataToFile(graph, res, file);\r
93                         return file;\r
94                 } catch (Exception e) {\r
95                         throw new DatabaseException(e);\r
96                 }\r
97         }\r
98         \r
99         public static void writeDataToFile(final Resource res, final File file) throws DatabaseException{\r
100                 Simantics.getSession().syncRequest(new ReadRequest() {\r
101                         \r
102                         @Override\r
103                         public void run(ReadGraph graph) throws DatabaseException {\r
104                                 try {\r
105                                         writeDataToFile(graph, res, file);\r
106                                 } catch (IOException e) {\r
107                                         throw new DatabaseException(e);\r
108                                 }\r
109                         }\r
110                 });\r
111         }\r
112         \r
113         /**\r
114          * Writes contents of a graphFile to file.\r
115          * @param graph\r
116          * @param res\r
117          * @param file\r
118          * @throws DatabaseException\r
119          * @throws IOException\r
120          */\r
121         public static void writeDataToFile(ReadGraph graph, Resource res, File file) throws DatabaseException, IOException {\r
122                 \r
123                 GraphFileResource gf = GraphFileResource.getInstance(graph);\r
124                 if (USE_RANDOM_ACCESS_BINARY) {\r
125                         Resource filedata = graph.getSingleObject(res, gf.HasFiledata);\r
126                         LiteralFileUtil.copyRandomAccessBinaryToFile(graph, filedata, file);\r
127                 } else {\r
128                 \r
129                         byte[] data = graph.getRelatedValue(res, gf.HasFiledata);\r
130                         FileOutputStream fos = new FileOutputStream(file);\r
131                         fos.write(data);\r
132                         fos.flush();\r
133                         fos.close();\r
134                 \r
135                 }\r
136                 Long lastModified = graph.getPossibleRelatedValue(res, gf.LastModified);\r
137                 if (lastModified != null)\r
138                         file.setLastModified(lastModified);\r
139         }\r
140 \r
141         /**\r
142          * Updates contents of a graphFile, including the name.\r
143          * @param filename\r
144          * @param graphFile\r
145          * @throws DatabaseException\r
146          */\r
147         public static void toGraph(final String filename, final Resource graphFile)throws DatabaseException {\r
148                 Simantics.getSession().syncRequest(new WriteRequest() {\r
149                         @Override\r
150                         public void perform(WriteGraph graph) throws DatabaseException {\r
151                                 try {\r
152                                         toGraph(graph, filename,graphFile);\r
153                                 } catch (IOException e) {\r
154                                         throw new DatabaseException(e);\r
155                                 }\r
156                         }\r
157                 });\r
158         }\r
159         \r
160         /**\r
161          * Updates contents of a graphFile, including the name.\r
162          * @param graph\r
163          * @param filename\r
164          * @param graphFile\r
165          * @throws DatabaseException\r
166          * @throws IOException\r
167          */\r
168         public static void toGraph(WriteGraph graph, String filename, Resource graphFile) throws DatabaseException, IOException {\r
169                 File file = new File(filename);\r
170                 if (!file.exists())\r
171                         throw new IOException("File " + filename + " not found.");\r
172                 \r
173                 toGraph(graph, file, graphFile);\r
174         }\r
175         \r
176         /**\r
177          * Updates contents of a graphFile, including the name.\r
178          * @param graph\r
179          * @param file\r
180          * @param graphFile\r
181          * @throws DatabaseException\r
182          * @throws IOException\r
183          */\r
184         public static void toGraph(WriteGraph graph, File file, Resource graphFile) throws DatabaseException, IOException {\r
185 \r
186                 writeDataToGraph(graph, file, graphFile);\r
187                 String name = file.getName();\r
188                 GraphFileResource gf = GraphFileResource.getInstance(graph);\r
189                 graph.claimLiteral(graphFile, gf.HasResourceName, name);\r
190                 \r
191         }\r
192         \r
193         /**\r
194          * Writes contents of a file to a graphFile (data and time stamp).\r
195          * @param graph\r
196          * @param file\r
197          * @param graphFile\r
198          * @throws IOException\r
199          * @throws ManyObjectsForFunctionalRelationException\r
200          * @throws ServiceException\r
201          */\r
202         public static void writeDataToGraph(WriteGraph graph, File file, Resource graphFile) throws IOException, DatabaseException{\r
203                 GraphFileResource gf = GraphFileResource.getInstance(graph);\r
204                 if (USE_RANDOM_ACCESS_BINARY) {\r
205                         \r
206                         Resource fileData = graph.getPossibleObject(graphFile, gf.HasFiledata);\r
207                         RandomAccessBinary rab = null;\r
208                         if (fileData == null) {\r
209                                 Layer0 l0 = Layer0.getInstance(graph);\r
210                                 ClusteringSupport cs = graph.getService(ClusteringSupport.class);\r
211                                 fileData = graph.newResource(cs.createCluster());\r
212                                 graph.claim(fileData, l0.InstanceOf, l0.ByteArray);\r
213                                 graph.claim(graphFile, gf.HasFiledata, fileData);\r
214                                 rab = graph.createRandomAccessBinary(fileData, Bindings.BYTE_ARRAY.type(), null);\r
215                         } else {\r
216                                 rab = graph.getRandomAccessBinary(fileData);\r
217                         }\r
218                         LiteralFileUtil.copyRandomAccessBinaryFromFile(file, rab);\r
219                 } else {\r
220                         FileInputStream stream = new FileInputStream(file);\r
221                         FileChannel chan = stream.getChannel();\r
222                         long lsize = chan.size();\r
223                         if (lsize > Integer.MAX_VALUE)\r
224                                 throw new IOException("File is too big");\r
225                         int size = (int)lsize;\r
226                         final byte[] array = new byte[size];\r
227                         ByteBuffer buf = ByteBuffer.wrap(array);\r
228                         while (size > 0)\r
229                                 size -= chan.read(buf);\r
230                         \r
231                         graph.claimLiteral(graphFile, gf.HasFiledata, array);\r
232                         chan.close();\r
233                         stream.close();\r
234                 }\r
235 \r
236                 graph.claimLiteral(graphFile, gf.LastModified, file.lastModified());\r
237                 \r
238         }\r
239         \r
240         public static void writeDataToGraph(WriteGraph graph, byte data[], Resource graphFile) throws IOException, ManyObjectsForFunctionalRelationException, ServiceException {\r
241                 \r
242                 GraphFileResource gf = GraphFileResource.getInstance(graph);\r
243                 graph.claimLiteral(graphFile, gf.HasFiledata, data);\r
244                 graph.claimLiteral(graphFile, gf.LastModified, 0L);\r
245         }\r
246         \r
247         /**\r
248          * Writes contents of a file to a graphFile (data and time stamp).\r
249          * @param file\r
250          * @param graphFile\r
251          * @throws DatabaseException\r
252          */\r
253         public static void writeDataToGraph(final File file, final Resource graphFile) throws DatabaseException {\r
254                 Simantics.getSession().syncRequest(new WriteRequest() {\r
255                         \r
256                         @Override\r
257                         public void perform(WriteGraph graph) throws DatabaseException {\r
258                                 try {\r
259                                         writeDataToGraph(graph, file, graphFile);\r
260                                 } catch (IOException e) {\r
261                                         throw new DatabaseException(e);\r
262                                 }\r
263                                 \r
264                         }\r
265                 });\r
266         }\r
267         \r
268         public static void syncFolderToGraph(WriteGraph g, File folder, Resource folderRes) throws Exception {\r
269                 File subFiles[] = folder.listFiles();\r
270                 Layer0 l0 = Layer0.getInstance(g);\r
271                 GraphFileResource gf = GraphFileResource.getInstance(g);\r
272                 Collection<Resource> subFileResources = g.getObjects(folderRes, gf.HasFile);\r
273                 Collection<Resource> subFolderResources = g.getObjects(folderRes, gf.HasFolder);\r
274                                 \r
275                 Map<Resource,File> matching = new HashMap<Resource, File>();\r
276                 \r
277                 for (File f : subFiles) {\r
278                         String name = f.getName();\r
279                         if (f.isDirectory()) {\r
280                                 Resource matchingFolder = findWithName(g, subFolderResources, name);\r
281 \r
282                                 if (matchingFolder != null) {\r
283                                         if (matching.containsKey(matchingFolder))\r
284                                                 throw new Exception("Matching folder already in use" + f.getAbsolutePath() + " " + matchingFolder);\r
285                                         \r
286                                         matching.put(matchingFolder, f);\r
287                                         syncFolderToGraph(g, f, matchingFolder);\r
288                                 } else {\r
289                                         matchingFolder = g.newResource();\r
290                                         g.claim(matchingFolder, l0.InstanceOf, gf.Folder);\r
291                                         g.claimLiteral(matchingFolder, gf.HasResourceName, name);\r
292                                         g.claimLiteral(matchingFolder, l0.HasName, name);\r
293                                         g.claim(folderRes, gf.HasFolder, matchingFolder);\r
294                                         matching.put(matchingFolder, f);\r
295                                         syncFolderToGraph(g, f, matchingFolder);\r
296                                 }\r
297                         } else { //file\r
298                                 Resource fileRes = findWithName(g, subFileResources, name);\r
299                                 if (fileRes != null) {\r
300                                         if (matching.containsKey(fileRes))\r
301                                                 throw new Exception("Matching file already in use" + f.getAbsolutePath() + " " + fileRes);\r
302                                         matching.put(fileRes, f);\r
303                                         toGraph(g, f, fileRes);\r
304                                 } else {\r
305                                         fileRes = g.newResource();\r
306                                         g.claim(fileRes, l0.InstanceOf, gf.File);\r
307                                         g.claimLiteral(fileRes, gf.HasResourceName, name);\r
308                                         g.claimLiteral(fileRes, l0.HasName, name);\r
309                                         g.claim(folderRes, gf.HasFile, fileRes);\r
310                                         matching.put(fileRes, f);\r
311                                         toGraph(g, f, fileRes);\r
312                                 }\r
313                         }\r
314                 }\r
315                 // delete resources, which have no matching file (or folder)\r
316                 for (Resource subFolder : subFolderResources) {\r
317                         if (!matching.containsKey(subFolder))\r
318                                 g.deny(subFolder);\r
319                 }\r
320                 \r
321                 for (Resource subFolder : subFileResources) {\r
322                         if (!matching.containsKey(subFolder))\r
323                                 g.deny(subFolder);\r
324                 }\r
325         }\r
326         \r
327         public static void writeFolderToDisk(ReadGraph g, Resource folderRes, File folder) throws DatabaseException, IOException{\r
328 \r
329                 GraphFileResource gf = GraphFileResource.getInstance(g);\r
330                 for (Resource subFolder : g.getObjects(folderRes, gf.HasFolder)) {\r
331                         String name = g.getRelatedValue(subFolder, gf.HasResourceName);\r
332 \r
333                         if (name.length() == 0)\r
334                                 throw new DatabaseException("Empty folder name for " + subFolder);\r
335                         \r
336                         File newFolder = new File(folder.getAbsolutePath() + "/" + name);\r
337                         if (!newFolder.mkdir()) {\r
338                                 throw new DatabaseException("Could not create folder " + name + " for resource " + subFolder);\r
339                         }\r
340                         writeFolderToDisk(g, subFolder, newFolder);\r
341                 }\r
342                 for (Resource fileRes : g.getObjects(folderRes, gf.HasFile)) {\r
343                         String name = g.getRelatedValue(fileRes, gf.HasResourceName);\r
344                         File file = new File(folder.getAbsolutePath() + "/" + name);\r
345                         writeDataToFile(g, fileRes, file);\r
346                 }\r
347         }\r
348         \r
349         public static void syncFolderToGraph(WriteGraph g, File folder, Resource folderRes, ToGraphHelper helper) throws Exception {\r
350                 File subFiles[] = folder.listFiles();\r
351                 GraphFileResource gf = GraphFileResource.getInstance(g);\r
352                 Collection<Resource> subFileResources = g.getObjects(folderRes, gf.HasFile);\r
353                 Collection<Resource> subFolderResources = g.getObjects(folderRes, gf.HasFolder);\r
354                                 \r
355                 Map<Resource,File> matching = new HashMap<Resource, File>();\r
356                 \r
357                 for (File f : subFiles) {\r
358                         String name = f.getName();\r
359                         if (f.isDirectory()) {\r
360                                 Resource matchingFolder = helper.findFolder(g, subFolderResources, name);\r
361 \r
362                                 if (matchingFolder != null) {\r
363                                         if (matching.containsKey(matchingFolder))\r
364                                                 throw new Exception("Matching folder already in use" + f.getAbsolutePath() + " " + matchingFolder);\r
365                                         \r
366                                         matching.put(matchingFolder, f);\r
367                                         syncFolderToGraph(g, f, matchingFolder,helper);\r
368                                 } else {\r
369                                         matchingFolder = helper.createFolder(g, name);\r
370                                         g.claim(folderRes, gf.HasFolder, matchingFolder);\r
371                                         matching.put(matchingFolder, f);\r
372                                         syncFolderToGraph(g, f, matchingFolder,helper);\r
373                                 }\r
374                         } else { //file\r
375                                 Resource fileRes = helper.findFile(g, subFileResources, name);\r
376                                 if (fileRes != null) {\r
377                                         if (matching.containsKey(fileRes))\r
378                                                 throw new Exception("Matching file already in use" + f.getAbsolutePath() + " " + fileRes);\r
379                                         matching.put(fileRes, f);\r
380                                         toGraph(g, f, fileRes);\r
381                                 } else {\r
382                                         fileRes = helper.createFile(g, name);\r
383                                         g.claim(folderRes, gf.HasFile, fileRes);\r
384                                         matching.put(fileRes, f);\r
385                                         toGraph(g, f, fileRes);\r
386                                 }\r
387                         }\r
388                 }\r
389                 // delete resources, which have no matching file (or folder)\r
390                 for (Resource subFolder : subFolderResources) {\r
391                         if (!matching.containsKey(subFolder))\r
392                                 g.deny(subFolder);\r
393                 }\r
394                 \r
395                 for (Resource subFolder : subFileResources) {\r
396                         if (!matching.containsKey(subFolder))\r
397                                 g.deny(subFolder);\r
398                 }\r
399         }\r
400         \r
401         public static interface ToGraphHelper {\r
402                 public Resource findFolder(ReadGraph g, Collection<Resource> subFolderResources, String name) throws DatabaseException;\r
403                 public Resource createFolder(WriteGraph g, String name) throws DatabaseException;\r
404                 public Resource findFile(ReadGraph g, Collection<Resource> subFileResources, String name) throws DatabaseException;\r
405                 public Resource createFile(WriteGraph g, String name) throws DatabaseException;\r
406         }\r
407         \r
408         public static interface ToDiskHelper {\r
409                 public String getName(ReadGraph g, Resource systemResource) throws DatabaseException;\r
410         }\r
411         \r
412         public static void writeFolderToDisk(ReadGraph g, Resource folderRes, File folder, ToDiskHelper helper) throws DatabaseException, IOException{\r
413                 GraphFileResource gf = GraphFileResource.getInstance(g);\r
414                 for (Resource subFolder : g.getObjects(folderRes, gf.HasFolder)) {\r
415                         String name = helper.getName(g, subFolder);\r
416 \r
417                         if (name.length() == 0)\r
418                                 throw new DatabaseException("Empty folder name for " + subFolder);\r
419                         \r
420                         File newFolder = new File(folder.getAbsolutePath() + "/" + name);\r
421                         if (!newFolder.mkdir()) {\r
422                                 throw new DatabaseException("Could not create folder " + name + " for resource " + subFolder);\r
423                         }\r
424                         writeFolderToDisk(g, subFolder, newFolder, helper);\r
425                 }\r
426                 for (Resource fileRes : g.getObjects(folderRes, gf.HasFile)) {\r
427                         String name = helper.getName(g, fileRes);\r
428                         File file = new File(folder.getAbsolutePath() + "/" + name);\r
429                         writeDataToFile(g, fileRes, file);\r
430                 }\r
431         }\r
432         \r
433         public static interface ToDiskHelper2 extends ToDiskHelper {\r
434                 public Resource findFolder(ReadGraph g, Collection<Resource> subFolderResources, String name) throws DatabaseException;\r
435                 public Resource findFile(ReadGraph g, Collection<Resource> subFileResources, String name) throws DatabaseException;\r
436         }\r
437         \r
438         public static void syncFolderToDisk(ReadGraph g, Resource folderRes, File folder, ToDiskHelper2 helper) throws Exception {\r
439                 File subFiles[] = folder.listFiles();\r
440                 GraphFileResource gf = GraphFileResource.getInstance(g);\r
441                 Collection<Resource> subFileResources = g.getObjects(folderRes, gf.HasFile);\r
442                 Collection<Resource> subFolderResources = g.getObjects(folderRes, gf.HasFolder);\r
443                                 \r
444                 Map<Resource,File> matching = new HashMap<Resource, File>();\r
445                 \r
446                 for (File f : subFiles) {\r
447                         String name = f.getName();\r
448                         if (f.isDirectory()) {\r
449                                 Resource matchingFolder = helper.findFolder(g, subFolderResources, name);\r
450 \r
451                                 if (matchingFolder != null) {\r
452                                         if (matching.containsKey(matchingFolder))\r
453                                                 throw new Exception("Matching folder already in use" + f.getAbsolutePath() + " " + matchingFolder);\r
454                                         \r
455                                         matching.put(matchingFolder, f);\r
456                                         syncFolderToDisk(g, matchingFolder, f, helper);\r
457                                 } else {\r
458                                         deleteDirectoryStructure(f);\r
459                                 }\r
460                         } else { //file\r
461                                 Resource fileRes = helper.findFile(g, subFileResources, name);\r
462                                 if (fileRes != null) {\r
463                                         if (matching.containsKey(fileRes))\r
464                                                 throw new Exception("Matching file already in use" + f.getAbsolutePath() + " " + fileRes);\r
465                                         matching.put(fileRes, f);\r
466                                         writeDataToFile(g, fileRes, f);\r
467                                 } else {\r
468                                         if (!f.delete())\r
469                                         throw new Exception("Cannot delete file " + f.getAbsolutePath());\r
470                                 }\r
471                         }\r
472                 }\r
473                 // create files and folders, which have no matching graphFile (or folder)\r
474                 for (Resource subFolder : subFolderResources) {\r
475                         if (!matching.containsKey(subFolder)) {\r
476                                 String name = helper.getName(g, subFolder);\r
477 \r
478                                 if (name.length() == 0)\r
479                                         throw new DatabaseException("Empty folder name for " + subFolder);\r
480                                 \r
481                                 File newFolder = new File(folder.getAbsolutePath() + "/" + name);\r
482                                 if (!newFolder.mkdir()) {\r
483                                         throw new DatabaseException("Could not create folder " + name + " for resource " + subFolder);\r
484                                 }\r
485                                 writeFolderToDisk(g, subFolder, newFolder, helper);\r
486                         }\r
487                 }\r
488                 \r
489                 for (Resource fileRes : subFileResources) {\r
490                         if (!matching.containsKey(fileRes)) {\r
491                                 String name = helper.getName(g, fileRes);\r
492                                 File file = new File(folder.getAbsolutePath() + "/" + name);\r
493                                 writeDataToFile(g, fileRes, file);\r
494                         }\r
495                 }\r
496                 \r
497         }\r
498         \r
499         \r
500         \r
501         public static Resource findWithName(ReadGraph g, Collection<Resource> resources, String name) throws ServiceException, NoSingleResultException, DoesNotContainValueException {\r
502                 GraphFileResource gf = GraphFileResource.getInstance(g);\r
503                 for (Resource r : resources)\r
504                         if (name.equals(g.getRelatedValue(r, gf.HasResourceName)))\r
505                                 return r;\r
506                 return null;\r
507         }\r
508         \r
509         /**\r
510          * Deletes the directory and all it contents.\r
511          * @param dir\r
512          * @throws Exception\r
513          */\r
514         public static void deleteDirectoryStructure(File dir) throws Exception{\r
515                 deleteDirectoryStructure(dir, true);\r
516         }\r
517         \r
518         /**\r
519          * Deletes the directory's contents, but does not delete the directory.\r
520          * @param dir\r
521          * @throws Exception\r
522          */\r
523         public static void clearDirectoryStructure(File dir) throws Exception{\r
524                 deleteDirectoryStructure(dir, false);\r
525         }\r
526         \r
527         private static void deleteDirectoryStructure(File dir, boolean deleteDir) throws Exception{\r
528                 File subFiles[] = dir.listFiles();\r
529                 for (File f : subFiles) {\r
530                         if (f.isDirectory())\r
531                                 deleteDirectoryStructure(f,true);\r
532                         else\r
533                                 if (!f.delete()) {\r
534                                         throw new Exception("Cannot delete file " + f.getAbsolutePath());\r
535                                 }\r
536                 }\r
537                 if (deleteDir) {\r
538                         if (!dir.delete()) {\r
539                                 throw new Exception("Cannot delete folder " + dir.getAbsolutePath());\r
540                         }\r
541                 }\r
542         }\r
543 }\r