-package org.simantics.fileimport;\r
-\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.io.OutputStream;\r
-import java.nio.file.Files;\r
-import java.nio.file.Path;\r
-import java.nio.file.Paths;\r
-import java.util.ArrayList;\r
-import java.util.Collections;\r
-import java.util.HashMap;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Optional;\r
-import java.util.Properties;\r
-import java.util.function.Consumer;\r
-\r
-import org.osgi.framework.InvalidSyntaxException;\r
-import org.osgi.framework.ServiceReference;\r
-import org.simantics.Simantics;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.common.request.UniqueRead;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.service.SerialisationSupport;\r
-import org.simantics.layer0.Layer0;\r
-\r
-public class FileImportService {\r
-\r
- public static final String DB_FILE = ".simanticsdb";\r
-\r
- public static List<IGenericFileImport> getFileImportServices() {\r
- ServiceReference<?>[] serviceReferences = new ServiceReference<?>[0];\r
- try {\r
- serviceReferences = Activator.getContext().getAllServiceReferences(IGenericFileImport.class.getName(),\r
- null);\r
- } catch (InvalidSyntaxException e) {\r
- e.printStackTrace();\r
- }\r
- if (serviceReferences.length == 0)\r
- return Collections.emptyList();\r
-\r
- List<IGenericFileImport> services = new ArrayList<>(serviceReferences.length);\r
- for (ServiceReference<?> reference : serviceReferences) {\r
- IGenericFileImport service = (IGenericFileImport) Activator.getContext().getService(reference);\r
- services.add(service);\r
- }\r
- return services;\r
- }\r
-\r
- public static Map<String, String> supportedExtensionsWithFilters() {\r
- List<IGenericFileImport> services = getFileImportServices();\r
- Map<String, String> extensionsWithFilters = new HashMap<>();\r
- for (IGenericFileImport service : services)\r
- extensionsWithFilters.putAll(service.allowedExtensionsWithFilters());\r
-\r
- return extensionsWithFilters;\r
- }\r
-\r
- public static void performFileImport(Path file, Optional<Consumer<Throwable>> callback) {\r
- if (file.getFileName().toString().equals(DB_FILE))\r
- return;\r
- Optional<IGenericFileImport> serviceOp = findServiceForFileExtension(file);\r
- serviceOp.ifPresent(service -> {\r
- try {\r
- Optional<String> resource = service.perform(file);\r
- saveResourceForPath(file, resource);\r
- } catch (Throwable t) {\r
- if (callback.isPresent()) {\r
- callback.get().accept(t);\r
- } else {\r
- t.printStackTrace();\r
- }\r
- }\r
- });\r
- }\r
-\r
- public static void removeResourceForFile(Path file, Optional<Consumer<Throwable>> callback) {\r
- Optional<IGenericFileImport> serviceOp = findServiceForFileExtension(file);\r
- serviceOp.ifPresent(service -> {\r
- try {\r
- Optional<String> resource = getResourceForPath(file);\r
- if (!resource.isPresent())\r
- return;\r
- service.remove(resource.get());\r
- removeResourceForPath(file);\r
- } catch (Throwable t) {\r
- if (callback.isPresent()) {\r
- callback.get().accept(t);\r
- } else {\r
- t.printStackTrace();\r
- }\r
- }\r
- });\r
- }\r
- \r
- public static void removeFileForResource(long id, Optional<Consumer<Throwable>> callback) {\r
- Optional<Path> fileOp;\r
- try {\r
- fileOp = findPathForId(id);\r
- } catch (IOException e) {\r
- e.printStackTrace();\r
- return;\r
- }\r
- if (!fileOp.isPresent())\r
- return;\r
- Path file = fileOp.get();\r
- Optional<IGenericFileImport> serviceOp = findServiceForFileExtension(file);\r
- serviceOp.ifPresent(service -> {\r
- try {\r
- Optional<String> resource = getResourceForPath(file);\r
- if (!resource.isPresent())\r
- return;\r
- service.remove(resource.get());\r
- removeResourceForPath(file);\r
- } catch (Throwable t) {\r
- if (callback.isPresent()) {\r
- callback.get().accept(t);\r
- } else {\r
- t.printStackTrace();\r
- }\r
- }\r
- });\r
- }\r
-\r
- private static Optional<Path> findPathForId(long id) throws IOException {\r
- Path db = Activator.getDropinsFolder().resolve(DB_FILE);\r
- if (!Files.exists(db))\r
- Files.createFile(db);\r
- Properties props = new Properties();\r
- try (InputStream stream = Files.newInputStream(db)) {\r
- props.load(stream);\r
- }\r
- for (Map.Entry<Object, Object> entry : props.entrySet()) {\r
- Long value = Long.valueOf(entry.getValue().toString());\r
- if (value.longValue() == id) {\r
- String key = (String) entry.getKey();\r
- return Optional.of(Paths.get(key));\r
- }\r
- }\r
- return Optional.empty();\r
- }\r
-\r
- static final String FOLDER = "_folder_";\r
- \r
- public static Optional<IGenericFileImport> findServiceForFileExtension(Path file) {\r
- String extension = "";\r
-\r
- int i = file.getFileName().toString().lastIndexOf('.');\r
- if (i > 0) {\r
- extension = file.getFileName().toString().substring(i);\r
- } else {\r
- // Handle case that file is actually a directory\r
- if (Files.isDirectory(file) || !Files.isRegularFile(file)) {\r
- extension = FOLDER;\r
- }\r
- }\r
-\r
- List<IGenericFileImport> services = getFileImportServices();\r
- for (IGenericFileImport service : services) {\r
- for (Map.Entry<String, String> entry : service.allowedExtensionsWithFilters().entrySet()) {\r
- String possibleExtensions = entry.getKey();\r
- if (possibleExtensions.startsWith("*"))\r
- possibleExtensions = possibleExtensions.substring(1);\r
- if (possibleExtensions.equals(extension) || possibleExtensions.isEmpty()) {\r
- if (extension.equals(FOLDER) && possibleExtensions.equals(FOLDER)) {\r
- return Optional.of(service);\r
- } else if (!extension.isEmpty() && !extension.equals(FOLDER)){\r
- return Optional.of(service);\r
- }\r
- }\r
- }\r
- }\r
- return Optional.empty();\r
- }\r
- \r
- public static Map<String, Long> getPathsAndResources() {\r
- try {\r
- Path db = Activator.getDropinsFolder().resolve(DB_FILE);\r
- if (!Files.exists(db))\r
- Files.createFile(db);\r
- Properties props = new Properties();\r
- try (InputStream stream = Files.newInputStream(db)) {\r
- props.load(stream);\r
- }\r
- Map<String, Long> result = Simantics.getSession().syncRequest(new UniqueRead<Map<String, Long>>() {\r
-\r
- @Override\r
- public Map<String, Long> perform(ReadGraph graph) throws DatabaseException {\r
- Map<String, Long> map = new HashMap<>();\r
- for (Map.Entry<Object, Object> entry : props.entrySet()) {\r
- String value = (String) entry.getValue();\r
- Long id = Long.valueOf(value);\r
- SerialisationSupport ss = graph.getService(SerialisationSupport.class);\r
- try {\r
- Resource r = ss.getResource(id);\r
- String name = graph.getRelatedValue(r, Layer0.getInstance(graph).HasName);\r
- map.put(name, id);\r
- } catch (DatabaseException e) {\r
- e.printStackTrace();\r
- }\r
- }\r
- return map;\r
- }\r
- });\r
-\r
- return result;\r
- } catch (IOException | DatabaseException e) {\r
- e.printStackTrace();\r
- return Collections.emptyMap();\r
- }\r
- }\r
-\r
- private static void saveResourceForPath(Path file, Optional<String> resource) {\r
- resource.ifPresent(res -> {\r
- try {\r
- Path db = Activator.getDropinsFolder().resolve(DB_FILE);\r
- if (!Files.exists(db))\r
- Files.createFile(db);\r
- Properties props = new Properties();\r
- try (InputStream stream = Files.newInputStream(db)) {\r
- props.load(stream);\r
- }\r
- props.put(file.getFileName().toString(), resource.get());\r
- try (OutputStream stream = Files.newOutputStream(db)) {\r
- props.store(stream, null);\r
- }\r
- } catch (IOException e) {\r
- e.printStackTrace();\r
- }\r
- });\r
- }\r
-\r
- private static void removeResourceForPath(Path file) throws IOException {\r
- Path db = Activator.getDropinsFolder().resolve(DB_FILE);\r
- if (!Files.exists(db))\r
- Files.createFile(db);\r
- Properties props = new Properties();\r
- try (InputStream stream = Files.newInputStream(db)) {\r
- props.load(stream);\r
- }\r
- props.remove(file.getFileName().toString());\r
- try (OutputStream stream = Files.newOutputStream(db)) {\r
- props.store(stream, null);\r
- }\r
- }\r
- \r
- private static Optional<String> getResourceForPath(Path file) throws IOException {\r
- Path db = Activator.getDropinsFolder().resolve(DB_FILE);\r
- if (!Files.exists(db))\r
- Files.createFile(db);\r
- Properties props = new Properties();\r
- try (InputStream stream = Files.newInputStream(db)) {\r
- props.load(stream);\r
- }\r
- String value = props.getProperty(file.getFileName().toString());\r
- if (value == null)\r
- return Optional.empty();\r
- return Optional.of(value);\r
- }\r
-}\r
+package org.simantics.fileimport;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Properties;
+import java.util.function.Consumer;
+
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+import org.simantics.databoard.util.Base64;
+import org.simantics.fileimport.dropins.FileImportDropins;
+import org.simantics.utils.FileUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Utility class for Simantics File import functions
+ *
+ * @author Jani Simomaa
+ *
+ */
+public class FileImportService {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(FileImportService.class);
+
+ private FileImportService() {}
+
+ public static final String DB_FILE = ".simanticsdb";
+
+ private static List<IGenericFileImport> getFileImportServices() {
+ ServiceReference<?>[] serviceReferences = new ServiceReference<?>[0];
+ try {
+ serviceReferences = Activator.getContext().getAllServiceReferences(IGenericFileImport.class.getName(),
+ null);
+ } catch (InvalidSyntaxException e) {
+ LOGGER.error("Could not get service references for IGenericFileImport!", e);
+ }
+ if (serviceReferences.length == 0)
+ return Collections.emptyList();
+
+ List<IGenericFileImport> services = new ArrayList<>(serviceReferences.length);
+ for (ServiceReference<?> reference : serviceReferences) {
+ IGenericFileImport service = (IGenericFileImport) Activator.getContext().getService(reference);
+ services.add(service);
+ }
+ return services;
+ }
+
+ /**
+ * Lists all supported file extensions which have a registered service for handling the import
+ *
+ * @return Map containing the extension and the description of the extension in that order
+ */
+ public static Map<String, String> supportedExtensionsWithFilters() {
+ List<IGenericFileImport> services = getFileImportServices();
+ Map<String, String> extensionsWithFilters = new HashMap<>();
+ for (IGenericFileImport service : services)
+ extensionsWithFilters.putAll(service.allowedExtensionsWithFilters());
+
+ return extensionsWithFilters;
+ }
+
+ private static class ConsumerHolder implements Consumer<Throwable> {
+
+ private Throwable throwable;
+
+ @Override
+ public void accept(Throwable t) {
+ throwable = t;
+ }
+
+ public Throwable getThrowable() {
+ return throwable;
+ }
+
+ }
+
+ public static String performFileImport(String base64, String name) throws Throwable {
+ byte[] bytes = Base64.decode(base64);
+ Path file = Activator.getModelsFolder().resolve(name);
+ Files.write(file, bytes);
+
+ ConsumerHolder holder = new ConsumerHolder();
+ String result = performFileImport(file, Optional.of(holder));
+ if (holder.getThrowable() != null)
+ throw holder.getThrowable();
+ return result;
+ }
+
+ /**
+ * 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
+ *
+ * @param file Path file to be imported
+ * @param callback Optional callback which can be used to catch Throwables thrown in the import process
+ */
+ public static String performFileImport(Path file, Optional<Consumer<Throwable>> callback) {
+ if (file.getFileName().toString().equals(DB_FILE)) {
+ return null;
+ }
+ String result = "Import failed";
+ Optional<IGenericFileImport> serviceOp = findServiceForFileExtension(file);
+ if (serviceOp.isPresent()) {
+ IGenericFileImport service = serviceOp.get();
+ try {
+ Optional<String> resource = service.perform(file);
+ saveResourceForPath(file, resource);
+ result = resource.get();
+ } catch (Throwable t) {
+ if (callback.isPresent()) {
+ callback.get().accept(t);
+ } else {
+ LOGGER.error("Could not import file " + file, t);
+ }
+ }
+ } else {
+ LOGGER.warn("Could not find service for importing file " + file);
+ if (callback.isPresent())
+ callback.get().accept(new Exception("Could not find IGenericFileImport service for file " + file));
+ }
+ return result;
+ }
+
+
+ /**
+ * 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
+ *
+ * @param file Path file that was deleted
+ * @param callback Optional callback to catch Throwables thrown during the deletion process
+ */
+ public static void removeResourceForFile(Path file, Optional<Consumer<Throwable>> callback) {
+ Optional<IGenericFileImport> serviceOp = findServiceForFileExtension(file);
+ serviceOp.ifPresent(service -> {
+ try {
+ Optional<String> resource = getResourceForPath(file);
+ if (!resource.isPresent())
+ return;
+ service.remove(resource.get());
+ removeResourceForPath(file);
+ } catch (Throwable t) {
+ if (callback.isPresent()) {
+ callback.get().accept(t);
+ } else {
+ t.printStackTrace();
+ }
+ }
+ });
+ }
+
+ public static void removeFileForResource(long id, Optional<Consumer<Throwable>> callback) {
+ Optional<Path> fileOp;
+ try {
+ fileOp = findPathForId(id);
+ } catch (IOException e) {
+ e.printStackTrace();
+ return;
+ }
+ if (!fileOp.isPresent())
+ return;
+ Path file = fileOp.get();
+ Optional<IGenericFileImport> serviceOp = findServiceForFileExtension(file);
+ serviceOp.ifPresent(service -> {
+ try {
+ Optional<String> resource = getResourceForPath(file);
+ if (!resource.isPresent())
+ return;
+ service.remove(resource.get());
+ removeResourceForPath(file);
+ try {
+ Files.delete(file);
+ } catch (IOException e) {
+ Files.delete(file);
+ }
+ } catch (Throwable t) {
+ if (callback.isPresent()) {
+ callback.get().accept(t);
+ } else {
+ t.printStackTrace();
+ }
+ }
+ });
+ }
+
+ private static Optional<Path> findPathForId(long id) throws IOException {
+ Path db = Activator.getDropinsFolder().resolve(DB_FILE);
+ if (!Files.exists(db))
+ Files.createFile(db);
+ Properties props = new Properties();
+ try (InputStream stream = Files.newInputStream(db)) {
+ props.load(stream);
+ }
+ for (Map.Entry<Object, Object> entry : props.entrySet()) {
+ Long value = Long.valueOf(entry.getValue().toString());
+ if (value.longValue() == id) {
+ String key = (String) entry.getKey();
+ return Optional.of(Paths.get(key));
+ }
+ }
+ return Optional.empty();
+ }
+
+ static final String FOLDER = "_folder_";
+
+ /**
+ * Method for finding a File Import service for the given file based on the file extension
+ *
+ * @param file Path file for which the import service is looked for
+ * @return Optiona IGenerigFileImport service which is able to handle the import of this type of file
+ */
+ public static Optional<IGenericFileImport> findServiceForFileExtension(Path file) {
+ String extension = "";
+
+ int i = file.getFileName().toString().lastIndexOf('.');
+ if (i > 0) {
+ extension = file.getFileName().toString().substring(i);
+ } else {
+ // Handle case that file is actually a directory
+ if (Files.isDirectory(file) || !Files.isRegularFile(file)) {
+ extension = FOLDER;
+ }
+ }
+
+ List<IGenericFileImport> services = getFileImportServices();
+ for (IGenericFileImport service : services) {
+ for (Map.Entry<String, String> entry : service.allowedExtensionsWithFilters().entrySet()) {
+ String possibleExtensions = entry.getKey();
+ if (possibleExtensions.startsWith("*"))
+ possibleExtensions = possibleExtensions.substring(1);
+ if (possibleExtensions.equals(extension) || possibleExtensions.isEmpty()) {
+ if (extension.equals(FOLDER) && possibleExtensions.equals(FOLDER)) {
+ return Optional.of(service);
+ } else if (!extension.isEmpty() && !extension.equals(FOLDER)){
+ return Optional.of(service);
+ }
+ }
+ }
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Method for listing all current paths and their corresponding identifiers in Simantics database
+ *
+ * @return Map containing
+ */
+ public static Map<String, String> getPathsAndResources() {
+ try {
+ Path db = Activator.getDropinsFolder().resolve(DB_FILE);
+ if (!Files.exists(db))
+ Files.createFile(db);
+ Properties props = new Properties();
+ try (InputStream stream = Files.newInputStream(db)) {
+ props.load(stream);
+ }
+ Map<String, String> map = new HashMap<>();
+ for (Map.Entry<Object, Object> entry : props.entrySet()) {
+ String value = (String) entry.getValue();
+ String key = (String) entry.getKey();
+ map.put(key, value);
+ }
+ return map;
+ } catch (IOException e) {
+ e.printStackTrace();
+ return Collections.emptyMap();
+ }
+ }
+
+ private static void saveResourceForPath(Path file, Optional<String> resource) {
+ resource.ifPresent(res -> {
+ try {
+ Path db = Activator.getDropinsFolder().resolve(DB_FILE);
+ if (!Files.exists(db))
+ Files.createFile(db);
+ Properties props = new Properties();
+ try (InputStream stream = Files.newInputStream(db)) {
+ props.load(stream);
+ }
+ props.put(file.getFileName().toString(), resource.get());
+ try (OutputStream stream = Files.newOutputStream(db)) {
+ props.store(stream, null);
+ }
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ });
+ }
+
+ private static void removeResourceForPath(Path file) throws IOException {
+ Path db = Activator.getDropinsFolder().resolve(DB_FILE);
+ if (!Files.exists(db))
+ Files.createFile(db);
+ Properties props = new Properties();
+ try (InputStream stream = Files.newInputStream(db)) {
+ props.load(stream);
+ }
+ props.remove(file.getFileName().toString());
+ try (OutputStream stream = Files.newOutputStream(db)) {
+ props.store(stream, null);
+ }
+ }
+
+ private static Optional<String> getResourceForPath(Path file) throws IOException {
+ Path db = Activator.getDropinsFolder().resolve(DB_FILE);
+ if (!Files.exists(db))
+ Files.createFile(db);
+ Properties props = new Properties();
+ try (InputStream stream = Files.newInputStream(db)) {
+ props.load(stream);
+ }
+ String value = props.getProperty(file.getFileName().toString());
+ if (value == null)
+ return Optional.empty();
+ return Optional.of(value);
+ }
+}