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.init;
019
020import java.io.File;
021import java.io.IOException;
022import java.lang.reflect.Constructor;
023import java.lang.reflect.InvocationTargetException;
024import java.nio.file.Files;
025import java.nio.file.Paths;
026import java.util.logging.Logger;
027
028import org.syncany.config.Config;
029import org.syncany.config.LocalEventBus;
030import org.syncany.config.to.ConfigTO;
031import org.syncany.operations.Operation;
032import org.syncany.operations.daemon.messages.ShowMessageExternalEvent;
033import org.syncany.plugins.Plugins;
034import org.syncany.plugins.UserInteractionListener;
035import org.syncany.plugins.transfer.StorageException;
036import org.syncany.plugins.transfer.TransferManager;
037import org.syncany.plugins.transfer.TransferManagerFactory.TransferManagerBuilder;
038import org.syncany.plugins.transfer.TransferPlugin;
039import org.syncany.plugins.transfer.TransferSettings;
040import org.syncany.plugins.transfer.features.ReadAfterWriteConsistent;
041import org.syncany.util.EnvironmentUtil;
042
043/**
044 * The abstract init operation implements common functions of the {@link InitOperation}
045 * and the {@link ConnectOperation}. Its sole purpose is to avoid duplicate code in these
046 * similar operations.
047 *
048 * @author Philipp C. Heckel (philipp.heckel@gmail.com)
049 */
050public abstract class AbstractInitOperation extends Operation {
051        protected static final Logger logger = Logger.getLogger(AbstractInitOperation.class.getSimpleName());
052
053        protected UserInteractionListener listener;
054        protected LocalEventBus eventBus;
055
056        public AbstractInitOperation(Config config, UserInteractionListener listener) {
057                super(config);
058
059                this.listener = listener;
060                this.eventBus = LocalEventBus.getInstance();
061        }
062
063        protected File createAppDirs(File localDir) throws IOException {
064                if (localDir == null) {
065                        throw new RuntimeException("Unable to create app dir, local dir is null.");
066                }
067
068                File appDir = new File(localDir, Config.DIR_APPLICATION);
069                File logDir = new File(appDir, Config.DIR_LOG);
070                File cacheDir = new File(appDir, Config.DIR_CACHE);
071                File databaseDir = new File(appDir, Config.DIR_DATABASE);
072                File stateDir = new File(appDir, Config.DIR_STATE);
073
074                appDir.mkdir();
075                logDir.mkdir();
076                cacheDir.mkdir();
077                databaseDir.mkdir();
078                stateDir.mkdir();
079
080                if (EnvironmentUtil.isWindows()) {
081                        Files.setAttribute(Paths.get(appDir.getAbsolutePath()), "dos:hidden", true);
082                }
083
084                return appDir;
085        }
086
087        protected void deleteAppDirs(File localDir) throws IOException {
088                File appDir = new File(localDir, Config.DIR_APPLICATION);
089                File logDir = new File(appDir, Config.DIR_LOG);
090                File cacheDir = new File(appDir, Config.DIR_CACHE);
091                File databaseDir = new File(appDir, Config.DIR_DATABASE);
092
093                for (File log : logDir.listFiles()) {
094                        log.delete();
095                }
096
097                for (File cache : cacheDir.listFiles()) {
098                        cache.delete();
099                }
100
101                for (File db : databaseDir.listFiles()) {
102                        db.delete();
103                }
104
105                for (File file : appDir.listFiles()) {
106                        file.delete();
107                }
108
109                logDir.delete();
110                cacheDir.delete();
111                databaseDir.delete();
112                appDir.delete();
113        }
114
115        protected void fireNotifyCreateMaster() {
116                eventBus.post(new ShowMessageExternalEvent("Creating master key from password (this might take a while) ..."));
117        }
118
119        protected TransferManager createTransferManagerFromNullConfig(ConfigTO configTo) throws IllegalAccessException,
120                                        InvocationTargetException, InstantiationException, NoSuchMethodException, StorageException {
121
122                // Init plugin and transfer manager
123                TransferPlugin plugin = Plugins.get(configTo.getTransferSettings().getType(), TransferPlugin.class);
124
125                TransferSettings transferSettings = configTo.getTransferSettings();
126                transferSettings.setUserInteractionListener(listener);
127                TransferManager transferManager = plugin.createTransferManager(transferSettings, config);
128
129                // constructor is not visible and config seems to be null at this point, hence we cannot use the build method here
130                Constructor<TransferManagerBuilder> tmbConstructor = TransferManagerBuilder.class.getDeclaredConstructor(Config.class, TransferManager.class);
131                tmbConstructor.setAccessible(true);
132
133                return tmbConstructor.newInstance(config, transferManager)
134                                                .withFeature(ReadAfterWriteConsistent.class)
135                                                .asDefault();
136        }
137}