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.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
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.Locale;
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.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.InputStream;
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.*;

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

/**
 * 

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 final XmlMapper xmlMapper = getConfiguredXmlMapper(); 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); } @SuppressWarnings("deprecation") public ContentAPI(final String keyId, final String secretKey, final String endpoint, final String defaultCurrency) throws ContentAPIException { this.keyId = keyId; this.secretKey = secretKey; try { setUriDefaults(endpoint); } catch (Exception e) { throw new ContentAPIException(e); } setDefaultCurrency(defaultCurrency); } /** * @deprecated This method will become private in the next release */ @Deprecated 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; } /** * @deprecated This method will become private in the next release */ @Deprecated public void setDefaultCurrency(final String defaultCurrency) { this.defaultCurrency = defaultCurrency; } /** * Determine if the endpoint and credentials you provided are valid * * @return A boolean representing validity * @throws ContentAPIException An exception containing any API errors */ public boolean isValid() throws ContentAPIException { try { CloseableHttpClient httpClient = getCloseableClient(); HttpGet request = generateGetRequest("/account/info"); CloseableHttpResponse response = httpClient.execute(request); return response.getStatusLine().getStatusCode() == HttpStatus.SC_OK; } catch (Exception e) { throw new ContentAPIException(e); } } /** * @deprecated You should use getLocales instead */ @Deprecated public LocaleList listLocales() throws ContentAPIException { return getApiObject("/locales", LocaleList.class); } /** * Returns a list of Locales supported for translation * * @return List of Locales * @throws ContentAPIException An exception containing any API errors */ public List getLocales() throws ContentAPIException { return getApiObjectList("/locales", Locale.class); } /** * @deprecated You should use getServices instead */ @Deprecated public ServiceList listServices() throws ContentAPIException { return getApiObject("/services", ServiceList.class); } /** * Returns a list of Services provided by Lionbridge * * @return List of Services * @throws ContentAPIException An exception containing any API errors */ public List getServices() throws ContentAPIException { return getApiObjectList("/services", Service.class); } /** * Get information about a specific service * * @param serviceId The ID of the service you want * @return The requested Service * @throws ContentAPIException An exception containing any API errors */ public Service getService(int serviceId) throws ContentAPIException { return getApiObject(format("/services/%d", serviceId), Service.class); } /** * Use this method to retrieve all your projects * * @return A List of Projects * @throws ContentAPIException An exception containing any API errors */ public List listProjects() throws ContentAPIException { return getApiObjectList("/projects", Project.class); } /** * Returns a list of all of the quotes owned by a user. * * @return A list of Quote objects * @throws ContentAPIException An exception containing any API errors */ public List listQuotes() throws ContentAPIException { return getApiObjectList("/quote", Quote.class); } /** * Retrieve a Project by ID * * @param projectId The ID of the Project you want * @return The requested Project * @throws ContentAPIException An exception containing any API errors */ public Project getProject(final String projectId) throws ContentAPIException { 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."); } return getApiObject(format("/projects/%s", projectId.trim()), Project.class); } /** * Retrieve a single Quote by ID * * @param quoteId The ID of the desired quote * @return The desired Quote * @throws ContentAPIException An exception containing any API errors */ public Quote getQuote(final String quoteId) throws ContentAPIException { 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."); } return getApiObject(format("/quote/%s", quoteId.trim()), Quote.class); } /** * Returns details about a file * * @param assetId The ID of the file you want details on * @return The requested file information * @throws ContentAPIException An exception containing any API errors */ public LBFile getFileDetails(String assetId) throws ContentAPIException { if (null == assetId) { throw new ContentAPIException("Cannot get file details for null asset ID."); } else if (assetId.trim().isEmpty()) { throw new ContentAPIException("Cannot get file details for blank asset ID."); } return getApiObject(format("/files/%s/details", assetId), LBFile.class); } /** * @deprecated You should use getQuotesForJob(String jobId) instead */ @Deprecated @SuppressWarnings("unused") public List getQuotesForJob(String jobId, String objectTitle) throws ContentAPIException { return getQuotesForJob(jobId); } /** * Retrieve a list of Quotes associated with a Job * * @param jobId The Job ID you want Quotes for * @return A List of Quotes * @throws ContentAPIException An exception containing any API errors */ public List getQuotesForJob(String jobId) 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; } /** * Downloads the desired file and stores it at the returned path * * @param assetId The ID of the desired file * @return A string representing the path of the downloaded files * @throws ContentAPIException An exception containing any API errors */ public String getFile(final String assetId) throws ContentAPIException { /* * 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. */ 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 { CloseableHttpClient httpClient = this.getCloseableClient(); HttpGet request = generateGetRequest(format("/files/%s", assetId.trim())); CloseableHttpResponse response = httpClient.execute(request); 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 String[] dispositionPieces = fileNameHeader.getValue().split("="); fileName = dispositionPieces[dispositionPieces.length - 1]; } if (fileName.isEmpty()) { fileName = "liondemand_" + assetId; } 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); IOUtils.copy(response.getEntity().getContent(), fileStream); fileStream.close(); } else { handleErrorResponse(response); } } catch (Exception e) { throw new ContentAPIException(e); } if (null != outputFile) { return ZipUtils.extractFilesFromZip(outputFile, "extract"); } return null; } /** * Get the translated version of a file * * @param assetId The ID of the source file * @param languageCode The language code of the desired translation * @return The translated file as a File object * @throws ContentAPIException An exception containing any API errors */ public File getTranslatedFile(final String assetId, final String languageCode) throws ContentAPIException { 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; try { CloseableHttpClient httpClient = this.getCloseableClient(); HttpGet request = generateGetRequest(format("/files/%s/%s", assetId.trim(), languageCode)); CloseableHttpResponse response = null; while (true) { response = httpClient.execute(request); int statusCode = response.getStatusLine().getStatusCode(); 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 String[] dispositionPieces = fileNameHeader.getValue().split("="); fileName = dispositionPieces[dispositionPieces.length - 1]; } if (fileName.isEmpty()) { fileName = "liondemand_" + assetId; } File tempFolder = new File("/tmp/liondemand/getTranslatedFile/" + assetId + "/" + languageCode + "/"); if (!tempFolder.isDirectory()) { tempFolder.mkdirs(); } translatedAsset = new File(tempFolder, fileName); translatedAsset.createNewFile(); // build the file for translation FileOutputStream fileStream = new FileOutputStream(translatedAsset); IOUtils.copy(response.getEntity().getContent(), fileStream); fileStream.close(); return translatedAsset; } else { handleErrorResponse(response); } } catch (Exception e) { throw new ContentAPIException(e); } return null; } /** * 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 An exception containing any API errors */ public LBFile addFile(final String mimeType, final File inputFile, final String languageCode) throws ContentAPIException { LBFile file = null; try { CloseableHttpClient httpClient = getCloseableClient(); StringBuilder pathBuilder = new StringBuilder(); // TODO the replace() is a workaround for rejected images with a space in the file name 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); } // build request and header final HttpPost request = generatePostRequest(pathBuilder.toString()); request.setHeader(HttpHeaders.CONTENT_TYPE, mimeType); // attach the file in the request body FileEntity inputEntity = new FileEntity(inputFile); request.setEntity(inputEntity); boolean sendFile = true; while (sendFile) { // send the request and handle the response final CloseableHttpResponse response = httpClient.execute(request); int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_CREATED) { LBFile fileInfo = xmlMapper.readValue(response.getEntity().getContent(), LBFile.class); 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) { throw e; } catch (Exception e) { throw new ContentAPIException(e); } return file; } /** * Add a file by URL for translation * * @param url The URL of the file you want to add. * @param languageCode the source language (the current language) * @return file information returned from the API * @throws ContentAPIException An exception containing any API errors */ public LBFile addFileByReference(URI url, String languageCode) throws ContentAPIException { LBFile file = null; try { CloseableHttpClient httpClient = getCloseableClient(); StringBuilder pathBuilder = new StringBuilder(); String[] pathParts =url.getPath().split("/"); String encodedFileName = pathParts[pathParts.length-1]; if (languageCode == null) { pathBuilder.append("/files/add_by_reference/detect-language/").append(encodedFileName); } else { pathBuilder.append("/files/add_by_reference/").append(languageCode).append("/").append(encodedFileName); } StringEntity stringEntity = new StringEntity("" + url.toString() + ""); HttpPost request = generatePostRequest(pathBuilder.toString()); request.setHeader(HttpHeaders.CONTENT_TYPE, "text/xml"); request.setHeader(HttpHeaders.ACCEPT, "text/xml"); request.setEntity(stringEntity); boolean sendFile = true; while (sendFile) { CloseableHttpResponse response = httpClient.execute(request); int statusCode = response.getStatusLine().getStatusCode(); if (statusCode == HttpStatus.SC_ACCEPTED) { LBFile fileInfo = xmlMapper.readValue(response.getEntity().getContent(), LBFile.class); file = fileInfo; sendFile = false; } else if (statusCode == TOO_MANY_REQUESTS_STATUS_CODE) { LOGGER.info("API addFile: Got too many requests."); Thread.sleep(TOO_MANY_REQUESTS_TIMEOUT_MS); } else { handleErrorResponse(response); sendFile = false; } } } catch (ContentAPIException e) { throw e; } catch (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 An exception containing any API errors */ 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 translationOptions 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) * @param notifications A list of notification endpoints * @return project information returned from the API * @throws ContentAPIException An exception containing any API errors */ public Project addProject( final String projectName, final TranslationOptions translationOptions, final List fileAssetIds, final List referenceFileAssetIds, List notifications ) throws ContentAPIException { AddProjectTemplate addProjectTemplate = new AddProjectTemplate(projectName, translationOptions, fileAssetIds, referenceFileAssetIds, notifications); return postApiObject( "/projects/add", addProjectTemplate.toXmlString(), Project.class ); } /** * 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 An exception containing any API errors */ 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 An exception containing any API errors */ public Quote addQuote(TranslationOptions translationOptions, List projects, List notifications) throws ContentAPIException { if (translationOptions == null) { throw new ContentAPIException("Must specify options to generate a quote"); } GenerateQuoteTemplate quoteTemplate = new GenerateQuoteTemplate(translationOptions, projects, notifications); return postApiObject( "/quote/generate", quoteTemplate.toXmlString(), Quote.class ); } /** * 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. * @param notificationList A list of endpoints to notify when the quote is paid. * @return A QuoteAuthorization * @throws ContentAPIException An exception containing any API errors */ public QuoteAuthorization authorizeQuote(String quoteId, String poNumber, List notificationList) throws ContentAPIException { 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."); } Quote quoteInfo = getQuote(quoteId); quoteInfo.setPurchaseOrderNumber(poNumber); List notificationSubscriptions = new ArrayList<>(); if (notificationList != null) { for (String endpoint : notificationList) { NotificationSubscription notificationSubscription = new NotificationSubscription(); notificationSubscription.setEndpoint(endpoint); notificationSubscription.setEventName("quote-paid"); notificationSubscriptions.add(notificationSubscription); } quoteInfo.setNotificationSubscriptions(notificationSubscriptions); } return postApiObject( format("/quote/%s/authorize", quoteId.trim()), quoteInfo.toXmlForAuthorize(), QuoteAuthorization.class ); } /** * 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 An exception containing any API errors */ public QuoteAuthorization authorizeQuote(final String quoteId, final String poNumber) throws ContentAPIException { return authorizeQuote(quoteId, poNumber, null); } /** * Reject a Quote * @param quoteId The ID of the quote to reject * @return A RejectQuote representing the status */ public RejectQuote rejectQuote(String quoteId) throws ContentAPIException { try { CloseableHttpClient httpClient = getCloseableClient(); HttpPost request = generatePostRequest(format("/quote/%s/reject", quoteId)); CloseableHttpResponse response = httpClient.execute(request); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { InputStream content = response.getEntity().getContent(); return xmlMapper.readValue(content, RejectQuote.class); } else { handleErrorResponse(response); } } catch (ContentAPIException contentApiException) { throw contentApiException; } catch (Exception e) { throw new ContentAPIException(e); } return null; } /** * Reject the translation of a file for the given language code * * @param assetId The ID of the source file * @param languageCode The language code for the translation you want to reject * @return A string representing the result of the operation * @throws ContentAPIException An exception containing any API errors */ public RejectTranslationOutput rejectTranslatedFile(final String assetId, final String languageCode) throws ContentAPIException { 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."); } RejectFile rejectBody = new RejectFile(5000, "Not good enough"); return postApiObject( format("/files/%s/%s/reject", assetId.trim(), languageCode), rejectBody.toXmlString(), RejectTranslationOutput.class ); } private HttpGet generateGetRequest(final String path) throws URISyntaxException, NoSuchAlgorithmException { URI uri = getURI(path); 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 { URI uri = getURI(path); 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; HttpEntity responseEntity = response.getEntity(); try { errorManager = 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) { String errorBuilder = format( "%s: %s", valueOf(response.getStatusLine().getStatusCode()), response.getStatusLine().getReasonPhrase() ); ContentAPIException contentAPIException = new ContentAPIException(); contentAPIException.setErrors(errorManager.getErrors()); throw contentAPIException; } else { throw errorManager.generateException(); } } private void setAuthHeaders(HttpRequest request, final URI uri, final String method) throws NoSuchAlgorithmException { String timestamp = getTimestamp(); 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() { StringBuilder timestamp = new StringBuilder(); Date now = new Date(); 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 = 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 { 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(); } private XmlMapper getConfiguredXmlMapper() { XmlMapper xmlMapper = new XmlMapper(); xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); return xmlMapper; } private T getApiObject(String path, Class valueType) throws ContentAPIException { try { CloseableHttpClient httpClient = getCloseableClient(); HttpGet request = generateGetRequest(path); CloseableHttpResponse response = httpClient.execute(request); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { return xmlMapper.readValue(response.getEntity().getContent(), valueType); } else { handleErrorResponse(response); } } catch (ContentAPIException contentApiException) { throw contentApiException; } catch (Exception e) { throw new ContentAPIException(e); } return null; } private T postApiObject(String path, String entity, Class valueType) throws ContentAPIException { try { StringEntity stringEntity = new StringEntity(entity); CloseableHttpClient httpClient = getCloseableClient(); HttpPost request = generatePostRequest(path); request.setEntity(stringEntity); CloseableHttpResponse response = httpClient.execute(request); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_ACCEPTED || response.getStatusLine().getStatusCode() == HttpStatus.SC_CREATED) { return xmlMapper.readValue(response.getEntity().getContent(), valueType); } else { handleErrorResponse(response); } } catch (ContentAPIException contentApiException) { throw contentApiException; } catch (Exception e) { throw new ContentAPIException(e); } return null; } private List getApiObjectList(String path, Class klazz) throws ContentAPIException { List objectList = new ArrayList<>(); try { CloseableHttpClient httpClient = this.getCloseableClient(); HttpGet request = generateGetRequest(path); CloseableHttpResponse response = httpClient.execute(request); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { JavaType type = xmlMapper.getTypeFactory().constructCollectionType(List.class, klazz); objectList = xmlMapper.readValue(response.getEntity().getContent(), type); } else { handleErrorResponse(response); } } catch (ContentAPIException contentApiException) { throw contentApiException; } catch (Exception e) { throw new ContentAPIException(e); } return objectList; } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy