Merge "Small SCL changes"
[simantics/platform.git] / bundles / org.simantics.fileimport / src / org / simantics / fileimport / FileImportService.java
1 package org.simantics.fileimport;\r
2 \r
3 import java.io.IOException;\r
4 import java.io.InputStream;\r
5 import java.io.OutputStream;\r
6 import java.nio.file.Files;\r
7 import java.nio.file.Path;\r
8 import java.nio.file.Paths;\r
9 import java.util.ArrayList;\r
10 import java.util.Collections;\r
11 import java.util.HashMap;\r
12 import java.util.List;\r
13 import java.util.Map;\r
14 import java.util.Optional;\r
15 import java.util.Properties;\r
16 import java.util.function.Consumer;\r
17 \r
18 import org.osgi.framework.InvalidSyntaxException;\r
19 import org.osgi.framework.ServiceReference;\r
20 import org.simantics.Simantics;\r
21 import org.simantics.db.ReadGraph;\r
22 import org.simantics.db.Resource;\r
23 import org.simantics.db.common.request.UniqueRead;\r
24 import org.simantics.db.exception.DatabaseException;\r
25 import org.simantics.db.service.SerialisationSupport;\r
26 import org.simantics.layer0.Layer0;\r
27 \r
28 public class FileImportService {\r
29 \r
30     public static final String DB_FILE = ".simanticsdb";\r
31 \r
32     public static List<IGenericFileImport> getFileImportServices() {\r
33         ServiceReference<?>[] serviceReferences = new ServiceReference<?>[0];\r
34         try {\r
35             serviceReferences = Activator.getContext().getAllServiceReferences(IGenericFileImport.class.getName(),\r
36                     null);\r
37         } catch (InvalidSyntaxException e) {\r
38             e.printStackTrace();\r
39         }\r
40         if (serviceReferences.length == 0)\r
41             return Collections.emptyList();\r
42 \r
43         List<IGenericFileImport> services = new ArrayList<>(serviceReferences.length);\r
44         for (ServiceReference<?> reference : serviceReferences) {\r
45             IGenericFileImport service = (IGenericFileImport) Activator.getContext().getService(reference);\r
46             services.add(service);\r
47         }\r
48         return services;\r
49     }\r
50 \r
51     public static Map<String, String> supportedExtensionsWithFilters() {\r
52         List<IGenericFileImport> services = getFileImportServices();\r
53         Map<String, String> extensionsWithFilters = new HashMap<>();\r
54         for (IGenericFileImport service : services)\r
55             extensionsWithFilters.putAll(service.allowedExtensionsWithFilters());\r
56 \r
57         return extensionsWithFilters;\r
58     }\r
59 \r
60     public static void performFileImport(Path file, Optional<Consumer<Throwable>> callback) {\r
61         if (file.getFileName().toString().equals(DB_FILE))\r
62             return;\r
63         Optional<IGenericFileImport> serviceOp = findServiceForFileExtension(file);\r
64         serviceOp.ifPresent(service -> {\r
65             try {\r
66                 Optional<String> resource = service.perform(file);\r
67                 saveResourceForPath(file, resource);\r
68             } catch (Throwable t) {\r
69                 if (callback.isPresent()) {\r
70                     callback.get().accept(t);\r
71                 } else {\r
72                     t.printStackTrace();\r
73                 }\r
74             }\r
75         });\r
76     }\r
77 \r
78     public static void removeResourceForFile(Path file, Optional<Consumer<Throwable>> callback) {\r
79         Optional<IGenericFileImport> serviceOp = findServiceForFileExtension(file);\r
80         serviceOp.ifPresent(service -> {\r
81             try {\r
82                 Optional<String> resource = getResourceForPath(file);\r
83                 if (!resource.isPresent())\r
84                     return;\r
85                 service.remove(resource.get());\r
86                 removeResourceForPath(file);\r
87             } catch (Throwable t) {\r
88                 if (callback.isPresent()) {\r
89                     callback.get().accept(t);\r
90                 } else {\r
91                     t.printStackTrace();\r
92                 }\r
93             }\r
94         });\r
95     }\r
96     \r
97     public static void removeFileForResource(long id, Optional<Consumer<Throwable>> callback) {\r
98         Optional<Path> fileOp;\r
99         try {\r
100             fileOp = findPathForId(id);\r
101         } catch (IOException e) {\r
102             e.printStackTrace();\r
103             return;\r
104         }\r
105         if (!fileOp.isPresent())\r
106             return;\r
107         Path file = fileOp.get();\r
108         Optional<IGenericFileImport> serviceOp = findServiceForFileExtension(file);\r
109         serviceOp.ifPresent(service -> {\r
110             try {\r
111                 Optional<String> resource = getResourceForPath(file);\r
112                 if (!resource.isPresent())\r
113                     return;\r
114                 service.remove(resource.get());\r
115                 removeResourceForPath(file);\r
116             } catch (Throwable t) {\r
117                 if (callback.isPresent()) {\r
118                     callback.get().accept(t);\r
119                 } else {\r
120                     t.printStackTrace();\r
121                 }\r
122             }\r
123         });\r
124     }\r
125 \r
126     private static Optional<Path> findPathForId(long id) throws IOException {\r
127         Path db = Activator.getDropinsFolder().resolve(DB_FILE);\r
128         if (!Files.exists(db))\r
129             Files.createFile(db);\r
130         Properties props = new Properties();\r
131         try (InputStream stream = Files.newInputStream(db)) {\r
132             props.load(stream);\r
133         }\r
134         for (Map.Entry<Object, Object> entry : props.entrySet()) {\r
135             Long value = Long.valueOf(entry.getValue().toString());\r
136             if (value.longValue() == id) {\r
137                 String key = (String) entry.getKey();\r
138                 return Optional.of(Paths.get(key));\r
139             }\r
140         }\r
141         return Optional.empty();\r
142     }\r
143 \r
144     static final String FOLDER = "_folder_";\r
145     \r
146     public static Optional<IGenericFileImport> findServiceForFileExtension(Path file) {\r
147         String extension = "";\r
148 \r
149         int i = file.getFileName().toString().lastIndexOf('.');\r
150         if (i > 0) {\r
151             extension = file.getFileName().toString().substring(i);\r
152         } else {\r
153             // Handle case that file is actually a directory\r
154             if (Files.isDirectory(file) || !Files.isRegularFile(file)) {\r
155                 extension = FOLDER;\r
156             }\r
157         }\r
158 \r
159         List<IGenericFileImport> services = getFileImportServices();\r
160         for (IGenericFileImport service : services) {\r
161             for (Map.Entry<String, String> entry : service.allowedExtensionsWithFilters().entrySet()) {\r
162                 String possibleExtensions = entry.getKey();\r
163                 if (possibleExtensions.startsWith("*"))\r
164                     possibleExtensions = possibleExtensions.substring(1);\r
165                 if (possibleExtensions.equals(extension) || possibleExtensions.isEmpty()) {\r
166                     if (extension.equals(FOLDER) && possibleExtensions.equals(FOLDER)) {\r
167                         return Optional.of(service);\r
168                     } else if (!extension.isEmpty() && !extension.equals(FOLDER)){\r
169                         return Optional.of(service);\r
170                     }\r
171                 }\r
172             }\r
173         }\r
174         return Optional.empty();\r
175     }\r
176     \r
177     public static Map<String, Long> getPathsAndResources() {\r
178         try {\r
179             Path db = Activator.getDropinsFolder().resolve(DB_FILE);\r
180             if (!Files.exists(db))\r
181                 Files.createFile(db);\r
182             Properties props = new Properties();\r
183             try (InputStream stream = Files.newInputStream(db)) {\r
184                 props.load(stream);\r
185             }\r
186             Map<String, Long> result = Simantics.getSession().syncRequest(new UniqueRead<Map<String, Long>>() {\r
187 \r
188                 @Override\r
189                 public Map<String, Long> perform(ReadGraph graph) throws DatabaseException {\r
190                     Map<String, Long> map = new HashMap<>();\r
191                     for (Map.Entry<Object, Object> entry : props.entrySet()) {\r
192                         String value = (String) entry.getValue();\r
193                         Long id = Long.valueOf(value);\r
194                         SerialisationSupport ss = graph.getService(SerialisationSupport.class);\r
195                         try {\r
196                             Resource r = ss.getResource(id);\r
197                             String name = graph.getRelatedValue(r, Layer0.getInstance(graph).HasName);\r
198                             map.put(name, id);\r
199                         } catch (DatabaseException e) {\r
200                             e.printStackTrace();\r
201                         }\r
202                     }\r
203                     return map;\r
204                 }\r
205             });\r
206 \r
207             return result;\r
208         } catch (IOException | DatabaseException e) {\r
209             e.printStackTrace();\r
210             return Collections.emptyMap();\r
211         }\r
212     }\r
213 \r
214     private static void saveResourceForPath(Path file, Optional<String> resource) {\r
215         resource.ifPresent(res -> {\r
216             try {\r
217                 Path db = Activator.getDropinsFolder().resolve(DB_FILE);\r
218                 if (!Files.exists(db))\r
219                     Files.createFile(db);\r
220                 Properties props = new Properties();\r
221                 try (InputStream stream = Files.newInputStream(db)) {\r
222                     props.load(stream);\r
223                 }\r
224                 props.put(file.getFileName().toString(), resource.get());\r
225                 try (OutputStream stream = Files.newOutputStream(db)) {\r
226                     props.store(stream, null);\r
227                 }\r
228             } catch (IOException e) {\r
229                 e.printStackTrace();\r
230             }\r
231         });\r
232     }\r
233 \r
234     private static void removeResourceForPath(Path file) throws IOException {\r
235         Path db = Activator.getDropinsFolder().resolve(DB_FILE);\r
236         if (!Files.exists(db))\r
237             Files.createFile(db);\r
238         Properties props = new Properties();\r
239         try (InputStream stream = Files.newInputStream(db)) {\r
240             props.load(stream);\r
241         }\r
242         props.remove(file.getFileName().toString());\r
243         try (OutputStream stream = Files.newOutputStream(db)) {\r
244             props.store(stream, null);\r
245         }\r
246     }\r
247     \r
248     private static Optional<String> getResourceForPath(Path file) throws IOException {\r
249         Path db = Activator.getDropinsFolder().resolve(DB_FILE);\r
250         if (!Files.exists(db))\r
251             Files.createFile(db);\r
252         Properties props = new Properties();\r
253         try (InputStream stream = Files.newInputStream(db)) {\r
254             props.load(stream);\r
255         }\r
256         String value = props.getProperty(file.getFileName().toString());\r
257         if (value == null)\r
258             return Optional.empty();\r
259         return Optional.of(value);\r
260     }\r
261 }\r