]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.document/src/org/simantics/document/FileDocumentUtil.java
4fc2eb93d7e00452bea8db4f0f188d7714495d8d
[simantics/platform.git] / bundles / org.simantics.document / src / org / simantics / document / FileDocumentUtil.java
1 package org.simantics.document;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.FileInputStream;
6 import java.io.IOException;
7 import java.io.InputStreamReader;
8 import java.io.PrintStream;
9 import java.util.Collection;
10 import java.util.HashSet;
11 import java.util.Set;
12
13 import org.eclipse.core.runtime.IProgressMonitor;
14 import org.simantics.Simantics;
15 import org.simantics.db.ReadGraph;
16 import org.simantics.db.Resource;
17 import org.simantics.db.WriteGraph;
18 import org.simantics.db.common.request.ReadRequest;
19 import org.simantics.db.common.request.WriteRequest;
20 import org.simantics.db.common.request.WriteResultRequest;
21 import org.simantics.db.exception.DatabaseException;
22 import org.simantics.graphfile.ontology.GraphFileResource;
23 import org.simantics.graphfile.util.GraphFileUtil;
24 import org.simantics.layer0.Layer0;
25 import org.simantics.utils.ui.ExceptionUtils;
26
27 /**
28  * 
29  * @author Marko Luukkainen <marko.luukkainen@vtt.fi>
30  *
31  */
32 public class FileDocumentUtil {
33         
34         /**
35          * Imports file, sets its L0.hasName, and and adds it to a library
36          * 
37          * Note: if library relation is L0.ConsistsOf, L0.HasName is set to next available unique name.
38          * 
39          * @param fileName
40          * @param lib
41          * @param rel
42          * @throws DatabaseException 
43          */
44         public static Resource importFile(final String fileName, final Resource lib, final Resource rel) throws DatabaseException {
45                 return Simantics.getSession().syncRequest(new WriteResultRequest<Resource>() {
46                         @Override
47                         public Resource perform(WriteGraph graph) throws DatabaseException {
48                                 return importFile(graph, fileName,lib,rel);
49                         }
50                 });
51                         
52                 
53         }
54         
55         public static void importFileAsync(final String fileName, final Resource lib, final Resource rel)  {
56                 Simantics.getSession().asyncRequest(new WriteRequest() {
57                         
58                         @Override
59                         public void perform(WriteGraph graph) throws DatabaseException {
60                                  importFile(graph, fileName,lib,rel);
61                                 
62                         }
63                 }, e -> {
64                         if (e != null)
65                                 ExceptionUtils.logAndShowError("Cannot import file " + fileName, e);
66                 });
67                         
68                 
69         }
70         
71         /**
72          * Imports file, sets its L0.HasName, and and adds it to a library
73          * 
74          * Note: if library relation is L0.ConsistsOf, L0.HasName is set to next available unique name.
75          * 
76          * @param graph
77          * @param fileName
78          * @param lib
79          * @param rel
80          * @throws DatabaseException
81          */
82         public static Resource importFile(WriteGraph graph, String fileName, Resource lib, Resource rel) throws DatabaseException{
83                 Layer0 l0 = Layer0.getInstance(graph);
84                 Resource fileResource = importFile(graph, fileName);
85                 graph.claim(lib, rel, fileResource);
86                 File file = new File(fileName);
87                 String name = file.getName();
88                 graph.claimLiteral(fileResource, l0.HasName, name);
89                 setUniqueName(graph, fileResource, lib, rel);
90                 return fileResource;
91         }
92         
93         public static Resource importFileWithName(WriteGraph graph, String fileName) throws DatabaseException{
94                 Layer0 l0 = Layer0.getInstance(graph);
95                 Resource fileResource = importFile(graph, fileName);
96                 File file = new File(fileName);
97                 String name = file.getName();
98                 graph.claimLiteral(fileResource, l0.HasName, name);
99                 return fileResource;
100         }
101         
102         /**
103          * Imports folder of documents recursively (including all sub folders). 
104          * @param graph
105          * @param folderName  Name of imported folder
106          * @param lib         Library, where imported folder is attached.
107          * @param folderType  Type of folders
108          * @param relation    Relation used to create file/folder hierarchy
109          * @return            the imported folder
110          * @throws DatabaseException
111          */
112         public static Resource importFolderWithName(WriteGraph graph, String folderName, Resource lib, Resource folderType, Resource relation, IProgressMonitor monitor) throws Exception{
113                 Resource folderRes = importFolderWithName(graph, folderName, folderType, relation,monitor);
114                 graph.claim(lib, relation, folderRes);
115                 FileDocumentUtil.createUniqueName(graph, folderRes);
116                 return folderRes;
117         }
118         
119         /**
120          * Imports folder of documents recursively (including all sub folders). 
121          * @param graph
122          * @param folderName  Name of imported folder
123          * @param folderType  Type of folders
124          * @param relation    Relation used to create file/folder hierarchy
125          * @param monitor     ProgessMonitor or null
126          * @return            the imported folder
127          * @throws DatabaseException
128          */
129         public static Resource importFolderWithName(WriteGraph graph, String folderName, Resource folderType, Resource relation, IProgressMonitor monitor) throws Exception{
130                 Layer0 l0 = Layer0.getInstance(graph);
131                 File folder = new File(folderName);
132                 Resource rootFolderRes = graph.newResource();
133                 graph.claim(rootFolderRes, l0.InstanceOf, folderType);
134                 graph.claimLiteral(rootFolderRes, l0.HasName, folder.getName());
135                 importFolder(graph, folder, rootFolderRes, relation, monitor);
136                 return rootFolderRes;
137         }
138         
139         /**
140          * Imports folder of documents recursively (including all sub folders).
141          * @param graph
142          * @param folder            Imported folder
143          * @param folderResource    Resource folder matching file system folder
144          * @param relation          Relation used to create file/folder hierarchy
145          * @throws DatabaseException
146          */
147         public static void importFolder(WriteGraph graph, File folder, Resource folderResource, Resource relation, IProgressMonitor monitor) throws Exception{
148                 if (monitor != null) {
149                         int count = _countFiles(folder);
150                         monitor.beginTask("Import files", count);
151                 }
152                 _importFolder(graph, folder, folderResource, relation, monitor);
153                 if (monitor != null)
154                         monitor.done();
155         }
156         
157         private static void _importFolder(WriteGraph graph, File folder, Resource folderResource, Resource relation, IProgressMonitor monitor) throws Exception{
158                 Layer0 l0 = Layer0.getInstance(graph);
159                 File files[] = folder.listFiles();
160                 for (File f : files) {
161                         if (f.isDirectory()) {
162                                 Resource newFolderRes = graph.newResource();
163                                 graph.claim(newFolderRes, l0.InstanceOf, graph.getSingleType(folderResource));
164                                 graph.claim(folderResource, relation, newFolderRes);
165                                 graph.claimLiteral(newFolderRes, l0.HasName, f.getName());
166                                 _importFolder(graph, f, newFolderRes, relation,monitor);
167                         } else {
168                                 Resource fileRes = null;
169                                 if (isUrl(f)) {
170                                 } else {
171                                     fileRes = importURL(graph, f);
172                                         fileRes = importFileWithName(graph, f.getAbsolutePath());
173                                 }
174                                 graph.claim(folderResource, relation, fileRes);
175                                 if (monitor != null)
176                                         monitor.worked(1);
177                         }
178                 }
179         }
180         
181         private static int _countFiles(File folder) {
182                 
183                 int count = 0;
184                 File files[] = folder.listFiles();
185                 for (File f : files) {
186                         if (f.isDirectory()) {
187                                 count += _countFiles(f);
188                         } else {
189                                 count++;
190                         }
191                 }
192                 return count;
193         }
194         
195         
196         public static void createUniqueName(WriteGraph graph, Resource document) throws DatabaseException {
197                 Layer0 l0 = Layer0.getInstance(graph);
198                 Resource lib = graph.getPossibleObject(document, l0.PartOf);
199                 if (lib == null)
200                         return;
201                 setUniqueName(graph, document, lib, l0.ConsistsOf);
202         }
203         
204         public static void setUniqueName(WriteGraph graph, Resource res, Resource lib, Resource rel) throws DatabaseException{
205                 Layer0 l0 = Layer0.getInstance(graph);
206                 Set<String> names = new HashSet<String>();
207                 for (Resource r : graph.getObjects(lib, rel)) {
208                         if (r.equals(res))
209                                 continue;
210                         names.add((String)graph.getRelatedValue(r, l0.HasName));
211                 }
212                 String name = graph.getRelatedValue(res, l0.HasName);
213                 if (!names.contains(name))
214                         return;
215                 int i = 1;
216                 while (true) {
217                         String proposal = name +" (" + i +")";
218                         if (!names.contains(proposal)) {
219                                 graph.claimLiteral(res, l0.HasName, proposal);
220                                 return;
221                         }
222                         i++;
223                 }
224                 
225         }
226         
227         /**
228          * Imports a file
229          * 
230          * @param graph
231          * @param fileName
232          * @return
233          * @throws DatabaseException
234          */
235         public static Resource importFile(WriteGraph graph, String fileName) throws DatabaseException{
236                 Layer0 l0 = Layer0.getInstance(graph);
237                 DocumentResource doc = DocumentResource.getInstance(graph);
238                 
239                 Resource fileResource = graph.newResource();
240                 graph.claim(fileResource, l0.InstanceOf, doc.FileDocument);
241                 try {
242                         GraphFileUtil.toGraph(graph,fileName, fileResource);
243                         
244                 } catch (IOException e) {
245                         throw new DatabaseException(e);
246                 }
247                 return fileResource;
248                 
249         }
250         
251         /**
252          * Exports graph folder recursively to file system. 
253          * @param graph
254          * @param folderResource
255          * @param folder
256          * @param relation
257          * @throws DatabaseException
258          */
259         public static void exportDocumentFolder(final Resource folderResource, final File folder, final Resource relation, boolean useResourceNames, final IProgressMonitor monitor) throws Exception{
260                 Simantics.getSession().syncRequest(new ReadRequest() {
261                         
262                         @Override
263                         public void run(ReadGraph graph) throws DatabaseException {
264                                 try {
265                                         exportDocumentFolder(graph, folderResource, folder, relation, useResourceNames, monitor);
266                                 } catch (Exception e) {
267                                         throw new DatabaseException(e);
268                                 }
269                                 
270                         }
271                 });
272         }
273         
274         
275         /**
276          * Exports graph folder recursively to file system. 
277          * @param graph
278          * @param folderResource
279          * @param folder
280          * @param relation
281          * @throws DatabaseException
282          */
283         public static void exportDocumentFolder(ReadGraph graph, Resource folderResource, File folder, Resource relation, boolean useResourceNames, IProgressMonitor monitor) throws Exception{
284                 Layer0 l0 = Layer0.getInstance(graph);
285                 DocumentResource doc = DocumentResource.getInstance(graph);
286                 GraphFileResource gf = GraphFileResource.getInstance(graph);
287                 Set<String> names = new HashSet<String>();
288                 Collection<Resource> folderType = graph.getPrincipalTypes(folderResource);
289                 for (Resource r : graph.getObjects(folderResource, relation)) {
290                         if (graph.isInstanceOf(r, doc.Document)) {
291                                 String name = null;
292                                 boolean canExport = false;
293                                 if (graph.isInstanceOf(r, doc.FileDocument)) {
294                                         name = graph.getRelatedValue(r, useResourceNames ? gf.HasResourceName : l0.HasName);
295                                         canExport = true;
296                                 } else if (graph.isInstanceOf(r, doc.UrlDocument)) {
297                                         name = graph.getRelatedValue(r, l0.HasName) +".url";
298                                         canExport = true;
299                                 }
300                                 if (canExport) {
301                                         name = resolveName(folder, name, names, true);
302                                         File file = new File(folder.getAbsolutePath()+"/"+name);
303                                         if (graph.isInstanceOf(r, doc.FileDocument)) {
304                                                 GraphFileUtil.writeDataToFile(graph,r, file);
305                                         } else if (graph.isInstanceOf(r, doc.UrlDocument)) {
306                                                 String url = graph.getRelatedValue(r, doc.HasUrl);
307                                                 String n = graph.getRelatedValue(r, l0.HasName);
308                                                 exportUrl(file, n, url);
309                                         }
310                                         if (monitor != null)
311                                                 monitor.worked(1);
312                                 }
313                                 
314                         } else {
315                                 Collection<Resource> type = graph.getPrincipalTypes(r);
316                                 if (type.size() == folderType.size() && folderType.containsAll(type)) {
317                                         String name = graph.getRelatedValue(r, l0.HasName);
318                                         name = resolveName(folder, name, names, false);
319                                         File subFolder = new File(folder.getAbsolutePath()+"/"+name);
320                                         if (!subFolder.exists()) {
321                                                 if (!subFolder.mkdir()) {
322                                                         // TODO : error.
323                                                         continue;
324                                                 }
325                                         }
326                                         exportDocumentFolder(graph, r, subFolder, relation, useResourceNames, monitor);
327                                 }
328                         }
329                 }
330         }
331         
332         /**
333          * Print URL to a file (Windows specific format?)
334          * @param toFile
335          * @param url
336          * @throws DatabaseException
337          */
338         private static void exportUrl(File toFile, String name, String url) throws Exception{
339                 PrintStream os = new PrintStream(toFile,"UTF-8");
340                 os.println("[InternetShortcut]");
341                 os.println("URL="+url);
342                 os.println("name="+name);
343                 os.flush();
344                 os.close();
345         }
346         
347         public static Resource importURL(WriteGraph graph, File file) throws Exception{
348                 String s = null;
349                 String url = null;
350                 String name = null;
351                 BufferedReader is = null;
352                 try {
353                 is = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));
354                 while ((s = is.readLine()) != null) {
355                         if (s.startsWith("URL=")) {
356                                 url = s.substring(4);
357                         } else if (s.startsWith("name=")) {
358                                 name = s.substring(5);
359                         }
360                 }
361                 } finally {
362                     if (is != null)
363                         is.close();
364                 }
365                 
366                 if (url == null)
367                         return null;
368                 
369                 Layer0 l0 = Layer0.getInstance(graph);
370                 DocumentResource doc = DocumentResource.getInstance(graph);
371                 
372                 Resource fileResource = graph.newResource();
373                 graph.claim(fileResource, l0.InstanceOf, doc.UrlDocument);
374                 if (name == null) {
375                         name = file.getName();
376                         name = unescape(name);
377                         name = name.substring(0,name.length()-4);
378                 }
379                 graph.claimLiteral(fileResource, l0.HasName, name);
380                 graph.claimLiteral(fileResource, doc.HasUrl, url);
381                 return fileResource;
382         }
383         
384         private static boolean isUrl(File file) throws Exception{
385                 return (file.getAbsolutePath().endsWith(".url"));
386         }
387         
388         private static final char ESCAPE = '%';
389         
390         private static String escape(String s) {
391                 
392                 int len = s.length();
393                 StringBuilder sb = new StringBuilder(len);
394                 for (int i = 0; i < len; i++) {
395                     char ch = s.charAt(i);
396                     if (ch < ' ' || ch >= 0x7F || ch == '/'  || ch == '\\' || ch == ':' || ch == ESCAPE) {
397                         sb.append(ESCAPE);
398                         if (ch < 0x10) {
399                             sb.append('0');
400                         }
401                         sb.append(Integer.toHexString(ch));
402                     } else {
403                         sb.append(ch);
404                     }
405                 }
406                 return sb.toString();
407         }
408         
409         private static String unescape(String s) {
410                 int len = s.length();
411                 StringBuilder sb = new StringBuilder(len);
412                 for (int i = 0; i < len; i++) {
413                     char ch = s.charAt(i);
414                     if (ch == ESCAPE) {
415                         String num = "0x";
416                         num += s.charAt(++i);
417                         num += s.charAt(++i);
418                         ch = (char)Integer.decode(num).intValue();
419                     }
420                     sb.append(ch);
421                 }
422                 return sb.toString();
423                 
424         }
425         
426         private static String resolveName(File parentFolder, String proposal, Set<String> used, boolean file) {
427                 String current = escape(proposal);
428                 int i = 0;
429                 if (file) {
430                         while (true) {
431                                 i++;
432                                 if (used.contains(current)) {
433                                         current = createFileName(proposal, i);
434                                 } else {
435                                         File subFile = new File(parentFolder.getAbsolutePath()+"/"+current);
436                                         if (!subFile.exists())
437                                                 break;
438                                         if (subFile.exists() && subFile.isFile() && subFile.canWrite()) {
439                                                 break;
440                                         }
441                                 }
442                         }
443                 } else {
444                         while (true) {
445                                 i++;
446                                 if (used.contains(current)) {
447                                         current = proposal+i;
448                                 } else {
449                                         File subFolder = new File(parentFolder.getAbsolutePath()+"/"+current);
450                                         if (!subFolder.exists())
451                                                 break;
452                                         if (subFolder.exists() && subFolder.isDirectory()) {
453                                                 break;
454                                         }
455                                 }
456                         }
457                 }
458                 used.add(current);
459                 return current;
460         }
461         
462         private static String createFileName(String original, int i) {
463                 int extIndex = original.lastIndexOf(".");
464                 if (extIndex == -1)
465                         return original+i;
466                 return original.substring(0,extIndex) + i + original.substring(extIndex);
467         }
468
469 }