Skip to content

Commit

Permalink
I18N-1323 Update Mojito CLI to use OpenAPI spec for rest calls
Browse files Browse the repository at this point in the history
Refactor other commands
  • Loading branch information
DarKhaos committed Dec 18, 2024
1 parent c44ef6d commit a4da5f8
Show file tree
Hide file tree
Showing 93 changed files with 2,460 additions and 7,841 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,4 @@ release.properties
/tmp/
/local/
.vscode/
/webapp/src/main/resources/openapi.*
11 changes: 5 additions & 6 deletions cli/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,20 @@
</dependency>

<dependency>
<groupId>com.box.l10n.mojito</groupId>
<artifactId>mojito-webapp</artifactId>
<version>0.111-SNAPSHOT</version>
<scope>test</scope>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

<dependency>
<groupId>com.box.l10n.mojito</groupId>
<artifactId>mojito-common</artifactId>
<artifactId>mojito-webapp</artifactId>
<version>0.111-SNAPSHOT</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>com.box.l10n.mojito</groupId>
<artifactId>mojito-restclient</artifactId>
<artifactId>mojito-common</artifactId>
<version>0.111-SNAPSHOT</version>
</dependency>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,22 @@
import com.box.l10n.mojito.cli.command.CommandException;
import com.box.l10n.mojito.cli.model.AssetAssetSummary;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

@Component
public class AssetWsApiHelper {
@Autowired AssetWsApi assetClient;
public class AssetWsApiProxy extends AssetWsApi {

public static final String OUTPUT_BCP47_TAG = "en-x-pseudo";

public AssetWsApiProxy(ApiClient apiClient) {
super(apiClient);
}

public AssetAssetSummary getAssetByPathAndRepositoryId(String path, Long repositoryId)
throws CommandException {
throws CommandException, ApiException {
Assert.notNull(path, "path must not be null");
Assert.notNull(repositoryId, "repository must not be null");

List<AssetAssetSummary> assets;
try {
assets = this.assetClient.getAssets(repositoryId, path, null, null, null);
} catch (ApiException e) {
throw new RuntimeException(e);
}
List<AssetAssetSummary> assets = this.getAssets(repositoryId, path, null, null, null);
if (!assets.isEmpty()) {
return assets.getFirst();
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,35 +1,18 @@
package com.box.l10n.mojito.cli.apiclient;

import com.squareup.okhttp.OkHttpClient;
import jakarta.annotation.PostConstruct;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import org.springframework.stereotype.Component;

@Component
public class AuthenticatedApiClient extends ApiClient {

private CookieManager cookieManager;

@PostConstruct
public void init() {
this.cookieManager = this.getCookieManager();
public AuthenticatedApiClient() {
this.setHttpClient(this.getOkHttpClient());
}

private CookieManager getCookieManager() {
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);
CookieHandler.setDefault(cookieManager);
return cookieManager;
}

private OkHttpClient getOkHttpClient() {
OkHttpClient httpClient = new OkHttpClient();
httpClient
.interceptors()
.add(new AuthenticatedApiInterceptor(this.cookieManager, this.getBasePath()));
httpClient.interceptors().add(new AuthenticatedApiInterceptor(this.getBasePath()));
return httpClient;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
import java.io.IOException;
import java.net.CookieHandler;
import java.net.CookieManager;
import java.net.CookiePolicy;
import java.net.CookieStore;
import java.net.HttpCookie;
import java.util.Optional;
Expand All @@ -37,11 +38,18 @@ public class AuthenticatedApiInterceptor implements Interceptor {

private final String basePath;

public AuthenticatedApiInterceptor(CookieManager cookieManager, String basePath) {
this.cookieManager = cookieManager;
public AuthenticatedApiInterceptor(String basePath) {
this.cookieManager = getCookieManager();
this.basePath = basePath;
}

private CookieManager getCookieManager() {
CookieManager cookieManager = new CookieManager();
cookieManager.setCookiePolicy(CookiePolicy.ACCEPT_ORIGINAL_SERVER);
CookieHandler.setDefault(cookieManager);
return cookieManager;
}

private Optional<HttpCookie> getCookie() {
CookieStore cookieStore = this.cookieManager.getCookieStore();
return cookieStore.getCookies().stream()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.box.l10n.mojito.cli.apiclient;

import com.box.l10n.mojito.cli.command.CommandException;
import com.box.l10n.mojito.cli.model.Locale;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LocaleWsApiProxy extends LocaleWsApi {
/** logger */
static Logger logger = LoggerFactory.getLogger(LocaleWsApiProxy.class);

public LocaleWsApiProxy(ApiClient apiClient) {
super(apiClient);
}

public Locale getLocaleByBcp47Tag(String bcp47Tag) throws ApiException {
logger.debug("Getting locale for BCP47 tag: {}", bcp47Tag);

List<Locale> locales = this.getLocales(bcp47Tag);

if (locales.size() != 1) {
throw new CommandException("Could not find locale with BCP47 tag: " + bcp47Tag);
}

return locales.getFirst();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,164 @@
package com.box.l10n.mojito.cli.apiclient;

import static org.slf4j.LoggerFactory.getLogger;

import com.box.l10n.mojito.cli.apiclient.exceptions.PollableTaskException;
import com.box.l10n.mojito.cli.apiclient.exceptions.PollableTaskExecutionException;
import com.box.l10n.mojito.cli.apiclient.exceptions.PollableTaskTimeoutException;
import com.box.l10n.mojito.cli.command.CommandException;
import com.box.l10n.mojito.cli.model.PollableTask;
import com.box.l10n.mojito.cli.models.ErrorMessage;
import com.box.l10n.mojito.json.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Component
public class PollableTaskWsApiProxy extends PollableTaskWsApi {
/** logger */
static Logger logger = getLogger(PollableTaskWsApiProxy.class);

public static final Long NO_TIMEOUT = -1L;

private final ObjectMapper objectMapper;

@Autowired
public PollableTaskWsApiProxy(ApiClient apiClient, ObjectMapper objectMapper) {
super(apiClient);
this.objectMapper = objectMapper;
}

/**
* Waits for {@link PollableTask} to be all finished (see {@link PollableTask#isAllFinished() }).
* Infinite timeout.
*
* @param pollableId the {@link PollableTask#getId()}
* @throws PollableTaskException
*/
public void waitForPollableTask(Long pollableId) throws PollableTaskException {
waitForPollableTask(pollableId, NO_TIMEOUT);
}

public void waitForPollableTask(Long pollableTaskId, long timeout) throws PollableTaskException {
waitForPollableTask(pollableTaskId, timeout, null);
}

/**
* Waits for {@link PollableTask} to be all finished (see {@link PollableTask#isAllFinished() }).
*
* @param pollableId the {@link com.box.l10n.mojito.cli.model.PollableTask#getId()}
* @param timeout timeout in milliseconds.
* @param waitForPollableTaskListener listener to be called during polling
* @throws PollableTaskException
*/
public void waitForPollableTask(
Long pollableId, long timeout, WaitForPollableTaskListener waitForPollableTaskListener)
throws PollableTaskException {

long timeoutTime = System.currentTimeMillis() + timeout;
long waitTime = 0;

PollableTask pollableTask = null;

while (pollableTask == null || !pollableTask.isAllFinished()) {

logger.debug("Waiting for PollableTask: {} to finish", pollableId);

try {
pollableTask = this.getPollableTaskById(pollableId);
} catch (ApiException e) {
throw new CommandException(e.getMessage(), e);
}

if (waitForPollableTaskListener != null) {
waitForPollableTaskListener.afterPoll(pollableTask);
}

List<PollableTask> pollableTaskWithErrors = getAllPollableTasksWithError(pollableTask);

if (!pollableTaskWithErrors.isEmpty()) {

for (PollableTask pollableTaskWithError : pollableTaskWithErrors) {
ErrorMessage errorMessage =
this.objectMapper.convertValue(
pollableTaskWithError.getErrorMessage(), ErrorMessage.class);
logger.debug(
"Error happened in PollableTask {}: {}",
pollableTaskWithError.getId(),
errorMessage.getMessage());
}

// Last task is the root task if it has an error or any of the sub task
// TODO(P1) we might want to show all errors
PollableTask lastTaskInError =
pollableTaskWithErrors.get(pollableTaskWithErrors.size() - 1);

ErrorMessage errorMessage =
this.objectMapper.convertValue(lastTaskInError.getErrorMessage(), ErrorMessage.class);
throw new PollableTaskExecutionException(errorMessage.getMessage());
}

if (!pollableTask.isAllFinished()) {

if (timeout != NO_TIMEOUT && System.currentTimeMillis() > timeoutTime) {
logger.debug(
"Timed out waiting for PollableTask: {} to finish. \n{}",
pollableId,
ReflectionToStringBuilder.toString(pollableTask));
throw new PollableTaskTimeoutException(
"Timed out waiting for PollableTask: " + pollableId);
}

try {
Thread.sleep(waitTime);
waitTime = getNextWaitTime(waitTime);
} catch (InterruptedException ie) {
throw new RuntimeException(ie);
}
} else {
logger.debug("PollableTask: {} finished", pollableId);
}
}
}

long getNextWaitTime(long lastWaitTime) {
int maxTime = 500;
long nextWaitTime = lastWaitTime + 25;
nextWaitTime = Math.max(maxTime, nextWaitTime);
return nextWaitTime;
}

/**
* Get all the PollableTasks with error (traverses all the PollableTask's subtasks)
*
* @param pollableTask
* @return
*/
public List<PollableTask> getAllPollableTasksWithError(PollableTask pollableTask) {
List<PollableTask> result = new ArrayList<>();
recursivelyGetAllPollableTaskWithError(pollableTask, result);
return result;
}

/**
* Recursively traverses all subtasks of {@code pollableTask} and return all the {@link
* PollableTask} which had an error message
*
* @param pollableTask
* @param pollableTasksWithError
*/
private void recursivelyGetAllPollableTaskWithError(
PollableTask pollableTask, List<PollableTask> pollableTasksWithError) {

for (PollableTask subTask : pollableTask.getSubTasks()) {
recursivelyGetAllPollableTaskWithError(subTask, pollableTasksWithError);
}

if (pollableTask.getErrorMessage() != null) {
pollableTasksWithError.add(pollableTask);
}
}
}

This file was deleted.

Loading

0 comments on commit a4da5f8

Please sign in to comment.