Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@

import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.function.Predicate;
import java.util.function.Supplier;

abstract class AbstractUpmMojo extends AbstractMojo {
Expand Down Expand Up @@ -72,31 +73,42 @@ BasicHeader getAuthHeader() {
"Basic " + Base64.encodeBase64String((username + ":" + password).getBytes(StandardCharsets.UTF_8)));
}

void poll(String taskName, long maxWaitMillis, Supplier<Boolean> callback) throws Exception {
Boolean poll(String taskName, long maxWaitMillis, Supplier<Boolean> task) {
return poll(taskName, maxWaitMillis, task, result -> result);
}

Result pollResult(String taskName, long maxWaitMillis, Supplier<Result> task) {
return poll(taskName, maxWaitMillis, task, Result::isSuccess);
}

<T> T poll(String taskName, long maxWaitMillis, Supplier<T> task, Predicate<T> isCompleted) {
long millisWaited = 0;
boolean success = false;
while (!success && millisWaited < maxWaitMillis) {
T taskResult = null;
while (millisWaited < maxWaitMillis) {
getLog().info(taskName + ": Waiting for success (" + millisWaited + "/" + maxWaitMillis + " millis waited) ...");
long beginWaitMillis = System.currentTimeMillis();
success = callback.get();
Thread.sleep(5000);
taskResult = task.get();
if (isCompleted.test(taskResult)) {
return taskResult;
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new RuntimeException(e);
}
millisWaited += System.currentTimeMillis() - beginWaitMillis;
}

if (millisWaited >= maxWaitMillis && !success) {
getLog().info(taskName + ": No longer waiting for success after " + maxWaitMillis + " millis");
}
if (success) {
getLog().info(taskName + ": Success");
}
getLog().info(taskName + ": No longer waiting for success after " + maxWaitMillis + " millis");
return taskResult;
}

static JsonObject parseResponseAsJsonObject(CloseableHttpResponse response) throws Exception {
if (response.getStatusLine().getStatusCode() != 200) {
throw new Exception(response.getStatusLine().toString());
}
String json = EntityUtils.toString(response.getEntity());
return new JsonParser().parse(json).getAsJsonObject();
return JsonParser.parseString(json).getAsJsonObject();
}

}
49 changes: 49 additions & 0 deletions src/main/java/com/linkedplanet/maven/plugin/upm/Result.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package com.linkedplanet.maven.plugin.upm;

interface Result {
String toMessage();

boolean isSuccess();

default boolean isFailure() {
return !isSuccess();
}

class Success implements Result {
@Override
public boolean isSuccess() {
return true;
}

@Override
public String toMessage() {
return "Plugin verification succeeded.";
}
}

class Failure implements Result {
private final String hint;
private final Throwable cause;

Failure(String hint, Throwable cause) {
this.hint = hint;
this.cause = cause;
}

Failure(String hint) {
this(hint, null);
}

@Override
public boolean isSuccess() {
return false;
}

@Override
public String toMessage() {
return cause == null
? hint
: String.format("%s - Caused by: %s", hint, cause.getMessage());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;

import java.io.File;

Expand All @@ -44,6 +45,9 @@ public class UploadPluginFileMojo extends AbstractUpmMojo {

private static final String REST_PATH_PLUGINS = "/rest/plugins/1.0";

@Parameter(defaultValue = "${project}", readonly = true, required = true)
private MavenProject project;

@SuppressWarnings("unused")
@Parameter(property = "pluginKey")
private String pluginKey;
Expand All @@ -56,6 +60,7 @@ public class UploadPluginFileMojo extends AbstractUpmMojo {
@Parameter(property = "waitForSuccessMillis", defaultValue = "60000")
private int waitForSuccessMillis;


@Override
public void execute() throws MojoExecutionException {
try (CloseableHttpClient httpClient = createHttpClient()) {
Expand All @@ -64,18 +69,20 @@ public void execute() throws MojoExecutionException {
getLog().info("UPM token: " + token);

getLog().info("Uploading file: " + pluginFile + " ...");
uploadFile(httpClient, token);
uploadPluginFile(httpClient, token);

// wait for 5 seconds before checking plugin enabled state
Thread.sleep(5000);
poll("Plugin installation", waitForSuccessMillis, () -> checkPluginEnabled(httpClient));


Result result = pollResult("Plugin installation", waitForSuccessMillis, () -> verifyInstalledVersion(httpClient));
if (result.isFailure()) {
throw new RuntimeException("The given plugin wasn't installed properly. Reason: " + result.toMessage());
}
} catch (Exception e) {
throw new MojoExecutionException("Plugin installation error", e);
}
}


private String getUpmToken(CloseableHttpClient httpClient) throws Exception {
String url = baseUrl.toString() + REST_PATH_PLUGINS + "/?os_authType=basic";
HttpHead request = new HttpHead(url);
Expand All @@ -92,7 +99,7 @@ private String getUpmToken(CloseableHttpClient httpClient) throws Exception {
}
}

private void uploadFile(CloseableHttpClient httpClient, String token) throws Exception {
private void uploadPluginFile(CloseableHttpClient httpClient, String token) throws Exception {
String url = baseUrl.toString() + REST_PATH_PLUGINS + "/?token=" + token;
HttpPost request = new HttpPost(url);
request.setHeader(getAuthHeader());
Expand All @@ -107,16 +114,27 @@ private void uploadFile(CloseableHttpClient httpClient, String token) throws Exc
}
}

private boolean checkPluginEnabled(CloseableHttpClient httpClient) {
private Result verifyInstalledVersion(CloseableHttpClient httpClient) {
String expectedVersion = project.getVersion();
HttpGet request = new HttpGet(baseUrl.toString() + REST_PATH_PLUGINS + '/' + pluginKey + "-key");
request.setHeader(getAuthHeader());
try (CloseableHttpResponse response = httpClient.execute(request)) {
JsonObject jsonObject = parseResponseAsJsonObject(response);
return jsonObject.getAsJsonPrimitive("enabled").getAsBoolean();

JsonObject pluginInfo = parseResponseAsJsonObject(response);
String installedVersion = pluginInfo.getAsJsonPrimitive("version").getAsString();
boolean enabled = pluginInfo.getAsJsonPrimitive("enabled").getAsBoolean();
if (!enabled) {
return new Result.Failure("The plugin is not enabled. Please check the log for installation errors.");
}
if (!installedVersion.equals(expectedVersion)) {
return new Result.Failure(String.format(
"Expected version %s but currently installed version is %s. Deinstall the currently installed version and try again.",
expectedVersion,
installedVersion));
}
} catch (Exception e) {
throw new RuntimeException(e);
return new Result.Failure("Failed to fetch plugin metadata from the platform. Ensure Confluence is reachable and try again.", e);
}
return new Result.Success();
}

}