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.plugins.transfer; 019 020import java.lang.reflect.Constructor; 021import java.lang.reflect.InvocationTargetException; 022 023import org.syncany.config.Config; 024import org.syncany.plugins.Plugin; 025import org.syncany.plugins.transfer.files.RemoteFile; 026import org.syncany.util.ReflectionUtil; 027 028/** 029 * The transfer plugin is a special plugin responsible for transferring files 030 * to the remote storage. Implementations must provide implementations for 031 * {@link TransferPlugin} (this class), {@link TransferSettings} (connection 032 * details) and {@link TransferManager} (transfer methods).<br><br> 033 * 034 * <p>Plugins have to follow a naming convention: 035 * <ul> 036 * <li>Package names have to be lower snaked cased</li> 037 * <li>Class names have to be camel cased</li> 038 * <li>Package names will be converted to class names by replacing underscores ('_') and uppercasing the 039 * subsequent character.</li> 040 * </ul> 041 * 042 * <p>Example:</p> 043 * A plugin is called DummyPlugin, hence <i>org.syncany.plugins.dummy_plugin.DummyPluginTransferPlugin</i> is the 044 * plugin's {@link TransferPlugin} class and <i>org.syncany.plugins.dummy_plugin.DummyPluginTransferSettings</i> is the 045 * corresponding {@link TransferSettings} implementation. 046 * 047 * @author Philipp C. Heckel (philipp.heckel@gmail.com) 048 * @author Christian Roth (christian.roth@port17.de) 049 */ 050public abstract class TransferPlugin extends Plugin { 051 public TransferPlugin(String pluginId) { 052 super(pluginId); 053 } 054 055 /** 056 * Creates an empty plugin-specific {@link org.syncany.plugins.transfer.TransferSettings} instance. 057 * 058 * @return Empty plugin-specific {@link org.syncany.plugins.transfer.TransferSettings} instance. 059 * @throws StorageException Thrown if no {@link org.syncany.plugins.transfer.TransferSettings} are attached to a 060 * plugin 061 */ 062 @SuppressWarnings("unchecked") 063 public final <T extends TransferSettings> T createEmptySettings() throws StorageException { 064 final Class<? extends TransferSettings> transferSettings = TransferPluginUtil.getTransferSettingsClass(this.getClass()); 065 066 if (transferSettings == null) { 067 throw new StorageException("TransferPlugin does not have any settings attached!"); 068 } 069 070 try { 071 return (T) transferSettings.newInstance(); 072 } 073 catch (InstantiationException | IllegalAccessException e) { 074 throw new RuntimeException("Unable to create TransferSettings: " + e.getMessage()); 075 } 076 } 077 078 /** 079 * Creates an initialized, plugin-specific {@link org.syncany.plugins.transfer.TransferManager} object using the given 080 * connection details. 081 * 082 * <p>The created instance can be used to upload/download/delete {@link RemoteFile}s 083 * and query the remote storage for a file list. 084 * 085 * @param transferSettings A valid {@link org.syncany.plugins.transfer.TransferSettings} instance. 086 * @param config A valid {@link org.syncany.config.Config} instance. 087 * @return A initialized, plugin-specific {@link org.syncany.plugins.transfer.TransferManager} instance. 088 * @throws StorageException Thrown if no (valid) {@link org.syncany.plugins.transfer.TransferManager} are attached to 089 * a plugin 090 */ 091 @SuppressWarnings("unchecked") 092 public final <T extends TransferManager> T createTransferManager(TransferSettings transferSettings, Config config) throws StorageException { 093 if (!transferSettings.isValid()) { 094 throw new StorageException("Unable to create transfer manager: connection isn't valid (perhaps missing some mandatory fields?)"); 095 } 096 097 final Class<? extends TransferSettings> transferSettingsClass = TransferPluginUtil.getTransferSettingsClass(this.getClass()); 098 final Class<? extends TransferManager> transferManagerClass = TransferPluginUtil.getTransferManagerClass(this.getClass()); 099 100 if (transferSettingsClass == null) { 101 throw new RuntimeException("Unable to create transfer manager: No settings class attached"); 102 } 103 104 if (transferManagerClass == null) { 105 throw new RuntimeException("Unable to create transfer manager: No manager class attached"); 106 } 107 108 try { 109 Constructor<?> potentialConstructor = ReflectionUtil.getMatchingConstructorForClass(transferManagerClass, TransferSettings.class, 110 Config.class); 111 112 if (potentialConstructor == null) { 113 throw new RuntimeException("Invalid arguments for constructor in pluginclass -- must be 2 and subclass of " + TransferSettings.class 114 + " and " + Config.class); 115 } 116 117 return (T) potentialConstructor.newInstance(transferSettingsClass.cast(transferSettings), config); 118 } 119 catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { 120 throw new RuntimeException("Unable to create transfer settings: " + e.getMessage(), e); 121 } 122 } 123}