All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.lionbridge.content.sdk.ContentAPI Maven / Gradle / Ivy

There is a newer version: 2.2.0
Show newest version
package com.lionbridge.content.sdk;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.lionbridge.content.sdk.models.*;
import com.lionbridge.content.sdk.models.templates.AddProjectTemplate;
import com.lionbridge.content.sdk.models.templates.GenerateQuoteTemplate;
import com.lionbridge.content.sdk.utilities.ZipUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpRequest;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.FileEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BufferedHeader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;

import static java.lang.String.*;
import static java.lang.String.format;

/**
 * 

This is the main class for interacting with the Lionbridge Content API.

*

To use the Content API:

*
    *
  • instantiate an instance using your access key and secret
  • *
  • use the ContentAPI instance to send/received information
  • *
  • display the results of your operation
  • *
*

Here is a quick example that lists the services available:

*
{@code
 * try {
 *   ContentAPI contentApi = new ContentAPI(
 *     "LIOX_API_ACCESS_KEY_ID",
 *     "LIOX_API_SECRET_KEY",
 *     "LIOX_API_ENDPOINT",
 *     "LIOX_API_DEFAULT_CURRENCY"
 *   );
 *
 *   ServiceList serviceList = contentApi.listServices();
 *   serviceList.getServices().stream().map(service -> service.getName()).forEach(System.out::println);
 *
 * } catch (ContentAPIException e) {
 *   // Deal with exception...
 * }
 * }
*/ public class ContentAPI { private static final String VERSION = "2016-03-15"; private static final int TOO_MANY_REQUESTS_STATUS_CODE = 429; private static final long TOO_MANY_REQUESTS_TIMEOUT_MS = 60000; private final Logger LOGGER = LoggerFactory.getLogger(ContentAPI.class); private String defaultCurrency; private String host; private String keyId; private String rootPath; private String scheme; private String secretKey; private int port; public ContentAPI(final String keyId, final String secretKey, final String endpoint) throws ContentAPIException { this(keyId, secretKey, endpoint, null); } public ContentAPI(final String keyId, final String secretKey, final String endpoint, final String defaultCurrency) throws ContentAPIException { this.keyId = keyId; this.secretKey = secretKey; try { this.setUriDefaults(endpoint); } catch(Exception e) { throw new ContentAPIException(e); } this.setDefaultCurrency(defaultCurrency); } /** * Determine if the endpoint and credentials you provided are valid * @return A boolean representing validity * @throws ContentAPIException */ public boolean isValid() throws ContentAPIException { try (CloseableHttpClient httpClient = getCloseableClient()) { HttpGet request = generateGetRequest("/account/info"); CloseableHttpResponse response = httpClient.execute(request); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { return true; } else { return false; } } catch(Exception e) { throw new ContentAPIException(e); } } /** * Returns a list of Locales supported for translation * @return List of Locales * @throws ContentAPIException for any caught exception */ public LocaleList listLocales() throws ContentAPIException { LocaleList localeList = new LocaleList(); try (CloseableHttpClient httpClient = getCloseableClient()) { HttpGet request = generateGetRequest("/locales"); CloseableHttpResponse response = httpClient.execute(request); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { localeList = new XmlMapper().readValue( response.getEntity().getContent(), LocaleList.class ); } else { handleErrorResponse(response); } } catch(Exception e) { throw new ContentAPIException(e); } return localeList; } /** * Returns a list of Services provided by Lionbridge * @return List of Services * @throws ContentAPIException for any caught exception */ public ServiceList listServices() throws ContentAPIException { ServiceList serviceList = new ServiceList(); try (final CloseableHttpClient httpClient = getCloseableClient()) { HttpGet request = generateGetRequest("/services"); CloseableHttpResponse response = httpClient.execute(request); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { serviceList = new XmlMapper().readValue( response.getEntity().getContent(), ServiceList.class ); } else { handleErrorResponse(response); } } catch(Exception e) { throw new ContentAPIException(e); } return serviceList; } /** * Get information about a specific service * @param serviceId The ID of the service you want * @return The requested Service * @throws ContentAPIException for any caught exception */ public Service getService(int serviceId) throws ContentAPIException { Service service = new Service(); try (final CloseableHttpClient httpClient = getCloseableClient()) { HttpGet request = generateGetRequest(format("/services/%d", serviceId)); CloseableHttpResponse response = httpClient.execute(request); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { service = new XmlMapper().readValue( response.getEntity().getContent(), Service.class ); } else { handleErrorResponse(response); } } catch(Exception e) { throw new ContentAPIException(e); } return service; } /** * Set the class defaults based on an input URI path * @param uriPath the input path to use for the URI * @throws URISyntaxException */ public void setUriDefaults(final String uriPath) throws URISyntaxException { URI uri = new URI(uriPath); scheme = uri.getScheme(); host = uri.getHost(); port = uri.getPort(); rootPath = uri.getPath(); } /** * Returns the default currency * @return The default currency as a String */ public String getDefaultCurrency() { return defaultCurrency; } public void setDefaultCurrency(final String defaultCurrency) { this.defaultCurrency = defaultCurrency; } /** * Add a file for translation * @param mimeType type of the file - * This is an enum based on the MIME text, i.e. "text/plain" * @param inputFile the file selected for translation * @param languageCode the source language (the current language) * @return file information returned from the API * @throws ContentAPIException on any encountered exception */ public LBFile addFile(final String mimeType, final File inputFile, final String languageCode) throws ContentAPIException { LBFile file = null; try (final CloseableHttpClient httpClient = getCloseableClient()) { StringBuilder pathBuilder = new StringBuilder(); // TODO the replace() is a workaround for rejected images with a space in the file name final String encodedFileName = URLEncoder.encode(inputFile.getName(), "UTF-8").replace('+', '-'); if (languageCode == null) { //sample URI: /files/add/detect-language/file-name-here.xml pathBuilder.append("/files/add/detect-language/").append(encodedFileName); } else { //sample URI: /files/add/en-us/file-name-here.xml pathBuilder.append("/files/add/").append(languageCode).append("/").append(encodedFileName); } LOGGER.debug("addFile: pathBuilder=" + pathBuilder.toString() + ", mime=" + mimeType + ", rootPath=" + this.rootPath); // build request and header final HttpPost request = generatePostRequest(pathBuilder.toString()); LOGGER.trace("Request URL={}", request.getURI().toString()); request.setHeader(HttpHeaders.CONTENT_TYPE, mimeType); LOGGER.debug("addFile Request Content Header={}", request.getFirstHeader(HttpHeaders.CONTENT_TYPE)); LOGGER.trace("addFile Request Accept Header={}", request.getFirstHeader(HttpHeaders.ACCEPT)); // attach the file in the request body FileEntity inputEntity = new FileEntity(inputFile); request.setEntity(inputEntity); LOGGER.debug("API addFile Http request={}", request.toString()); boolean sendFile = true; while (sendFile) { // send the request and handle the response final CloseableHttpResponse response = httpClient.execute(request); LOGGER.debug("API addFile Response={}", response.toString()); int statusCode = response.getStatusLine().getStatusCode(); LOGGER.trace("API addFile Response phrase={}", response.getStatusLine().getReasonPhrase()); if (statusCode == HttpStatus.SC_CREATED) { LBFile fileInfo = new XmlMapper().readValue( response.getEntity().getContent(), LBFile.class ); LOGGER.debug("API handleAddFileResponse assetId={}", fileInfo.getAssetId()); file = fileInfo; sendFile = false; } else if (statusCode == TOO_MANY_REQUESTS_STATUS_CODE) { // wait one minute and try it again LOGGER.info("API addFile: Got too many requests."); Thread.sleep(TOO_MANY_REQUESTS_TIMEOUT_MS); } else { handleErrorResponse(response); sendFile = false; } } } catch (ContentAPIException e) { LOGGER.error("AddFile EXCEPTION", e); throw e; } catch (Exception e) { LOGGER.error("AddFile EXCEPTION", e); throw new ContentAPIException(e); } return file; } /** * Add a translation Project * @param projectName name of the project to create * @param translationOptions selected translation options * @param fileAssetIds file IDs to be translated * (must already have been added using addFile) * @return project information returned from the API * @throws ContentAPIException on any encountered exception */ public Project addProject( final String projectName, final TranslationOptions translationOptions, final List fileAssetIds ) throws ContentAPIException { return addProject(projectName, translationOptions, fileAssetIds, null, null); } /** * Add a translation Project * @param projectName name of the project to create * @param options selected translation options * @param fileAssetIds file IDs to be translated * (must already have been added using addFile) * @param referenceFileAssetIds * (must already have been added using addFile) * @return project information returned from the API * @throws ContentAPIException on any encountered exception */ public Project addProject( final String projectName, final TranslationOptions options, final List fileAssetIds, final List referenceFileAssetIds, List notifications ) throws ContentAPIException { Project result = null; try (final CloseableHttpClient httpClient = getCloseableClient()) { if (options == null) { throw new Exception("Must specify options"); } final HttpPost request = generatePostRequest("/projects/add"); AddProjectTemplate addProjectTemplate = new AddProjectTemplate(projectName, options, fileAssetIds, referenceFileAssetIds, notifications); StringEntity entity = new StringEntity(addProjectTemplate.toXmlString()); request.setEntity(entity); final CloseableHttpResponse response = httpClient.execute(request); final int statusCode = response.getStatusLine().getStatusCode(); LOGGER.trace("API addProject statusCode = {}", statusCode); if (statusCode == HttpStatus.SC_CREATED) { result = new XmlMapper().readValue( response.getEntity().getContent(), Project.class ); } else { this.handleErrorResponse(response); } } catch (ContentAPIException contentApiException) { LOGGER.error("AddProject EXCEPTION", contentApiException); throw contentApiException; } catch (Exception e) { LOGGER.error("AddProject EXCEPTION", e); throw new ContentAPIException(e); } return result; } /** * Create a quote from a list of projects * @param translationOptions The translation options to use for this Quote * @param projects The projects associate with this Quote (must already have been added using addProject) * @return The created Quote * @throws ContentAPIException */ public Quote addQuote(final TranslationOptions translationOptions, final List projects) throws ContentAPIException { return addQuote(translationOptions, projects, null); } /** * * @param translationOptions The translation options to use for this Quote * @param projects The projects associate with this Quote (must already have been added using addProject) * @param notifications A list of email addresses and/or URLs to send Quote Ready notifications to * @return The created Quote * @throws ContentAPIException */ public Quote addQuote(TranslationOptions translationOptions, List projects, List notifications) throws ContentAPIException { LOGGER.debug("\nAPI addQuote: Project 1 = {}", projects.get(0).getProjectId()); if (translationOptions == null) { throw new ContentAPIException("Must specify options to generate a quote"); } Quote result = null; try (CloseableHttpClient httpClient = getCloseableClient()) { HttpPost request = generatePostRequest("/quote/generate"); GenerateQuoteTemplate quoteTemplate = new GenerateQuoteTemplate(translationOptions, projects, notifications); StringEntity quoteEntity = new StringEntity(quoteTemplate.toXmlString()); request.setEntity(quoteEntity); CloseableHttpResponse response = httpClient.execute(request); LOGGER.debug("API addQuote Response={}", response.toString()); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED) { result = new XmlMapper().readValue( response.getEntity().getContent(), Quote.class ); LOGGER.debug( "API addQuote Result = {id: {}, status: {}}", result.getQuoteId(), result.getStatus() ); } else { handleErrorResponse(response); } } catch (ContentAPIException contentApiException) { throw contentApiException; } catch (Exception e) { throw new ContentAPIException(e); } return result; } public List listProjects() throws ContentAPIException { List projects = new ArrayList<>(); try { final CloseableHttpClient httpClient = this.getCloseableClient(); final HttpGet request = generateGetRequest("/projects"); final CloseableHttpResponse response = httpClient.execute(request); LOGGER.debug("\n\nAPI listProjects Response={}", response.toString()); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { final XmlMapper mapper = new XmlMapper(); projects = mapper.readValue(response.getEntity().getContent(), new TypeReference>() {}); } else { this.handleErrorResponse(response); } } catch (NoSuchAlgorithmException e) { LOGGER.debug("API listProjects NoSuchAlgorithmException", e); throw new ContentAPIException(e); } catch (URISyntaxException e) { LOGGER.debug("API listProjects URISyntaxException", e); throw new ContentAPIException(e); } catch (ClientProtocolException e) { LOGGER.debug("API listProjects ClientProtocolException", e); throw new ContentAPIException(e); } catch (IOException e) { LOGGER.debug("API listProjects IOException", e); throw new ContentAPIException(e); } catch (Exception e) { LOGGER.debug("API listProjects EXCEPTION", e); throw new ContentAPIException(e); } return projects; } public List getQuotesForJob(final String jobId, final String objectTitle) throws ContentAPIException { if(null == jobId) { throw new ContentAPIException("Cannot get quote info for null job ID."); } else if(jobId.trim().isEmpty()) { throw new ContentAPIException("Cannot get quote info for blank job ID."); } List quotes = null; // parse Job ID for name and creation date // /var/lionbridge-ondemand-connector/20160425/xmltest3_translationjob String jobName = ""; String jobCreationDate = ""; SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd"); String[] jobIdParts = jobId.split("/"); if(0 < jobIdParts.length) { // job name had better be last jobName = jobIdParts[jobIdParts.length - 1]; // now find the creation date. It should be just before the name. if(1 < jobIdParts.length) { int partNumber = jobIdParts.length - 2; while(0 <= partNumber) { String jobPart = jobIdParts[partNumber]; try { dateFormat.parse(jobPart); jobCreationDate = jobPart; break; } catch (ParseException e1) { // Hopefully this just means this piece isn't the date } partNumber--; } } } // list quotes, but don't bother if we didn't get a job name and creation date if(!jobName.isEmpty() && !jobCreationDate.isEmpty()) { final List allQuotes = this.listQuotes(); // loop through quotes to see if we can find the one matching this job for(Quote quote : allQuotes) { if(null != quote.getProjects()) { for(Project project : quote.getProjects()) { if(project.getName().toUpperCase().startsWith(jobName.toUpperCase())) { if(null == quotes) { quotes = new ArrayList(); } quotes.add(quote); } } } } } return quotes; } public Project getProject(final String projectId) throws ContentAPIException { LOGGER.debug("\nAPI getProject: projectId={}", projectId); if (null == projectId) { throw new ContentAPIException("Cannot get project info for null ID."); } else if(projectId.trim().isEmpty()) { throw new ContentAPIException("Cannot get project info for blank ID."); } Project projectInfo = null; try { CloseableHttpClient httpClient = this.getCloseableClient(); HttpGet request = generateGetRequest(format("/projects/%s", projectId.trim())); CloseableHttpResponse response = httpClient.execute(request); LOGGER.debug("API getProject Response={}" + response.toString()); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { projectInfo = new XmlMapper().readValue( response.getEntity().getContent(), Project.class ); LOGGER.debug("API getProject Result (MAPPED) = {}", projectInfo.toXmlStringSimple()); } else { handleErrorResponse(response); } } catch (NoSuchAlgorithmException e) { LOGGER.debug("API getProject NoSuchAlgorithmException", e); throw new ContentAPIException(e); } catch (URISyntaxException e) { LOGGER.debug("API getProject URISyntaxException", e); throw new ContentAPIException(e); } catch (ClientProtocolException e) { LOGGER.debug("API getProject ClientProtocolException", e); throw new ContentAPIException(e); } catch (IOException e) { LOGGER.debug("API getProject IOException", e); throw new ContentAPIException(e); } catch (Exception e) { LOGGER.debug("API getProject EXCEPTION", e); throw new ContentAPIException(e); } return projectInfo; } /** * Returns a list of all of the quotes owned by a user. * @return A list of Quote object * @throws ContentAPIException */ public List listQuotes() throws ContentAPIException { List quotes = new ArrayList<>(); try { final CloseableHttpClient httpClient = this.getCloseableClient(); final HttpGet request = generateGetRequest("/quote"); final CloseableHttpResponse response = httpClient.execute(request); LOGGER.debug("\n\nAPI listQuotes Response={}", response.toString()); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { final XmlMapper mapper = new XmlMapper(); quotes = mapper.readValue(response.getEntity().getContent(), new TypeReference>() {}); } else { this.handleErrorResponse(response); } } catch (NoSuchAlgorithmException e) { LOGGER.debug("API listQuotes NoSuchAlgorithmException", e); throw new ContentAPIException(e); } catch (URISyntaxException e) { LOGGER.debug("API listQuotes URISyntaxException", e); throw new ContentAPIException(e); } catch (ClientProtocolException e) { LOGGER.debug("API listQuotes ClientProtocolException", e); throw new ContentAPIException(e); } catch (IOException e) { LOGGER.debug("API listQuotes IOException", e); throw new ContentAPIException(e); } catch (Exception e) { LOGGER.debug("API listQuotes EXCEPTION", e); throw new ContentAPIException(e); } return quotes; } /** * Retrieve a single Quote * @param quoteId The ID of the desired quote * @return The desired Quote * @throws ContentAPIException */ public Quote getQuote(final String quoteId) throws ContentAPIException { LOGGER.debug("\nAPI getQuote: quoteId={}", quoteId); if(null == quoteId) { throw new ContentAPIException("Cannot get quote info for null ID."); } else if(quoteId.trim().isEmpty()) { throw new ContentAPIException("Cannot get quote info for blank ID."); } Quote quoteInfo = null; try { final CloseableHttpClient httpClient = this.getCloseableClient(); final HttpGet request = generateGetRequest(format("/quote/%s", quoteId.trim())); final CloseableHttpResponse response = httpClient.execute(request); LOGGER.debug("API getQuote Response={}", response.toString()); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { final XmlMapper mapper = new XmlMapper(); quoteInfo = mapper.readValue(response.getEntity().getContent(), Quote.class); LOGGER.debug("API getQuote Result = {}", quoteInfo.toXmlStringSimple()); } else { this.handleErrorResponse(response); } } catch (NoSuchAlgorithmException e) { LOGGER.debug("API getQuote NoSuchAlgorithmException", e); throw new ContentAPIException(e); } catch (URISyntaxException e) { LOGGER.debug("API getQuote URISyntaxException", e); throw new ContentAPIException(e); } catch (ClientProtocolException e) { LOGGER.debug("API getQuote ClientProtocolException", e); throw new ContentAPIException(e); } catch (IOException e) { LOGGER.debug("API getQuote IOException", e); throw new ContentAPIException(e); } catch (Exception e) { LOGGER.debug("API getQuote EXCEPTION", e); throw new ContentAPIException(e); } return quoteInfo; } /** * Authorizes a quote. Only quotes with a status of “Pending” can be authorized. * @param quoteId The ID of the desired quote * @param poNumber A PurchaseOrderNumber that matches a purchase order we have on file. * @return A QuoteAuthorization * @throws ContentAPIException */ public QuoteAuthorization authorizeQuote(final String quoteId, final String poNumber) throws ContentAPIException { LOGGER.debug("\nAPI authorizeQuote: quoteId={}, poNumber={}", quoteId, poNumber); if(null == quoteId) { throw new ContentAPIException("Cannot authorize quote for null ID."); } else if(quoteId.trim().isEmpty()) { throw new ContentAPIException("Cannot authorize quote for blank ID."); } else if(null == poNumber) { throw new ContentAPIException("Cannot authorize quote for null PO number."); } else if(poNumber.trim().isEmpty()) { throw new ContentAPIException("Cannot authorize quote for blank PO number."); } QuoteAuthorization quoteAuth = null; try { final CloseableHttpClient httpClient = this.getCloseableClient(); final HttpPost request = generatePostRequest(format("/quote/%s/authorize", quoteId.trim())); // get and update the quote info Quote quoteInfo = this.getQuote(quoteId); quoteInfo.setPurchaseOrderNumber(poNumber); StringEntity entity = new StringEntity(quoteInfo.toXmlForAuthorize()); request.setEntity(entity); LOGGER.debug("\nAPI authorizeQuote: request body={}", quoteInfo.toXmlForAuthorize()); final CloseableHttpResponse response = httpClient.execute(request); LOGGER.debug("API authorizeQuote Response={}", response.toString()); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_ACCEPTED) { final XmlMapper mapper = new XmlMapper(); quoteAuth = mapper.readValue(response.getEntity().getContent(), QuoteAuthorization.class); LOGGER.debug("API authorizeQuote Result = {}", quoteAuth.toXmlStringSimple()); } else { throw new ContentAPIException(response.getStatusLine().toString()); //this.handleErrorResponse(response); } } catch (NoSuchAlgorithmException e) { LOGGER.debug("API authorizeQuote NoSuchAlgorithmException", e); throw new ContentAPIException(e); } catch (URISyntaxException e) { LOGGER.debug("API authorizeQuote URISyntaxException", e); throw new ContentAPIException(e); } catch (ClientProtocolException e) { LOGGER.debug("API authorizeQuote ClientProtocolException", e); throw new ContentAPIException(e); } catch (IOException e) { LOGGER.debug("API authorizeQuote IOException", e); throw new ContentAPIException(e); } catch (Exception e) { LOGGER.debug("API authorizeQuote EXCEPTION", e); throw new ContentAPIException(e); } return quoteAuth; } /** * Returns details about a file * @param assetId The ID of the file you want details on * @return The requested file information * @throws ContentAPIException */ public LBFile getFileDetails(String assetId) throws ContentAPIException { LBFile lbFile = new LBFile(); try (final CloseableHttpClient httpClient = getCloseableClient()) { HttpGet request = generateGetRequest(format("/files/%s/details", assetId)); CloseableHttpResponse response = httpClient.execute(request); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { lbFile = new XmlMapper().readValue( response.getEntity().getContent(), LBFile.class ); } else { handleErrorResponse(response); } } catch(Exception e) { throw new ContentAPIException(e); } return lbFile; } /** * TODO This method was built on the assumption that a zip file was sent to * the Lionbridge API. That is no longer the case. However, this method is * not currently being used by the connector. If it ever is used, the method * will need to be rebuilt to be more like getTranslatedFile. * @param assetId * @return * @throws ContentAPIException */ public String getFile(final String assetId) throws ContentAPIException { LOGGER.debug("\nAPI getFile: assetId={}", assetId); if(null == assetId) { throw new ContentAPIException("Cannot get file info for null ID."); } else if(assetId.trim().isEmpty()) { throw new ContentAPIException("Cannot get file info for blank ID."); } File outputFile = null; try { final CloseableHttpClient httpClient = this.getCloseableClient(); final HttpGet request = generateGetRequest(format("/files/%s", assetId.trim())); final CloseableHttpResponse response = httpClient.execute(request); LOGGER.debug("API getFile Response={}", response.toString()); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { String fileName = ""; BufferedHeader fileNameHeader = (BufferedHeader) response.getFirstHeader("Content-Disposition"); if(null != fileNameHeader) { // Content-Disposition header should look like: // Content-Disposition: attachment; filename=add_file_only_20160405121236_20160405121236_564669.zip final String[] dispositionPieces = fileNameHeader.getValue().split("="); fileName = dispositionPieces[dispositionPieces.length - 1]; LOGGER.debug("Response file name (from firstHeader): {}", fileName); } if(fileName.isEmpty()) { fileName = "liondemand_" + assetId; LOGGER.debug("Failed to decipher file name. Using default name {}.", fileName); } File tempFolder = new File("/tmp/liondemand/getFile/" + assetId + "/"); if(!tempFolder.isDirectory()) { tempFolder.mkdirs(); } outputFile = new File(tempFolder, fileName); outputFile.createNewFile(); // build the file for return FileOutputStream fileStream = new FileOutputStream(outputFile); final int bytesCopied = IOUtils.copy(response.getEntity().getContent(), fileStream); LOGGER.debug("Copied {} bytes to output stream.", bytesCopied); fileStream.close(); } else { this.handleErrorResponse(response); } } catch (NoSuchAlgorithmException e) { LOGGER.debug("API getFile NoSuchAlgorithmException", e); throw new ContentAPIException(e); } catch (URISyntaxException e) { LOGGER.debug("API getFile URISyntaxException", e); throw new ContentAPIException(e); } catch (ClientProtocolException e) { LOGGER.debug("API getFile ClientProtocolException", e); throw new ContentAPIException(e); } catch (IOException e) { LOGGER.debug("API getFile IOException", e); throw new ContentAPIException(e); } catch (Exception e) { LOGGER.debug("API getFile EXCEPTION", e); throw new ContentAPIException(e); } if(null != outputFile) { final String extractPath = ZipUtils.extractFilesFromZip(outputFile, "extract"); return extractPath; } return null; } public File getTranslatedFile(final String assetId, final String languageCode) throws ContentAPIException { LOGGER.debug("\nAPI getTranslatedFile: assetId={}, language={}", assetId, languageCode); if(null == assetId) { throw new ContentAPIException("Cannot get translated file info for null ID."); } else if(assetId.trim().isEmpty()) { throw new ContentAPIException("Cannot get translated file info for blank ID."); } File translatedAsset = null; try { final CloseableHttpClient httpClient = this.getCloseableClient(); final HttpGet request = generateGetRequest(format("/files/%s/%s", assetId.trim(), languageCode)); CloseableHttpResponse response = null; while (true) { response = httpClient.execute(request); LOGGER.debug("API getTranslatedFile Response={}", response.toString()); int statusCode = response.getStatusLine().getStatusCode(); LOGGER.trace("API getTranslatedFile Response phrase={}", response.getStatusLine().getReasonPhrase()); if (statusCode == TOO_MANY_REQUESTS_STATUS_CODE) { // wait one minute and try it again LOGGER.info("API getTranslatedFile: Got too many requests."); Thread.sleep(TOO_MANY_REQUESTS_TIMEOUT_MS); } else { break; } } if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { String fileName = ""; BufferedHeader fileNameHeader = (BufferedHeader) response.getFirstHeader("Content-Disposition"); if(null != fileNameHeader) { // Content-Disposition header should look like: // Content-Disposition: attachment; filename=add_file_only_20160405121236_20160405121236_564669.zip final String[] dispositionPieces = fileNameHeader.getValue().split("="); fileName = dispositionPieces[dispositionPieces.length - 1]; LOGGER.debug("Response file name (from firstHeader): {}", fileName); } if(fileName.isEmpty()) { fileName = "liondemand_" + assetId; LOGGER.debug("Failed to decipher file name. Using default name {}.", fileName); } File tempFolder = new File("/tmp/liondemand/getTranslatedFile/" + assetId + "/" + languageCode + "/"); if(!tempFolder.isDirectory()) { tempFolder.mkdirs(); } translatedAsset = new File(tempFolder, fileName); final boolean fileCreated = translatedAsset.createNewFile(); LOGGER.debug("File {} created? {}", translatedAsset.getPath(), fileCreated); // build the file for translation FileOutputStream fileStream = new FileOutputStream(translatedAsset); final int bytesCopied = IOUtils.copy(response.getEntity().getContent(), fileStream); LOGGER.debug("Copied {} bytes to output stream.", bytesCopied); fileStream.close(); return translatedAsset; } else { this.handleErrorResponse(response); } } catch (NoSuchAlgorithmException e) { LOGGER.debug("API getTranslatedFile NoSuchAlgorithmException", e); throw new ContentAPIException(e); } catch (URISyntaxException e) { LOGGER.debug("API getTranslatedFile URISyntaxException", e); throw new ContentAPIException(e); } catch (ClientProtocolException e) { LOGGER.debug("API getTranslatedFile ClientProtocolException", e); throw new ContentAPIException(e); } catch (IOException e) { LOGGER.debug("API getTranslatedFile IOException", e); throw new ContentAPIException(e); } catch (Exception e) { LOGGER.debug("API getTranslatedFile EXCEPTION", e); throw new ContentAPIException(e); } return null; } public RejectTranslationOutput rejectTranslatedFile(final String assetId, final String languageCode) throws ContentAPIException { LOGGER.debug("\n\nAPI rejectTranslatedFile: assetId={}, language={}", assetId, languageCode); if(null == assetId) { throw new ContentAPIException("Cannot reject translated file for null ID."); } else if(assetId.trim().isEmpty()) { throw new ContentAPIException("Cannot reject translated file for blank ID."); } RejectTranslationOutput rejectOutput = null; try { final CloseableHttpClient httpClient = this.getCloseableClient(); final HttpPost request = generatePostRequest(format("/files/%s/%s/reject", assetId.trim(), languageCode)); final RejectFile rejectBody = new RejectFile(5000, "Not good enough"); StringEntity entity = new StringEntity(rejectBody.toXmlString()); request.setEntity(entity); LOGGER.debug("\nAPI rejectTranslatedFile: reject body={}", rejectBody.toXmlString()); final CloseableHttpResponse response = httpClient.execute(request); LOGGER.debug("API rejectTranslatedFile Response={}", response.toString()); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_ACCEPTED) { final XmlMapper mapper = new XmlMapper(); rejectOutput = mapper.readValue(response.getEntity().getContent(), RejectTranslationOutput.class); LOGGER.debug("API rejectTranslatedFile Result = {}", rejectOutput.toXmlStringSimple()); } else { this.handleErrorResponse(response); } } catch (NoSuchAlgorithmException e) { LOGGER.debug("API rejectTranslatedFile NoSuchAlgorithmException", e); throw new ContentAPIException(e); } catch (URISyntaxException e) { LOGGER.debug("API rejectTranslatedFile URISyntaxException", e); throw new ContentAPIException(e); } catch (ClientProtocolException e) { LOGGER.debug("API rejectTranslatedFile ClientProtocolException", e); throw new ContentAPIException(e); } catch (IOException e) { LOGGER.debug("API rejectTranslatedFile IOException", e); throw new ContentAPIException(e); } catch (Exception e) { LOGGER.debug("API rejectTranslatedFile EXCEPTION", e); throw new ContentAPIException(e); } return rejectOutput; } private HttpGet generateGetRequest(final String path) throws URISyntaxException, NoSuchAlgorithmException { final URI uri = this.getURI(path); final HttpGet request = new HttpGet(uri); request.setHeader(HttpHeaders.CONTENT_TYPE, "text/xml"); request.setHeader(HttpHeaders.ACCEPT, "text/xml"); setAuthHeaders(request, uri, "GET"); return request; } private HttpPost generatePostRequest(final String path) throws URISyntaxException, NoSuchAlgorithmException { final URI uri = getURI(path); final HttpPost request = new HttpPost(uri); request.setHeader(HttpHeaders.CONTENT_TYPE, "text/xml"); request.setHeader(HttpHeaders.ACCEPT, "text/xml"); setAuthHeaders(request, uri, "POST"); return request; } private void handleErrorResponse(final CloseableHttpResponse response) throws Exception { ErrorManager errorManager = null; final HttpEntity responseEntity = response.getEntity(); try { errorManager = new XmlMapper().readValue( responseEntity.getContent(), ErrorManager.class ); errorManager.setErrorCode( valueOf(response.getStatusLine().getStatusCode()) ); } catch(UnrecognizedPropertyException e) { // Gets thrown in case of errors such as 404, when HTML response is given. } if (errorManager == null) { StringBuilder errorBuilder = new StringBuilder(); errorBuilder.append(valueOf(response.getStatusLine().getStatusCode())) .append(": ") .append(response.getStatusLine().getReasonPhrase()); throw new ContentAPIException(errorBuilder.toString()); } else { throw errorManager.generateException(); } } private void setAuthHeaders(HttpRequest request, final URI uri, final String method) throws NoSuchAlgorithmException { final String timestamp = getTimestamp(); final String authorizationHeader = getAuthHeader(method, uri.getPath(), timestamp, VERSION); request.addHeader("x-lod-timestamp", timestamp); request.addHeader("x-lod-version", VERSION); request.setHeader(HttpHeaders.AUTHORIZATION, authorizationHeader); } private String getTimestamp() { final StringBuilder timestamp = new StringBuilder(); final Date now = new Date(); final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); timestamp.append(dateFormat.format(now)); timestamp.append("0000"); return timestamp.toString(); } private String getAuthHeader(final String method, final String resource, final String timestamp, final String version) throws NoSuchAlgorithmException { String signature = this.getSignature(method, resource, timestamp, version); return getHeaderFromSignature(signature); } private String getHeaderFromSignature(final String signature) { return "LOD1-BASE64-SHA256 " + "KeyID=" + this.keyId + ",Signature=" + signature + ",SignedHeaders=x-lod-timestamp;x-lod-version;accept"; } private String getSignature(final String method, final String resource, final String timestamp, final String version) throws NoSuchAlgorithmException { String toEncode = method + ":" + resource + ":" + secretKey + ":" + timestamp + ":" + version + ":text/xml"; return encodeSignature(toEncode); } private String encodeSignature(final String input) throws NoSuchAlgorithmException { final MessageDigest mDigest = MessageDigest.getInstance("SHA-256"); byte[] result = mDigest.digest(input.getBytes(StandardCharsets.US_ASCII)); return Base64.encodeBase64String(result); } private CloseableHttpClient getCloseableClient() { return HttpClients.custom().build(); } private URI getURI(final String path) throws URISyntaxException { URIBuilder uriBuilder = new URIBuilder(); uriBuilder.setScheme(scheme); uriBuilder.setHost(host); uriBuilder.setPath(rootPath + path); if (-1 != port) { uriBuilder.setPort(port); } return uriBuilder.build(); } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy