--- /dev/null
+package org.simantics.backup;\r
+\r
+import java.io.IOException;\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.Collection;\r
+import java.util.List;\r
+import java.util.concurrent.ExecutionException;\r
+import java.util.concurrent.Future;\r
+import java.util.function.Consumer;\r
+\r
+import org.eclipse.core.runtime.CoreException;\r
+import org.eclipse.core.runtime.IStatus;\r
+import org.eclipse.core.runtime.MultiStatus;\r
+import org.eclipse.core.runtime.Status;\r
+import org.osgi.framework.InvalidSyntaxException;\r
+import org.osgi.framework.ServiceReference;\r
+\r
+/**\r
+ * @author Jani Simomaa\r
+ */\r
+public class BackupProviderService {\r
+\r
+ private static volatile int threadCounter = 0;\r
+\r
+ public static void backup(String targetPath, int revision) throws BackupException {\r
+ backup(Paths.get(targetPath), revision, null);\r
+ }\r
+ \r
+ /**\r
+ * @param targetPath\r
+ * @param revision\r
+ * @param callback \r
+ * @throws BackupException \r
+ */\r
+ public static void backup(Path targetPath, int revision, Consumer<BackupException> callback) throws BackupException {\r
+ List<IBackupProvider> providers = getBackupProviders();\r
+ try {\r
+ if (!Files.exists(targetPath))\r
+ Files.createDirectories(targetPath);\r
+ Backups.lock(providers);\r
+ new Thread(() -> {\r
+ boolean unlockedAlready = false;\r
+ BackupException problem = null;\r
+ try {\r
+ List<Future<BackupException>> backups = Backups.syncBackup(providers, targetPath, revision);\r
+ // Unlock providers at this stage\r
+ Backups.unlock(providers);\r
+ unlockedAlready = true;\r
+ \r
+ // Wait for all providers to complete their work.\r
+ List<Exception> exceptions = new ArrayList<>(backups.size());\r
+ for (Future<BackupException> f : backups) {\r
+ try {\r
+ Exception e = f.get();\r
+ if (e != null)\r
+ exceptions.add(e);\r
+ } catch (InterruptedException | ExecutionException e) {\r
+ exceptions.add(e);\r
+ }\r
+ }\r
+\r
+ // Throw BackupException if any of the backup operations failed.\r
+ if (!exceptions.isEmpty()) {\r
+ IStatus[] ss = exceptions.stream()\r
+ .map(e -> new Status(IStatus.ERROR, Activator.BUNDLE_ID, e.getMessage(), e))\r
+ .toArray(IStatus[]::new);\r
+ problem = new BackupException(new CoreException(new MultiStatus(Activator.BUNDLE_ID, 0, ss,\r
+ "Backup operation(s) failed to complete.", null)));\r
+ }\r
+\r
+ } catch (BackupException e) {\r
+ problem = e;\r
+ } catch (Throwable t) {\r
+ problem = new BackupException(t);\r
+ } finally {\r
+ if (!unlockedAlready)\r
+ Backups.unlock(providers);\r
+ }\r
+ if (callback != null)\r
+ callback.accept(problem);\r
+ }, "Backup thread " + (++threadCounter)).start();\r
+ } catch (IOException e) {\r
+ throw new BackupException(e);\r
+ }\r
+ }\r
+\r
+ /**\r
+ * @param fromPath\r
+ * @param revision\r
+ */\r
+ public static void restore(Path fromPath, int revision) throws BackupException {\r
+ restore(getBackupProviders(), fromPath, revision);\r
+ }\r
+\r
+ private static void restore(Collection<IBackupProvider> providers, Path fromPath, int revision) throws BackupException {\r
+ for (IBackupProvider provider : providers)\r
+ provider.restore(fromPath, revision);\r
+ }\r
+\r
+ private static List<IBackupProvider> getBackupProviders() throws BackupException {\r
+ try {\r
+ List<IBackupProvider> results = new ArrayList<>();\r
+ Collection<ServiceReference<IBackupProvider>> backupProviders = Activator.getContext().getServiceReferences(IBackupProvider.class, null);\r
+ for (ServiceReference<IBackupProvider> reference : backupProviders) {\r
+ results.add(Activator.getContext().getService(reference));\r
+ }\r
+ return results;\r
+ } catch (InvalidSyntaxException e) {\r
+ throw new BackupException("Failed to enumerate backup providers.", e);\r
+ }\r
+ }\r
+\r
+}\r