]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.fileimport/src/org/simantics/fileimport/FileImportService.java
fcbd3cc30c33a04f87993e8307a1fda32b895fc4
[simantics/platform.git] / bundles / org.simantics.fileimport / src / org / simantics / fileimport / FileImportService.java
1 package org.simantics.fileimport;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.OutputStream;
6 import java.nio.file.Files;
7 import java.nio.file.Path;
8 import java.nio.file.Paths;
9 import java.util.ArrayList;
10 import java.util.Collections;
11 import java.util.HashMap;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.Optional;
15 import java.util.Properties;
16 import java.util.function.Consumer;
17
18 import org.osgi.framework.InvalidSyntaxException;
19 import org.osgi.framework.ServiceReference;
20 import org.simantics.fileimport.dropins.FileImportDropins;
21
22 /**
23  * Utility class for Simantics File import functions
24  * 
25  * @author Jani Simomaa
26  *
27  */
28 public class FileImportService {
29
30     private FileImportService() {}
31     
32     public static final String DB_FILE = ".simanticsdb";
33
34     private static List<IGenericFileImport> getFileImportServices() {
35         ServiceReference<?>[] serviceReferences = new ServiceReference<?>[0];
36         try {
37             serviceReferences = Activator.getContext().getAllServiceReferences(IGenericFileImport.class.getName(),
38                     null);
39         } catch (InvalidSyntaxException e) {
40             e.printStackTrace();
41         }
42         if (serviceReferences.length == 0)
43             return Collections.emptyList();
44
45         List<IGenericFileImport> services = new ArrayList<>(serviceReferences.length);
46         for (ServiceReference<?> reference : serviceReferences) {
47             IGenericFileImport service = (IGenericFileImport) Activator.getContext().getService(reference);
48             services.add(service);
49         }
50         return services;
51     }
52
53     /**
54      * Lists all supported file extensions which have a registered service for handling the import
55      * 
56      * @return Map containing the extension and the description of the extension in that order
57      */
58     public static Map<String, String> supportedExtensionsWithFilters() {
59         List<IGenericFileImport> services = getFileImportServices();
60         Map<String, String> extensionsWithFilters = new HashMap<>();
61         for (IGenericFileImport service : services)
62             extensionsWithFilters.putAll(service.allowedExtensionsWithFilters());
63
64         return extensionsWithFilters;
65     }
66
67     /**
68      * Method that performs the import of the given file. This method is called when e.g. {@link FileImportDropins} watcher detects {@link java.nio.file.StandardWatchEventKinds.ENTRY_CREATE} operation
69      * 
70      * @param file Path file to be imported
71      * @param callback Optional callback which can be used to catch Throwables thrown in the import process
72      */
73     public static void performFileImport(Path file, Optional<Consumer<Throwable>> callback) {
74         if (file.getFileName().toString().equals(DB_FILE))
75             return;
76         Optional<IGenericFileImport> serviceOp = findServiceForFileExtension(file);
77         serviceOp.ifPresent(service -> {
78             try {
79                 Optional<String> resource = service.perform(file);
80                 saveResourceForPath(file, resource);
81             } catch (Throwable t) {
82                 if (callback.isPresent()) {
83                     callback.get().accept(t);
84                 } else {
85                     t.printStackTrace();
86                 }
87             }
88         });
89     }
90
91     
92     /**
93      * Remove the entity that matches the file. This method is called when e.g. the {@link FileImportDropins} watcher detects {@link java.nio.file.StandardWatchEventKinds.ENTRY_DELETE} operation
94      * 
95      * @param file Path file that was deleted
96      * @param callback Optional callback to catch Throwables thrown during the deletion process
97      */
98     public static void removeResourceForFile(Path file, Optional<Consumer<Throwable>> callback) {
99         Optional<IGenericFileImport> serviceOp = findServiceForFileExtension(file);
100         serviceOp.ifPresent(service -> {
101             try {
102                 Optional<String> resource = getResourceForPath(file);
103                 if (!resource.isPresent())
104                     return;
105                 service.remove(resource.get());
106                 removeResourceForPath(file);
107             } catch (Throwable t) {
108                 if (callback.isPresent()) {
109                     callback.get().accept(t);
110                 } else {
111                     t.printStackTrace();
112                 }
113             }
114         });
115     }
116     
117     public static void removeFileForResource(long id, Optional<Consumer<Throwable>> callback) {
118         Optional<Path> fileOp;
119         try {
120             fileOp = findPathForId(id);
121         } catch (IOException e) {
122             e.printStackTrace();
123             return;
124         }
125         if (!fileOp.isPresent())
126             return;
127         Path file = fileOp.get();
128         Optional<IGenericFileImport> serviceOp = findServiceForFileExtension(file);
129         serviceOp.ifPresent(service -> {
130             try {
131                 Optional<String> resource = getResourceForPath(file);
132                 if (!resource.isPresent())
133                     return;
134                 service.remove(resource.get());
135                 removeResourceForPath(file);
136                 try {
137                     Files.delete(file);
138                 } catch (IOException e) {
139                     Files.delete(file);
140                 }
141             } catch (Throwable t) {
142                 if (callback.isPresent()) {
143                     callback.get().accept(t);
144                 } else {
145                     t.printStackTrace();
146                 }
147             }
148         });
149     }
150
151     private static Optional<Path> findPathForId(long id) throws IOException {
152         Path db = Activator.getDropinsFolder().resolve(DB_FILE);
153         if (!Files.exists(db))
154             Files.createFile(db);
155         Properties props = new Properties();
156         try (InputStream stream = Files.newInputStream(db)) {
157             props.load(stream);
158         }
159         for (Map.Entry<Object, Object> entry : props.entrySet()) {
160             Long value = Long.valueOf(entry.getValue().toString());
161             if (value.longValue() == id) {
162                 String key = (String) entry.getKey();
163                 return Optional.of(Paths.get(key));
164             }
165         }
166         return Optional.empty();
167     }
168
169     static final String FOLDER = "_folder_";
170     
171     /**
172      * Method for finding a File Import service for the given file based on the file extension
173      * 
174      * @param file Path file for which the import service is looked for
175      * @return Optiona IGenerigFileImport service which is able to handle the import of this type of file
176      */
177     public static Optional<IGenericFileImport> findServiceForFileExtension(Path file) {
178         String extension = "";
179
180         int i = file.getFileName().toString().lastIndexOf('.');
181         if (i > 0) {
182             extension = file.getFileName().toString().substring(i);
183         } else {
184             // Handle case that file is actually a directory
185             if (Files.isDirectory(file) || !Files.isRegularFile(file)) {
186                 extension = FOLDER;
187             }
188         }
189
190         List<IGenericFileImport> services = getFileImportServices();
191         for (IGenericFileImport service : services) {
192             for (Map.Entry<String, String> entry : service.allowedExtensionsWithFilters().entrySet()) {
193                 String possibleExtensions = entry.getKey();
194                 if (possibleExtensions.startsWith("*"))
195                     possibleExtensions = possibleExtensions.substring(1);
196                 if (possibleExtensions.equals(extension) || possibleExtensions.isEmpty()) {
197                     if (extension.equals(FOLDER) && possibleExtensions.equals(FOLDER)) {
198                         return Optional.of(service);
199                     } else if (!extension.isEmpty() && !extension.equals(FOLDER)){
200                         return Optional.of(service);
201                     }
202                 }
203             }
204         }
205         return Optional.empty();
206     }
207     
208     /**
209      * Method for listing all current paths and their corresponding identifiers in Simantics database
210      * 
211      * @return Map containing 
212      */
213     public static Map<String, String> getPathsAndResources() {
214         try {
215             Path db = Activator.getDropinsFolder().resolve(DB_FILE);
216             if (!Files.exists(db))
217                 Files.createFile(db);
218             Properties props = new Properties();
219             try (InputStream stream = Files.newInputStream(db)) {
220                 props.load(stream);
221             }
222             Map<String, String> map = new HashMap<>();
223             for (Map.Entry<Object, Object> entry : props.entrySet()) {
224                 String value = (String) entry.getValue();
225                 String key = (String) entry.getKey();
226                 map.put(key, value);
227             }
228             return map;
229         } catch (IOException e) {
230             e.printStackTrace();
231             return Collections.emptyMap();
232         }
233     }
234
235     private static void saveResourceForPath(Path file, Optional<String> resource) {
236         resource.ifPresent(res -> {
237             try {
238                 Path db = Activator.getDropinsFolder().resolve(DB_FILE);
239                 if (!Files.exists(db))
240                     Files.createFile(db);
241                 Properties props = new Properties();
242                 try (InputStream stream = Files.newInputStream(db)) {
243                     props.load(stream);
244                 }
245                 props.put(file.getFileName().toString(), resource.get());
246                 try (OutputStream stream = Files.newOutputStream(db)) {
247                     props.store(stream, null);
248                 }
249             } catch (IOException e) {
250                 e.printStackTrace();
251             }
252         });
253     }
254
255     private static void removeResourceForPath(Path file) throws IOException {
256         Path db = Activator.getDropinsFolder().resolve(DB_FILE);
257         if (!Files.exists(db))
258             Files.createFile(db);
259         Properties props = new Properties();
260         try (InputStream stream = Files.newInputStream(db)) {
261             props.load(stream);
262         }
263         props.remove(file.getFileName().toString());
264         try (OutputStream stream = Files.newOutputStream(db)) {
265             props.store(stream, null);
266         }
267     }
268     
269     private static Optional<String> getResourceForPath(Path file) throws IOException {
270         Path db = Activator.getDropinsFolder().resolve(DB_FILE);
271         if (!Files.exists(db))
272             Files.createFile(db);
273         Properties props = new Properties();
274         try (InputStream stream = Files.newInputStream(db)) {
275             props.load(stream);
276         }
277         String value = props.getProperty(file.getFileName().toString());
278         if (value == null)
279             return Optional.empty();
280         return Optional.of(value);
281     }
282 }