001/*
002 * Syncany, www.syncany.org
003 * Copyright (C) 2011-2016 Philipp C. Heckel <philipp.heckel@gmail.com>
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU General Public License as published by
007 * the Free Software Foundation, either version 3 of the License, or
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU General Public License for more details.
014 *
015 * You should have received a copy of the GNU General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018package org.syncany.operations.ls_remote;
019
020import java.util.ArrayList;
021import java.util.List;
022import java.util.Map;
023import java.util.logging.Level;
024import java.util.logging.Logger;
025
026import org.syncany.config.Config;
027import org.syncany.config.LocalEventBus;
028import org.syncany.database.SqlDatabase;
029import org.syncany.operations.Operation;
030import org.syncany.operations.daemon.messages.LsRemoteEndSyncExternalEvent;
031import org.syncany.operations.daemon.messages.LsRemoteStartSyncExternalEvent;
032import org.syncany.plugins.transfer.StorageException;
033import org.syncany.plugins.transfer.TransferManager;
034import org.syncany.plugins.transfer.TransferManagerFactory;
035import org.syncany.plugins.transfer.features.PathAware;
036import org.syncany.plugins.transfer.files.DatabaseRemoteFile;
037
038/**
039 * The list remote operation queries the transfer manager for any unknown
040 * {@link DatabaseRemoteFile}s.
041 *
042 * <p>It first uses a {@link TransferManager} to list all remote databases and then
043 * uses the local list of known databases to filter already processed files. The local
044 * list of known databases is loaded.
045 *
046 * @author Philipp C. Heckel (philipp.heckel@gmail.com)
047 */
048public class LsRemoteOperation extends Operation {
049        private static final Logger logger = Logger.getLogger(LsRemoteOperation.class.getSimpleName());
050
051        private TransferManager loadedTransferManager;
052        private SqlDatabase localDatabase;
053        private LocalEventBus eventBus;
054
055        public LsRemoteOperation(Config config) {
056                this(config, null);
057        }
058
059        public LsRemoteOperation(Config config, TransferManager transferManager) {
060                super(config);
061
062                this.loadedTransferManager = transferManager;
063                this.localDatabase = new SqlDatabase(config);
064                this.eventBus = LocalEventBus.getInstance();
065        }
066
067        @Override
068        public LsRemoteOperationResult execute() throws Exception {
069                logger.log(Level.INFO, "");
070                logger.log(Level.INFO, "Running 'Remote Status' at client " + config.getMachineName() + " ...");
071                logger.log(Level.INFO, "--------------------------------------------");
072
073                eventBus.post(new LsRemoteStartSyncExternalEvent(config.getLocalDir().getAbsolutePath()));
074
075                TransferManager transferManager = createTransferManager(loadedTransferManager);
076
077                List<DatabaseRemoteFile> knownDatabases = localDatabase.getKnownDatabases();
078                List<DatabaseRemoteFile> unknownRemoteDatabases = listUnknownRemoteDatabases(transferManager, knownDatabases);
079
080                transferManager.disconnect();
081
082                boolean hasChanges = unknownRemoteDatabases.size() > 0;
083                eventBus.post(new LsRemoteEndSyncExternalEvent(config.getLocalDir().getAbsolutePath(), hasChanges));
084
085                return new LsRemoteOperationResult(new ArrayList<>(unknownRemoteDatabases));
086        }
087
088        private TransferManager createTransferManager(TransferManager loadedTransferManager) throws StorageException {
089                if (loadedTransferManager != null) {
090                        return loadedTransferManager;
091                }
092                else {
093                        return TransferManagerFactory
094                                        .build(config)
095                                        .withFeature(PathAware.class)
096                                        .asDefault();
097                }
098        }
099
100        private List<DatabaseRemoteFile> listUnknownRemoteDatabases(TransferManager transferManager, List<DatabaseRemoteFile> knownDatabases)
101                        throws StorageException {
102                logger.log(Level.INFO, "Retrieving remote database list.");
103
104                List<DatabaseRemoteFile> unknownRemoteDatabases = new ArrayList<DatabaseRemoteFile>();
105
106                // List all remote database files
107                Map<String, DatabaseRemoteFile> remoteDatabaseFiles = transferManager.list(DatabaseRemoteFile.class);
108
109                for (DatabaseRemoteFile remoteDatabaseFile : remoteDatabaseFiles.values()) {
110                        // This does NOT filter 'lock' files!
111                        if (knownDatabases.contains(remoteDatabaseFile)) {
112                                logger.log(Level.INFO, "- Remote database {0} is already known (in local database). Ignoring.", remoteDatabaseFile.getName());
113                        }
114                        else {
115                                logger.log(Level.INFO, "- Remote database {0} is new.", remoteDatabaseFile.getName());
116                                unknownRemoteDatabases.add(remoteDatabaseFile);
117                        }
118                }
119
120                return unknownRemoteDatabases;
121        }
122}