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