X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.fileimport%2Fsrc%2Forg%2Fsimantics%2Ffileimport%2FFileImportService.java;h=15612d5fbd02905b8c2672d9621ad7d69dec719b;hp=1fa4e3f5b2756c3506bf45403845cd4f8387a005;hb=0d82e7808541ed486f6027a28038d44d2d93711a;hpb=5930811a7911090a0c4984380c3b45ed81a93cde diff --git a/bundles/org.simantics.fileimport/src/org/simantics/fileimport/FileImportService.java b/bundles/org.simantics.fileimport/src/org/simantics/fileimport/FileImportService.java index 1fa4e3f5b..15612d5fb 100644 --- a/bundles/org.simantics.fileimport/src/org/simantics/fileimport/FileImportService.java +++ b/bundles/org.simantics.fileimport/src/org/simantics/fileimport/FileImportService.java @@ -1,282 +1,377 @@ -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.fileimport.dropins.FileImportDropins; - -/** - * Utility class for Simantics File import functions - * - * @author Jani Simomaa - * - */ -public class FileImportService { - - private FileImportService() {} - - public static final String DB_FILE = ".simanticsdb"; - - private static List getFileImportServices() { - ServiceReference[] serviceReferences = new ServiceReference[0]; - try { - serviceReferences = Activator.getContext().getAllServiceReferences(IGenericFileImport.class.getName(), - null); - } catch (InvalidSyntaxException e) { - e.printStackTrace(); - } - if (serviceReferences.length == 0) - return Collections.emptyList(); - - List 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 supportedExtensionsWithFilters() { - List services = getFileImportServices(); - Map extensionsWithFilters = new HashMap<>(); - for (IGenericFileImport service : services) - extensionsWithFilters.putAll(service.allowedExtensionsWithFilters()); - - return extensionsWithFilters; - } - - /** - * 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 void performFileImport(Path file, Optional> callback) { - if (file.getFileName().toString().equals(DB_FILE)) - return; - Optional serviceOp = findServiceForFileExtension(file); - serviceOp.ifPresent(service -> { - try { - Optional resource = service.perform(file); - saveResourceForPath(file, resource); - } catch (Throwable t) { - if (callback.isPresent()) { - callback.get().accept(t); - } else { - t.printStackTrace(); - } - } - }); - } - - - /** - * 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> callback) { - Optional serviceOp = findServiceForFileExtension(file); - serviceOp.ifPresent(service -> { - try { - Optional 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> callback) { - Optional fileOp; - try { - fileOp = findPathForId(id); - } catch (IOException e) { - e.printStackTrace(); - return; - } - if (!fileOp.isPresent()) - return; - Path file = fileOp.get(); - Optional serviceOp = findServiceForFileExtension(file); - serviceOp.ifPresent(service -> { - try { - Optional 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 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 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 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 services = getFileImportServices(); - for (IGenericFileImport service : services) { - for (Map.Entry 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 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 map = new HashMap<>(); - for (Map.Entry 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 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 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); - } -} +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.Set; +import java.util.function.Consumer; +import java.util.stream.Collectors; + +import org.osgi.framework.InvalidSyntaxException; +import org.osgi.framework.ServiceReference; +import org.simantics.databoard.util.Base64; +import org.simantics.db.Resource; +import org.simantics.fileimport.dropins.FileImportDropins; +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 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 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 supportedExtensionsWithFilters() { + List services = getFileImportServices(); + Map extensionsWithFilters = new HashMap<>(); + for (IGenericFileImport service : services) + extensionsWithFilters.putAll(service.allowedExtensionsWithFilters()); + + return extensionsWithFilters; + } + + private static class ConsumerHolder implements Consumer { + + 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> callback) { + if (file.getFileName().toString().equals(DB_FILE)) { + return null; + } + String result = "Import failed"; + IGenericFileImport service = findServiceForFileExtension(file); + if (service != null) { + try { + Optional 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> callback) { + try { + Optional resource = getResourceForPath(file); + if (!resource.isPresent()) + return; + IGenericFileImport service = findServiceForFileExtension(file); + if (service == null) { + 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)); + } + service.remove(resource.get()); + removeResourceForPath(file); + } catch (Throwable t) { + if (callback.isPresent()) { + callback.get().accept(t); + } else { + LOGGER.error("Could not remove resource for file " + file.toAbsolutePath(), t); + } + } + } + + public static void removeFileForResource(long id, Optional> callback) { + Optional fileOp; + try { + fileOp = findPathForId(id); + } catch (IOException e) { + LOGGER.error("Could not remove file for resource id " + id, e); + return; + } + if (!fileOp.isPresent()) + return; + Path file = fileOp.get(); + + try { + Optional resource = getResourceForPath(file); + if (!resource.isPresent()) + return; + IGenericFileImport service = findServiceForFileExtension(file); + if (service == null) { + 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)); + } + 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 { + LOGGER.error("Could not remove file for resource " + id, t); + } + } + } + + private static Optional 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 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 Optional IGenerigFileImport service which is able to handle the import of this type of file + */ + public static 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; + } + } + return findServiceForExtension(extension); + } + + public static List filterSupportedExtensions(String filter) { + return getFileImportServices().stream().filter(s -> s.allowedExtensionsWithFilters().keySet().contains(filter)).map(s -> s.allowedExtensionsWithFilters().keySet()).flatMap(Set::stream).collect(Collectors.toList()); + } + + public static IGenericFileImport findServiceForExtension(String extension) { + List services = findServicesForExtension(extension); + IGenericFileImport service = null; + if (services.size() == 1) { + service = services.get(0); + } else { + for (IGenericFileImport servicee : services) { + service = servicee; + if (isPerfectMatch(servicee.allowedExtensionsWithFilters().keySet(), extension)) + break; + } + } + return service; + } + + public static List findServicesForExtension(String extension) { + List result = new ArrayList<>(); + List services = getFileImportServices(); + for (IGenericFileImport service : services) { + for (Map.Entry 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)) { + result.add(service); + } else if (!extension.isEmpty() && !extension.equals(FOLDER)){ + result.add(service); + } + } + } + } + return result; + } + + /** + * Method for listing all current paths and their corresponding identifiers in Simantics database + * + * @return Map containing + */ + public static Map 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 map = new HashMap<>(); + for (Map.Entry entry : props.entrySet()) { + String value = (String) entry.getValue(); + String key = (String) entry.getKey(); + map.put(key, value); + } + return map; + } catch (IOException e) { + LOGGER.error("Could not get current paths and resources!", e); + return Collections.emptyMap(); + } + } + + private static void saveResourceForPath(Path file, Optional 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) { + LOGGER.error("Could not save resource for path " + file.toAbsolutePath() + " and resource " + resource.get(), e); + } + }); + } + + 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 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); + } + + public static String importGenericFileWithExtension(String path, String extension) throws Exception { + IGenericFileImport service = findServiceForExtension(extension); + Optional result = service.perform(Paths.get(path)); + return result.get(); + } + + public static Resource importGenericFileWithExtensionAndParent(Resource parent, String path, String extension) throws Exception { + IGenericFileImport service = findServiceForExtension(extension); + Optional result = service.perform(parent, Paths.get(path)); + return result.get(); + } + + private static boolean isPerfectMatch(Set candidates, String extension) { + for (String ext : candidates) { + if (ext.startsWith(".")) + ext = ext.substring(1); + if (ext.equals(extension)) + return true; + } + return false; + } +}