001package co.codewizards.cloudstore.client;
002
003import java.net.MalformedURLException;
004import java.net.URL;
005import java.util.ArrayList;
006import java.util.HashMap;
007import java.util.List;
008import java.util.Map;
009import java.util.UUID;
010
011import org.kohsuke.args4j.Argument;
012import org.kohsuke.args4j.Option;
013import org.slf4j.Logger;
014import org.slf4j.LoggerFactory;
015
016import co.codewizards.cloudstore.core.oio.File;
017import co.codewizards.cloudstore.core.progress.LoggerProgressMonitor;
018import co.codewizards.cloudstore.core.repo.local.LocalRepoManager;
019import co.codewizards.cloudstore.core.repo.local.LocalRepoManagerFactory;
020import co.codewizards.cloudstore.core.repo.local.LocalRepoRegistryImpl;
021import co.codewizards.cloudstore.core.repo.sync.RepoToRepoSync;
022
023public class SyncSubCommand extends SubCommandWithExistingLocalRepo {
024        private static final Logger logger = LoggerFactory.getLogger(SyncSubCommand.class);
025
026        @Argument(metaVar="<remote>", index=1, required=false, usage="An ID or URL of a remote repository. If none is specified, all remote repositories are synced.")
027        private String remote;
028
029        private UUID remoteRepositoryId;
030        private URL remoteRoot;
031
032        @Option(name="-localOnly", required=false, usage="Synchronise locally only. Do not communicate with any remote repository.")
033        private boolean localOnly;
034
035        @Override
036        public String getSubCommandDescription() {
037                return "Synchronise a local repository. Depending on the parameters, it synchronises only locally or with one or more remote repositories.";
038        }
039
040        @Override
041        public void prepare() throws Exception {
042                super.prepare();
043                remoteRepositoryId = null;
044                remoteRoot = null;
045                if (remote != null && !remote.isEmpty()) {
046                        try {
047                                remoteRepositoryId = UUID.fromString(remote);
048                        } catch (final IllegalArgumentException x) {
049                                try {
050                                        remoteRoot = new URL(remote);
051                                } catch (final MalformedURLException y) {
052                                        throw new IllegalArgumentException(String.format("<remote> '%s' is neither a valid repositoryId nor a valid URL!", remote));
053                                }
054                        }
055                }
056        }
057
058        @Override
059        protected void assertLocalRootNotNull() {
060                if (!isAll())
061                        super.assertLocalRootNotNull();
062        }
063
064        @Override
065        public void run() throws Exception {
066                if (isAll()) {
067                        for (final UUID repositoryId : LocalRepoRegistryImpl.getInstance().getRepositoryIds())
068                                sync(repositoryId);
069                }
070                else
071                        sync(localRoot);
072        }
073
074        private void sync(final UUID repositoryId) {
075                final File localRoot = LocalRepoRegistryImpl.getInstance().getLocalRootOrFail(repositoryId);
076                sync(localRoot);
077        }
078
079        private void sync(File localRoot) {
080                final List<URL> remoteRoots = new ArrayList<URL>();
081                final Map<UUID, URL> filteredRemoteRepositoryId2RemoteRoot = new HashMap<UUID, URL>();
082                UUID repositoryId;
083                final LocalRepoManager localRepoManager = LocalRepoManagerFactory.Helper.getInstance().createLocalRepoManagerForExistingRepository(localRoot);
084                try {
085                        if (localOnly) {
086                                localRepoManager.localSync(new LoggerProgressMonitor(logger));
087                                return;
088                        }
089
090                        repositoryId = localRepoManager.getRepositoryId();
091                        localRoot = localRepoManager.getLocalRoot();
092                        for (final Map.Entry<UUID, URL> me : localRepoManager.getRemoteRepositoryId2RemoteRootMap().entrySet()) {
093                                final UUID id = me.getKey();
094                                final URL url = me.getValue();
095
096                                remoteRoots.add(url);
097                                if ((remoteRepositoryId == null && remoteRoot == null)
098                                                || (remoteRepositoryId != null && remoteRepositoryId.equals(id))
099                                                || (remoteRoot != null && remoteRoot.equals(url)))
100                                        filteredRemoteRepositoryId2RemoteRoot.put(id, url);
101                        }
102                } finally {
103                        localRepoManager.close();
104                }
105
106                if (remoteRoots.isEmpty())
107                        System.err.println(String.format("WARNING: The repository %s ('%s') is not connected to any remote repository as client!", repositoryId, localRoot));
108                else if (filteredRemoteRepositoryId2RemoteRoot.isEmpty())
109                        System.err.println(String.format("WARNING: The repository %s ('%s') is not connected to the specified remote repository ('%s')!", repositoryId, localRoot, remote));
110                else {
111                        for (final Map.Entry<UUID, URL> me : filteredRemoteRepositoryId2RemoteRoot.entrySet()) {
112                                final UUID remoteRepositoryId = me.getKey();
113                                final URL remoteRoot = me.getValue();
114                                System.out.println("********************************************************************************");
115                                System.out.println(String.format("Syncing %s ('%s') with %s ('%s').", repositoryId, localRoot, remoteRepositoryId, remoteRoot));
116                                System.out.println("********************************************************************************");
117                                final RepoToRepoSync repoToRepoSync = RepoToRepoSync.create(localRoot, remoteRoot);
118                                try {
119                                        repoToRepoSync.sync(new LoggerProgressMonitor(logger));
120                                } finally {
121                                        repoToRepoSync.close();
122                                }
123                        }
124                }
125        }
126
127        private boolean isAll() {
128                return "ALL".equals(local);
129        }
130}