TransifexServiceImpl.java
/**
* Copyright 2014 Global Crop Diversity Trust
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
package org.genesys.transifex.client;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.Locale;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;
/**
* Java implementation for Transifex API 2.
*
* @author alexandr
* @author matijaobreza
*/
@Service
public class TransifexServiceImpl implements TransifexService, InitializingBean {
/** The Constant LOG. */
private static final Logger LOG = Logger
.getLogger(TransifexServiceImpl.class);
/** The Constant TRANSIFEX_API_URL. */
private static final String TRANSIFEX_API_URL = "https://www.transifex.com/api/2";
/** Transifex project slug */
@Value("${transifex.project}")
private String projectSlug;
/** The trasifex user name. */
@Value("${transifex.username}")
private String trasifexUserName;
/** The transifex passord. */
@Value("${transifex.password}")
private String transifexPassord;
/** The content template. */
@Value("${transifex.content.template}")
private String contentTemplate;
/** The Spring REST template. */
private RestTemplate template = new RestTemplate();
/** The transifex project url. */
private String transifexProjectUrl;
/*
* (non-Javadoc)
*
* @see
* org.springframework.beans.factory.InitializingBean#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() throws Exception {
transifexProjectUrl = TRANSIFEX_API_URL.concat("/project/").concat(
projectSlug);
LOG.info("Transifex project URL: " + transifexProjectUrl);
// ensureTransifexCredentials();
}
/**
* Ensure transifex credentials.
*
* @throws TransifexException
* the transifex exception
*/
@Override
public void testCredentials() throws TransifexException {
HttpHeaders headers = basicAuthentication();
HttpEntity<String> request = new HttpEntity<>(headers);
try {
ResponseEntity<String> response = template.exchange(
transifexProjectUrl + "/?details", HttpMethod.GET, request,
String.class);
// response.getBody() // contains JSON information about the project
if (LOG.isInfoEnabled()) {
LOG.info("Transifex connection okay! HTTP status code="
+ response.getStatusCode());
}
} catch (HttpClientErrorException e) {
// Fail here to stop initializing the context!
throw new TransifexException(
"Transifex credentials are not valid.", e);
}
}
/**
* Transifex requires Basic HTTP authentication! This method adds Basic
* authentication.
*
* @return the http headers with Auhtorization header
*/
protected HttpHeaders basicAuthentication() {
HttpHeaders headers = new HttpHeaders();
String trasifexCreds = trasifexUserName + ":" + transifexPassord;
byte[] transifexCredsBytes = trasifexCreds.getBytes();
byte[] base64CredsBytes = Base64.encodeBase64(transifexCredsBytes);
String base64Creds = new String(base64CredsBytes);
headers.add("Authorization", "Basic " + base64Creds);
return headers;
}
/*
* (non-Javadoc)
*
* @see
* org.genesys.transifex.client.TransifexService#resourceExists(java.lang
* .String)
*/
@Override
public boolean resourceExists(String slug) {
if (LOG.isDebugEnabled()) {
LOG.debug("Checking for resource " + slug);
}
ResponseEntity<String> response;
HttpHeaders headers = basicAuthentication();
HttpEntity<String> request = new HttpEntity<>(headers);
try {
response = template.exchange(transifexProjectUrl
+ "/resource/{slug}", HttpMethod.GET, request,
String.class, slug);
if (LOG.isDebugEnabled()) {
LOG.debug(response.getStatusCode() + " " + response.getBody());
}
} catch (HttpClientErrorException e) {
return false;
}
return response.getStatusCode().value() == HttpStatus.OK.value();
}
/*
* (non-Javadoc)
*
* @see
* org.genesys.transifex.client.TransifexService#deleteResource(java.lang
* .String)
*/
@Override
public boolean deleteResource(String slug) throws TransifexException {
HttpHeaders headers = basicAuthentication();
HttpEntity<String> request = new HttpEntity<>(headers);
try {
ResponseEntity<String> response = template.exchange(
transifexProjectUrl + "/resource/{slug}",
HttpMethod.DELETE, request, String.class, slug);
if (response.getStatusCode().value() == 204) {
return true;
}
return false;
} catch (HttpClientErrorException e) {
throw new TransifexException(e.getMessage(), e);
}
}
/*
* (non-Javadoc)
*
* @see
* org.genesys.transifex.client.TransifexService#getTranslatedResource(
* java.lang.String, java.util.Locale)
*/
@Override
public String getTranslatedResource(String slug, Locale locale, TranslationMode mode)
throws TransifexException {
HttpHeaders headers = basicAuthentication();
HttpEntity<String> request = new HttpEntity<>(headers);
try {
ResponseEntity<String> response = template.exchange(
transifexProjectUrl
+ "/resource/{slug}/translation/{language}?mode={mode}",
HttpMethod.GET, request, String.class, slug,
locale.toLanguageTag(), mode.toString().toLowerCase());
// FIXME Check response status. Proceed only on HTTP OK response.
if (LOG.isDebugEnabled()) {
LOG.debug("Response code=" + response.getStatusCode());
}
return response.getBody();
} catch (HttpClientErrorException | ResourceAccessException e) {
throw new TransifexException("Error fetching translated resource",
e);
}
}
/*
* (non-Javadoc)
*
* @see
* org.genesys.transifex.client.TransifexService#downloadTranslatedResource
* (java.lang.String, java.util.Locale)
*/
@Override
public String downloadTranslatedResource(String slug, Locale locale, TranslationMode mode)
throws TransifexException {
HttpHeaders headers = basicAuthentication();
HttpEntity<byte[]> request = new HttpEntity<>(headers);
try {
ResponseEntity<byte[]> response = template.exchange(
transifexProjectUrl
+ "/resource/{slug}/translation/{language}?mode={mode}&file",
HttpMethod.GET, request, byte[].class, slug,
locale.toLanguageTag(), mode.toString().toLowerCase());
// FIXME Check response status. Proceed only on HTTP OK response.
if (LOG.isDebugEnabled()) {
LOG.debug("Response code=" + response.getStatusCode());
LOG.debug("Response ct="
+ response.getHeaders().getContentType());
}
// Do it with byte[] so we can enforce UTF8
return new String(response.getBody(), Charset.forName("UTF-8"));
} catch (HttpClientErrorException e) {
throw new TransifexException("Error fetching translated resource",
e);
}
}
/*
* (non-Javadoc)
*
* @see
* org.genesys.transifex.client.TransifexService#createXhtmlResource(java
* .lang.String, java.lang.String, java.lang.String)
*/
@Override
public void createXhtmlResource(String slug, String title, String content)
throws IOException {
// Make the authentication for Transifex
HttpHeaders headers = basicAuthentication();
// We will request like MULTIPART_FORM_DATA
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
// Create Multi value map with all necessary information for request
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("slug", slug);
map.add("name", title);
map.add("i18n_type", "XHTML");
File tempFile = File.createTempFile(slug, ".xhtml");
// default FileWriter support default encoding only
try (BufferedWriter writer = new BufferedWriter(
new FileWriter(tempFile))) {
LOG.debug(content);
// This is template our xhtml
String xhtmlContent = String
.format(contentTemplate, title, content);
IOUtils.write(xhtmlContent, writer);
writer.flush();
Resource resource = new FileSystemResource(tempFile);
map.add("content", resource);
// Create our request entity
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(
map, headers);
// Send our post request(with .xhtml file) to Transifex
ResponseEntity<Object> response = template.postForEntity(
transifexProjectUrl + "/resources/", request, Object.class);
if (LOG.isDebugEnabled()) {
// 201 CREATED is returned by Transifex API 2
LOG.debug("Response: " + response.getStatusCode());
}
} catch (HttpClientErrorException e) {
LOG.error(e.getMessage());
LOG.error(e.getResponseBodyAsString());
throw e;
} finally {
tempFile.delete();
}
}
/*
* (non-Javadoc)
*
* @see
* org.genesys.transifex.client.TransifexService#updateXhtmlResource(java
* .lang.String, java.lang.String, java.lang.String)
*/
@Override
public void updateXhtmlResource(String slug, String title, String content)
throws IOException {
if (!resourceExists(slug)) {
// POST the resource
createXhtmlResource(slug, title, content);
return;
}
LOG.info("Updating Transifex resource " + slug);
// Make the authentication for Transifex
HttpHeaders headers = basicAuthentication();
// We will request like MULTIPART_FORM_DATA
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
// Create Multi value map with all necessary information for request
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
// map.add("slug", slug);
// map.add("name", title);
// map.add("i18n_type", "XHTML");
File tempFile = File.createTempFile(slug, ".xhtml");
// default FileWriter support default encoding only
try (BufferedWriter writer = new BufferedWriter(
new FileWriter(tempFile))) {
LOG.debug(content);
// This is template our xhtml
String xhtmlContent = String
.format(contentTemplate, title, content);
IOUtils.write(xhtmlContent, writer);
writer.flush();
Resource resource = new FileSystemResource(tempFile);
map.add("content", resource);
// Create our request entity
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(
map, headers);
// Send our post request(with .xhtml file) to Transifex
template.put(transifexProjectUrl + "/resource/{slug}/content/",
request, slug);
} catch (HttpClientErrorException e) {
LOG.error(e.getMessage());
LOG.error(e.getResponseBodyAsString());
throw e;
} finally {
tempFile.delete();
}
}
/**
* Creates the properties xml resource.
*
* @param slug
* the slug
* @param title
* the title
* @param file
* the file
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public void createPropertiesXmlResource(String slug, String title, File file)
throws IOException {
// Make the authentication for Transifex
HttpHeaders headers = basicAuthentication();
// We will request like MULTIPART_FORM_DATA
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
// Create Multi value map with all necessary information for request
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
map.add("slug", slug);
map.add("name", title);
map.add("i18n_type", "PROPERTIESXML");
try {
Resource resource = new FileSystemResource(file);
map.add("content", resource);
// Create our request entity
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(
map, headers);
// Send our post reques to Transifex
ResponseEntity<Object> response = template.postForEntity(
transifexProjectUrl + "/resources/", request, Object.class);
if (LOG.isDebugEnabled()) {
// 201 CREATED is returned by Transifex API 2
LOG.debug("Response: " + response.getStatusCode());
}
} catch (HttpClientErrorException e) {
LOG.error(e.getMessage());
LOG.error(e.getResponseBodyAsString());
throw e;
} finally {
}
}
/*
* (non-Javadoc)
*
* @see
* org.genesys.transifex.client.TransifexService#updatePropertiesXmlResource
* (java.lang.String, java.lang.String, java.io.File)
*/
@Override
public void updatePropertiesXmlResource(String slug, String title, File file)
throws IOException {
if (!resourceExists(slug)) {
// POST the resource
createPropertiesXmlResource(slug, title, file);
return;
}
LOG.info("Updating Transifex resource " + slug);
// Make the authentication for Transifex
HttpHeaders headers = basicAuthentication();
// We will request like MULTIPART_FORM_DATA
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
// Create Multi value map with all necessary information for request
MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
try {
Resource resource = new FileSystemResource(file);
map.add("content", resource);
// Create our request entity
HttpEntity<MultiValueMap<String, Object>> request = new HttpEntity<>(
map, headers);
// Send our post request(with .xhtml file) to Transifex
template.put(transifexProjectUrl + "/resource/{slug}/content/",
request, slug);
} catch (HttpClientErrorException e) {
LOG.error(e.getMessage());
LOG.error(e.getResponseBodyAsString());
throw e;
} finally {
}
}
}