diff --git a/app/server/appsmith-server/pom.xml b/app/server/appsmith-server/pom.xml index c2e3e22740..4564049424 100644 --- a/app/server/appsmith-server/pom.xml +++ b/app/server/appsmith-server/pom.xml @@ -116,6 +116,11 @@ guava 28.1-jre + + commons-io + commons-io + 2.6 + org.pf4j diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java index 8c23f11f7c..72c52ebd86 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/exceptions/AppsmithError.java @@ -16,7 +16,8 @@ public enum AppsmithError { PAGE_DOESNT_BELONG_TO_USER_ORGANIZATION(400, 4006, "Page {0} does not belong to the current user {1} organization."), UNAUTHORIZED_DOMAIN(401, 4001, "Invalid email domain provided. Please sign in with a valid work email ID"), INTERNAL_SERVER_ERROR(500, 5000, "Internal server error while processing request"), - REPOSITORY_SAVE_FAILED(500, 5001, "Repository save failed."); + REPOSITORY_SAVE_FAILED(500, 5001, "Repository save failed."), + PLUGIN_INSTALLATION_FAILED_DOWNLOAD_ERROR(500, 5002, "Due to error in downloading the plugin from remote repository, plugin installation has failed. Check the jar location and try again."); private Integer httpErrorCode; private Integer appErrorCode; diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PluginServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PluginServiceImpl.java index 5f6bfa5aeb..bbd7148045 100644 --- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PluginServiceImpl.java +++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/PluginServiceImpl.java @@ -12,6 +12,8 @@ import com.appsmith.server.exceptions.AppsmithException; import com.appsmith.server.repositories.PluginRepository; import com.segment.analytics.Analytics; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.FileUtils; +import org.pf4j.PluginManager; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.data.mongodb.core.ReactiveMongoTemplate; @@ -21,6 +23,9 @@ import reactor.core.publisher.Mono; import reactor.core.scheduler.Scheduler; import javax.validation.Validator; +import java.io.File; +import java.net.URL; +import java.nio.file.Path; import java.util.ArrayList; import java.util.List; @@ -31,6 +36,10 @@ public class PluginServiceImpl extends BaseService This is to find if the organization already has the plugin installed Mono userMono = super.sessionUserService.getCurrentUser(); - Mono organizationMono = userMono.flatMap(user -> + Mono pluginInOrganizationMono = userMono.flatMap(user -> organizationService.findByIdAndPluginsPluginId(user.getOrganizationId(), pluginDTO.getPluginId())); //If plugin is already present for the organization, just return the organization, else install and return organization - return organizationMono + return pluginInOrganizationMono .switchIfEmpty(Mono.defer(() -> { //If the plugin is not found in the organization, its not installed already. Install now. - return userMono + return pluginRepository + .findById(pluginDTO.getPluginId()) + .map(plugin -> { + if (plugin.getJarLocation() == null) { + // Plugin jar location not set. Must be local + /** TODO + * In future throw an error if jar location is not set + */ + return plugin; + } + + String baseUrl = "../dist/plugins/"; + String pluginJar = plugin.getName() + ".jar"; + + // Else download the plugin jar to the local + try { + FileUtils.copyURLToFile( + new URL(plugin.getJarLocation()), + new File(baseUrl, pluginJar), + CONNECTION_TIMEOUT, + READ_TIMEOUT); + } catch (Exception e) { + log.error("",e); + return Mono.error(new AppsmithException(AppsmithError.PLUGIN_INSTALLATION_FAILED_DOWNLOAD_ERROR)); + } + + //Now that the plugin has been downloaded, load and restart the plugin + pluginManager.loadPlugin(Path.of(baseUrl + pluginJar)); + pluginManager.startPlugins(); + + return plugin; + }) + //Now that the plugin jar has been successfully downloaded, go on and add the plugin to the organization + .then(userMono) .flatMap(user -> organizationService.findById(user.getOrganizationId())) .map(organization -> { + List organizationPluginList = organization.getPlugins(); if (organizationPluginList == null) { organizationPluginList = new ArrayList(); @@ -134,6 +178,8 @@ public class PluginServiceImpl extends BaseService