1 package org.simantics.fileimport;
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;
14 import java.util.Optional;
15 import java.util.Properties;
16 import java.util.function.Consumer;
18 import org.osgi.framework.InvalidSyntaxException;
19 import org.osgi.framework.ServiceReference;
20 import org.simantics.fileimport.dropins.FileImportDropins;
23 * Utility class for Simantics File import functions
25 * @author Jani Simomaa
28 public class FileImportService {
30 private FileImportService() {}
32 public static final String DB_FILE = ".simanticsdb";
34 private static List<IGenericFileImport> getFileImportServices() {
35 ServiceReference<?>[] serviceReferences = new ServiceReference<?>[0];
37 serviceReferences = Activator.getContext().getAllServiceReferences(IGenericFileImport.class.getName(),
39 } catch (InvalidSyntaxException e) {
42 if (serviceReferences.length == 0)
43 return Collections.emptyList();
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);
54 * Lists all supported file extensions which have a registered service for handling the import
56 * @return Map containing the extension and the description of the extension in that order
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());
64 return extensionsWithFilters;
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
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
73 public static void performFileImport(Path file, Optional<Consumer<Throwable>> callback) {
74 if (file.getFileName().toString().equals(DB_FILE))
76 Optional<IGenericFileImport> serviceOp = findServiceForFileExtension(file);
77 serviceOp.ifPresent(service -> {
79 Optional<String> resource = service.perform(file);
80 saveResourceForPath(file, resource);
81 } catch (Throwable t) {
82 if (callback.isPresent()) {
83 callback.get().accept(t);
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
95 * @param file Path file that was deleted
96 * @param callback Optional callback to catch Throwables thrown during the deletion process
98 public static void removeResourceForFile(Path file, Optional<Consumer<Throwable>> callback) {
99 Optional<IGenericFileImport> serviceOp = findServiceForFileExtension(file);
100 serviceOp.ifPresent(service -> {
102 Optional<String> resource = getResourceForPath(file);
103 if (!resource.isPresent())
105 service.remove(resource.get());
106 removeResourceForPath(file);
107 } catch (Throwable t) {
108 if (callback.isPresent()) {
109 callback.get().accept(t);
117 public static void removeFileForResource(long id, Optional<Consumer<Throwable>> callback) {
118 Optional<Path> fileOp;
120 fileOp = findPathForId(id);
121 } catch (IOException e) {
125 if (!fileOp.isPresent())
127 Path file = fileOp.get();
128 Optional<IGenericFileImport> serviceOp = findServiceForFileExtension(file);
129 serviceOp.ifPresent(service -> {
131 Optional<String> resource = getResourceForPath(file);
132 if (!resource.isPresent())
134 service.remove(resource.get());
135 removeResourceForPath(file);
138 } catch (IOException e) {
141 } catch (Throwable t) {
142 if (callback.isPresent()) {
143 callback.get().accept(t);
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)) {
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));
166 return Optional.empty();
169 static final String FOLDER = "_folder_";
172 * Method for finding a File Import service for the given file based on the file extension
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
177 public static Optional<IGenericFileImport> findServiceForFileExtension(Path file) {
178 String extension = "";
180 int i = file.getFileName().toString().lastIndexOf('.');
182 extension = file.getFileName().toString().substring(i);
184 // Handle case that file is actually a directory
185 if (Files.isDirectory(file) || !Files.isRegularFile(file)) {
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);
205 return Optional.empty();
209 * Method for listing all current paths and their corresponding identifiers in Simantics database
211 * @return Map containing
213 public static Map<String, String> getPathsAndResources() {
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)) {
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();
229 } catch (IOException e) {
231 return Collections.emptyMap();
235 private static void saveResourceForPath(Path file, Optional<String> resource) {
236 resource.ifPresent(res -> {
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)) {
245 props.put(file.getFileName().toString(), resource.get());
246 try (OutputStream stream = Files.newOutputStream(db)) {
247 props.store(stream, null);
249 } catch (IOException e) {
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)) {
263 props.remove(file.getFileName().toString());
264 try (OutputStream stream = Files.newOutputStream(db)) {
265 props.store(stream, null);
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)) {
277 String value = props.getProperty(file.getFileName().toString());
279 return Optional.empty();
280 return Optional.of(value);