Tuesday, 16 April 2019

Complete a Task Step in SDL WorldServer using the REST API

In this article, I would like to present a method for completing an active Task Step in SDL WorldServer using the REST API.

The method takes three parameters:
  1. wsBaseUrl
  2. token
  3. completeTaskStepRequestBody
The wsBaseUrl must be the <serverURL>:<portnumber> where your WorldServer instance is running.

The second parameter is a security token, which can be retrieved by using the SDL WorldServer REST API as explained here.

The third parameter is a CompleteTaskStepRequestBody object containing the data to support the task step completion. This includes the id (task id), the transitionId and an optional comment to set as metadata. The task id and transition id can be retrieved by invoking the REST call described here for retrieving the tasks from a specified Project. The returned TaskDetails object provides the data.

The method returns a boolean value specifying whether the task step completion was successful.

public class CompleteTaskStepRequestBody {
private int id;
private int transitionId;
private String comment;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getTransitionId() {
return transitionId;
}
public void setTransitionId(int transitionId) {
this.transitionId = transitionId;
}
public String getComment() {
return comment;
}
public void setComment(String comment) {
this.comment = comment;
}
}
public static boolean completeTaskStep(String wsBaseUrl, String token, CompleteTaskStepRequestBody completeTaskStepRequestBody)
throws IOException, URISyntaxException {
JsonObject jsonObject = doPost(wsBaseUrl, "/ws-api/v1/tasks/complete", token, Arrays.asList(completeTaskStepRequestBody));
return StringUtils.equals(jsonObject.getAsJsonPrimitive("status").getAsString(), "OK");
}
public static JsonObject doPost(String wsBaseUrl, String restPath, String token, Object pojo)
throws IOException, URISyntaxException {
URI postUri = new URIBuilder(wsBaseUrl + restPath)
.addParameter("token", token)
.addParameter("content-type", "application/json")
.build();
HttpClient httpClient = HttpClientBuilder.create().build();
HttpPost httpPost = new HttpPost(postUri);
httpPost.setEntity(getStringEntity(pojo));
HttpResponse response = httpClient.execute(httpPost);
Gson gson = new GsonBuilder().create();
return gson.fromJson(new InputStreamReader(response.getEntity().getContent()), JsonObject.class);
}

Download an asset associated with a TASK in SDL WorldServer using the REST API

In this article, I would like to present a method for downloading a file (asset) associated with a Task in SDL WorldServer using the REST API.

The method takes six parameters:
  1. wsBaseUrl
  2. token
  3. taskId
  4. assetName
  5. downloadLocation
  6. assetLocationType
The wsBaseUrl must be the <serverURL>:<portnumber> where your WorldServer instance is running.

The second parameter is a security token, which can be retrieved by using the SDL WorldServer REST API as explained here.

The third parameter is the id of the Task in SDL WorldServer to download the asset from.

The fourth parameter is the name of the asset to download. This can be retrieved by invoking the REST call described here for retrieving the tasks from a specified Project. The returned TaskDetails object provides the targetAsset attribute containing the path to the target asset. Use this path to work out the file (asset) name.

The firth parameter is the path to the download location where to place the downloaded file.

Finally the sixth parameter is used to determine the location type: SOURCE, TARGET or SOURCE_TARGET.

The method returns a String containing the path to the downloaded file.

public enum AssetLocationType {
SOURCE,
TARGET,
SOURCE_TARGET
}
public enum AssetResourceType {
TASK,
PROJECT,
PROJECT_GROUP
}
public static String getAssetFromTask(String wsBaseUrl, String token, int taskId, String assetName,
String downloadLocation, AssetLocationType assetLocationType)
throws IOException, URISyntaxException {
File translatedFile = new File(downloadLocation, assetName);
URI getUri = new URIBuilder(wsBaseUrl + "/ws-api/v1/files/asset")
.addParameter("token", token)
.addParameter("resourceId", String.valueOf(taskId))
.addParameter("assetLocationType", assetLocationType.toString())
.addParameter("resourceType", AssetResourceType.TASK.toString())
.build();
HttpClient httpClient = HttpClientBuilder.create().build();
HttpGet httpGet = new HttpGet(getUri);
HttpResponse response = httpClient.execute(httpGet);
byte[] bytes = EntityUtils.toByteArray(response.getEntity());
FileUtils.writeByteArrayToFile(translatedFile, bytes);
return translatedFile.getPath();
}

Get a list of Tasks from a Project in SDL WorldServer using the REST API

In this article, I would like to present a method for retrieving a list of Tasks from a Project in SDL WorldServer using the REST API.

The method takes three parameters:
  1. wsBaseUrl
  2. token
  3. projectId
The wsBaseUrl must be the <serverURL>:<portnumber> where your WorldServer instance is running.

The second parameter is a security token, which can be retrieved by using the SDL WorldServer REST API as explained here.

The third parameter is the id of the Project in SDL WorldServer to retrieve the tasks from.

The method returns a List of TaskDetails objects, one for each task returned, containing a subset of the JSON response data.

public class CurrentTaskStep {
private int id;
private String name;
private String displayName;
private String type;
private String typeName;
private List<WorkflowTransition> workflowTransitions;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getTypeName() {
return typeName;
}
public void setTypeName(String typeName) {
this.typeName = typeName;
}
public List<WorkflowTransition> getWorkflowTransitions() {
return workflowTransitions;
}
public void setWorkflowTransitions(List<WorkflowTransition> workflowTransitions) {
this.workflowTransitions = workflowTransitions;
}
public class WorkflowTransition {
private int id;
private int index;
private String text;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
}
public class TaskDetails {
private int id;
private CurrentTaskStep currentTaskStep;
private String targetAsset;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public CurrentTaskStep getCurrentTaskStep() {
return currentTaskStep;
}
public void setCurrentTaskStep(CurrentTaskStep currentTaskStep) {
this.currentTaskStep = currentTaskStep;
}
public String getTargetAsset() {
return targetAsset;
}
public void setTargetAsset(String targetAsset) {
this.targetAsset = targetAsset;
}
}
public static List<TaskDetails> getTasksFromProject(String wsBaseUrl, String token, int projectId)
throws IOException, URISyntaxException {
Gson gson = new GsonBuilder().create();
URI getUri = new URIBuilder(wsBaseUrl + "/ws-api/v1/tasks")
.addParameter("token", token)
.addParameter("projectId", String.valueOf(projectId))
.build();
List<TaskDetails> tasks = new ArrayList<>();
JsonObject jsonObject = getItems(getUri);
JsonArray items = jsonObject.getAsJsonArray("items");
Iterator<JsonElement> itemIterator = items.iterator();
while (itemIterator.hasNext()) {
JsonObject item = itemIterator.next().getAsJsonObject();
// Get the current task step details
JsonObject jsonCurrentTaskStep = item.getAsJsonObject("currentTaskStep");
CurrentTaskStep currentTaskStep = new CurrentTaskStep();
currentTaskStep.setId(jsonCurrentTaskStep.getAsJsonPrimitive("id").getAsInt());
currentTaskStep.setName(jsonCurrentTaskStep.getAsJsonPrimitive("name").getAsString());
currentTaskStep.setDisplayName(jsonCurrentTaskStep.getAsJsonPrimitive("displayName").getAsString());
currentTaskStep.setType(jsonCurrentTaskStep.getAsJsonPrimitive("type").getAsString());
currentTaskStep.setTypeName(jsonCurrentTaskStep.getAsJsonPrimitive("typeName").getAsString());
// Fetch the transitions
List<CurrentTaskStep.WorkflowTransition> workflowTransitions = new ArrayList<>();
Iterator<JsonElement> transitionsIt = jsonCurrentTaskStep.getAsJsonArray("workflowTransitions").iterator();
while (transitionsIt.hasNext()) {
workflowTransitions.add(gson.fromJson(transitionsIt.next(), CurrentTaskStep.WorkflowTransition.class));
}
currentTaskStep.setWorkflowTransitions(workflowTransitions);
// Bundle everything together
TaskDetails taskDetails = new TaskDetails();
taskDetails.setId(item.getAsJsonPrimitive("id").getAsInt());
taskDetails.setCurrentTaskStep(currentTaskStep);
// Fetch the target asset (if present)
JsonArray targetAssetsArray = item.getAsJsonArray("targetAssets");
if (targetAssetsArray.size() > 0) {
taskDetails.setTargetAsset(targetAssetsArray.get(0).getAsString());
}
// Add to the list
tasks.add(taskDetails);
}
return tasks;
}

Create Project Groups in SDL WorldServer using the REST API

In this article, I would like to present a method for creating a Project Group in SDL WorldServer using the REST API.

The method takes three parameters:
  1. wsBaseUrl
  2. token
  3. projectGroups
The wsBaseUrl must be the <serverURL>:<portnumber> where your WorldServer instance is running.

The second parameter is a security token, which can be retrieved by using the SDL WorldServer REST API as explained here.

The third parameter is a List of ProjectGroup objects, each one containing the data required for creating each Project Group in WorldServer. This includes the namedescriptionprojectTypeIdclientId, the list of files for translation (systemFiles) and the list of Locales (target locales). The systemFiles attribute (List of String) must be populated with each asset's internalName returned by the file upload process described here.

The method returns a List of CreateProjectGroupResponse objects, one for each project group created, containing the JSON response data. With this data, it is possible to verify if the call was successful and also retrieve the newly created project group id.

public class CreateProjectGroupResponse {
private String status;
private List<Response> response;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public List<Response> getResponse() {
return response;
}
public void setResponse(List<Response> response) {
this.response = response;
}
public class Response {
private String status;
private int response;
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public int getResponse() {
return response;
}
public void setResponse(int response) {
this.response = response;
}
}
}
public class Locale {
private int id;
private String dueDate;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getDueDate() {
return dueDate;
}
public void setDueDate(String dueDate) {
this.dueDate = dueDate;
}
}
view raw Locale.java hosted with ❤ by GitHub
public class ProjectGroup {
private String name;
private String description;
private int projectTypeId;
private int clientId;
private List<String> systemFiles;
private List<Locale> locales;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public int getProjectTypeId() {
return projectTypeId;
}
public void setProjectTypeId(int projectTypeId) {
this.projectTypeId = projectTypeId;
}
public int getClientId() {
return clientId;
}
public void setClientId(int clientId) {
this.clientId = clientId;
}
public List<String> getSystemFiles() {
return systemFiles;
}
public void setSystemFiles(List<String> systemFiles) {
this.systemFiles = systemFiles;
}
public List<Locale> getLocales() {
return locales;
}
public void setLocales(List<Locale> locales) {
this.locales = locales;
}
}
public static CreateProjectGroupResponse createProjectGroup(String wsBaseUrl, String token, List<ProjectGroup> projectGroups)
throws IOException, URISyntaxException {
JsonObject jsonObject = doPost(wsBaseUrl, "/ws-api/v1/projectGroups/create", token, projectGroups);
Gson gson = new GsonBuilder().create();
return gson.fromJson(jsonObject, CreateProjectGroupResponse.class);
}
public static JsonObject doPost(String wsBaseUrl, String restPath, String token, Object pojo)
throws IOException, URISyntaxException {
URI postUri = new URIBuilder(wsBaseUrl + restPath)
.addParameter("token", token)
.addParameter("content-type", "application/json")
.build();
HttpClient httpClient = HttpClientBuilder.create().build();
HttpPost httpPost = new HttpPost(postUri);
httpPost.setEntity(getStringEntity(pojo));
HttpResponse response = httpClient.execute(httpPost);
Gson gson = new GsonBuilder().create();
return gson.fromJson(new InputStreamReader(response.getEntity().getContent()), JsonObject.class);
}
private static StringEntity getStringEntity(Object pojo) {
Gson gson = new GsonBuilder().create();
String jsonString = gson.toJson(pojo);
return new StringEntity(jsonString, ContentType.APPLICATION_JSON);
}
public static void createProjectGroup(Properties config, String token) throws IOException, URISyntaxException, NumberFormatException {
if (!enableProjectCreation(config))
return;
// Upload assets
Collection<File> assetFiles = getIncomingFiles(config);
if (assetFiles == null || assetFiles.isEmpty()) {
System.out.println("There are no incoming files.");
return;
}
List<FileUploadResponse> responses = WSRestUtils.uploadAssets(getWsBaseUrl(config), token, assetFiles);
// Create project group
List<String> internalNames = new ArrayList<>();
for (FileUploadResponse fileUploadResponse : responses) {
internalNames.add(fileUploadResponse.getInternalName());
}
ProjectGroup projectGroup = new ProjectGroup();
projectGroup.setName("Project - " + internalNames.get(0));
projectGroup.setDescription("Project created using the REST API.");
projectGroup.setClientId(getClientId(config));
projectGroup.setProjectTypeId(getProjectTypeId(config));
projectGroup.setLocales(getLocales(config));
projectGroup.setSystemFiles(internalNames);
// Create the project group
CreateProjectGroupResponse response = WSRestUtils
.createProjectGroup(getWsBaseUrl(config), token, Arrays.asList(projectGroup));
if (StringUtils.equalsIgnoreCase(response.getStatus(), "OK")) {
System.out.println("Created project group with id: " + response.getResponse().get(0).getResponse());
// Move the asset files to the processed folder
File processedFolder = new File(getProcessedFolder(config));
for (File file : assetFiles) {
FileUtils.moveFileToDirectory(file, processedFolder, false);
}
System.out.println("Moved files to the processed folder");
}
}

Upload files to SDL WorldServer using the REST API

In this article, I would like to present a method for uploading a collection of files to SDL WorldServer using the REST API.

The method takes three parameters:
  1. wsBaseUrl
  2. token
  3. files
The wsBaseUrl must be the <serverURL>:<portnumber> where your WorldServer instance is running.

The second parameter is a security token, which can be retrieved by using the SDL WorldServer REST API as explained here.

The third parameter is a Collection of File objects for upload.

The method returns a List of FileUploadResponse objects, one for each uploaded file, containing data from the uploaded asset. With this information, it is possible to create Projects in WorldServer using the REST API and place these assets through translation.

public class FileUploadResponse {
private String name;
private String internalName;
private String fullName;
private String url;
private double size;
private long creationTime;
private boolean exists;
private File[] files;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInternalName() {
return internalName;
}
public void setInternalName(String internalName) {
this.internalName = internalName;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public double getSize() {
return size;
}
public void setSize(double size) {
this.size = size;
}
public long getCreationTime() {
return creationTime;
}
public void setCreationTime(long creationTime) {
this.creationTime = creationTime;
}
public boolean isExists() {
return exists;
}
public void setExists(boolean exists) {
this.exists = exists;
}
public File[] getFiles() {
return files;
}
public void setFiles(File[] files) {
this.files = files;
}
}
public static List<FileUploadResponse> uploadAssets(String wsBaseUrl, String token, Collection<File> files)
throws IOException, URISyntaxException {
List<FileUploadResponse> fileUploadResponses = new ArrayList<>();
for (File file : files) {
String boundary = "--" + UUID.randomUUID() + "--";
URI postUri = new URIBuilder(wsBaseUrl + "/ws-api/v1/files")
.addParameter("token", token)
.addParameter("content-type", "multipart/form-data; boundary=" + boundary)
.build();
MultipartEntityBuilder builder = MultipartEntityBuilder
.create()
.setMode(HttpMultipartMode.BROWSER_COMPATIBLE)
.setBoundary(boundary)
.addPart("file", new FileBody(file));
HttpPost httpPost = new HttpPost(postUri);
httpPost.setEntity(builder.build());
HttpClient httpClient = HttpClientBuilder.create().build();
HttpResponse response = httpClient.execute(httpPost);
Gson gson = new GsonBuilder().create();
FileUploadResponse fileUploadResp = gson
.fromJson(new InputStreamReader(response.getEntity().getContent()), FileUploadResponse.class);
fileUploadResponses.add(fileUploadResp);
}
return fileUploadResponses;
}

Retrieve the list of active Projects available in SDL WorldServer using the REST API

In this article, I would like to present a method for retrieving the list of active Projects in SDL WorldServer using the REST API.

The method takes two parameters:
  1. wsBaseUrl
  2. token
The wsBaseUrl must be the <serverURL>:<portnumber> where your WorldServer instance is running.

The second parameter is a security token, which can be retrieved by using the SDL WorldServer REST API as explained here.

The method returns a List of Project objects, one for each active project, containing a subset of the JSON response data.

public class Project {
private int id;
private int projectGroupId;
private String name;
private String description;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getProjectGroupId() {
return projectGroupId;
}
public void setProjectGroupId(int projectGroupId) {
this.projectGroupId = projectGroupId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
view raw Project.java hosted with ❤ by GitHub
public static List<Project> getActiveProjects(String wsBaseUrl, String token) throws IOException, URISyntaxException {
List<Project> activeProjects = new ArrayList<>();
URI getUri = new URIBuilder(wsBaseUrl + "/ws-api/v1/projects")
.addParameter("token", token)
.addParameter("onlyActive", "true")
.build();
JsonObject jsonObject = getItems(getUri);
JsonArray items = jsonObject.getAsJsonArray("items");
Iterator<JsonElement> itemIterator = items.iterator();
while (itemIterator.hasNext()) {
JsonObject item = itemIterator.next().getAsJsonObject();
Project project = new Project();
project.setId(item.getAsJsonPrimitive("id").getAsInt());
project.setProjectGroupId(item.getAsJsonPrimitive("projectGroupId").getAsInt());
project.setName(item.getAsJsonPrimitive("name").getAsString());
project.setDescription(item.getAsJsonPrimitive("description").getAsString());
activeProjects.add(project);
}
return activeProjects;
}

Connecting to SDL WorldServer using the REST API

It is now possible to connect to SDL WorldServer and perform a number of actions by using the WorldServer REST API. The REST API documentation is available from your WorldServer instance by accessing <serverURL>:<portnumber>/ws-api/docs/ws-api-doc-v1.html.

In this article I present a method for connecting to SDL WorldServer and fetching a security token to be used in all subsequent API calls.

public static String getSecurityToken(String wsBaseUrl, String username, String password) throws IOException {
StringBuilder loginJson = new StringBuilder();
loginJson.append("{");
loginJson.append("\"username\":\"" + username + "\",");
loginJson.append("\"password\":\"" + password + "\"");
loginJson.append("}");
HttpClient httpClient = HttpClientBuilder.create().build();
HttpPost httpPostRequest = new HttpPost(wsBaseUrl + "/ws-api/v1/login");
httpPostRequest.setHeader(new BasicHeader("Content-Type", "application/json"));
httpPostRequest.setHeader(new BasicHeader("Accept", "application/json"));
httpPostRequest.setEntity(new StringEntity(loginJson.toString()));
HttpResponse response = httpClient.execute(httpPostRequest);
Gson gson = new GsonBuilder().create();
JsonObject jsonLoginResponse = gson
.fromJson(new InputStreamReader(response.getEntity().getContent()), JsonObject.class);
return jsonLoginResponse.getAsJsonPrimitive("sessionId").getAsString();
}
The method takes three parameters:
  1. wsBaseUrl
  2. username
  3. password
The wsBaseUrl must be the <serverURL>:<portnumber> where your WorldServer instance is running. The login method will append the "/ws-api/v1/login" path required for invoking the REST based login call.

As mentioned earlier, the call returns a security token to be used in all subsequent API calls.