Skip to content

Commit

Permalink
Add service to install a plugin from a given url
Browse files Browse the repository at this point in the history
  • Loading branch information
derTobsch committed Mar 22, 2020
1 parent 798fc87 commit ab73610
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased]
### Added
- Sonarcloud check
- Possibility to install a plugin via the frontpage

### Changed
- CoffeeNet Starter Parent to version `0.38.2`
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package coffee.synyx.frontpage.installer;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* @author Tobias Schneider
*/
@Configuration
public class PluginConfiguration {

@Bean
PluginConfigurationProperties pluginConfigurationProperties() {

return new PluginConfigurationProperties();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package coffee.synyx.frontpage.installer;

import org.hibernate.validator.constraints.NotEmpty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;

/**
* @author Tobias Schneider
*/
@Validated
@ConfigurationProperties("frontpage.plugins")
public class PluginConfigurationProperties {

@NotEmpty
private String directory = "./plugins";

public String getDirectory() {
return directory;
}

public void setDirectory(String directory) {
this.directory = directory;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package coffee.synyx.frontpage.installer;

/**
* @author Tobias Schneider
*/
public class PluginInstallationException extends RuntimeException {

PluginInstallationException(String message) {
super(message);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package coffee.synyx.frontpage.installer;

/**
* @author Tobias Schneider
*/
public interface PluginInstallerService {

/**
* Installs a plugin into the defined directory of `frontpage.plugins.directory`
*
* @param url of the plugin to download and install
*
* @throws PluginInstallationException if an error occurred
*/
void installPlugin(String url);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package coffee.synyx.frontpage.installer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import static java.lang.String.format;
import static java.lang.invoke.MethodHandles.lookup;
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpStatus.OK;

/**
* @author Tobias Schneider
*/
@Service
public class SimplePluginInstallerService implements PluginInstallerService {

private static final Logger LOGGER = LoggerFactory.getLogger(lookup().lookupClass());

private final RestTemplate restTemplate;
private final PluginConfigurationProperties pluginConfigurationProperties;

@Autowired
public SimplePluginInstallerService(RestTemplate restTemplate, PluginConfigurationProperties pluginConfigurationProperties) {

this.restTemplate = restTemplate;
this.pluginConfigurationProperties = pluginConfigurationProperties;
}

@Override
public void installPlugin(String url) {

HttpHeaders headers = new HttpHeaders();
HttpEntity<String> entity = new HttpEntity<>(headers);

ResponseEntity<byte[]> response = restTemplate.exchange(url, GET, entity, byte[].class);

if (response.getStatusCode() == OK) {

createPluginDirectory();

Path pluginUri = Paths.get(pluginConfigurationProperties.getDirectory(), getPluginName(url));
try {
Files.write(pluginUri, response.getBody());
} catch (IOException e) {
throw new PluginInstallationException(format("IO Error occurred while saving the plugin to %s", pluginUri));
}
}
}

private void createPluginDirectory() {

if (new File(pluginConfigurationProperties.getDirectory()).mkdirs()) {
LOGGER.debug("{} was created", pluginConfigurationProperties.getDirectory());
}
}

private String getPluginName(String url) {

String path;
try {
path = new URI(url).getPath();
} catch (URISyntaxException e) {
throw new PluginInstallationException("Url of plugin is in wrong format and violates RFC 2396");
}

return path.substring(path.lastIndexOf('/') + 1);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package coffee.synyx.frontpage.installer;


import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.RestTemplate;

import java.io.File;

import static org.assertj.core.api.Assertions.assertThat;


/**
* @author Tobias Schneider
*/
@RunWith(SpringRunner.class)
public class SimplePluginInstallerServiceIT {

private PluginInstallerService sut;

@Before
public void setUp() {

final PluginConfigurationProperties pluginConfigurationProperties = new PluginConfigurationProperties();

sut = new SimplePluginInstallerService(new RestTemplate(), pluginConfigurationProperties);
}

@After
public void tearDown() {

deleteDirectory(new File("./plugins"));
}


@Test
public void downloadPlugin() {
String url = "https://github.com/coffeenet/coffeenet-frontpage-plugin-feed/releases/download/0.2.0/" +
"frontpage-plugin-feed-0.2.0-jar-with-dependencies.jar";

sut.installPlugin(url);

File plugin = new File("./plugins/frontpage-plugin-feed-0.2.0-jar-with-dependencies.jar");

assertThat(plugin.exists()).isTrue();
assertThat(plugin.isFile()).isTrue();
}

private boolean deleteDirectory(File directoryToBeDeleted) {
File[] allContents = directoryToBeDeleted.listFiles();
if (allContents != null) {
for (File file : allContents) {
deleteDirectory(file);
}
}
return directoryToBeDeleted.delete();
}
}

0 comments on commit ab73610

Please sign in to comment.